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 #include "asterisk.h"
00066
00067 #ifdef IMAP_STORAGE
00068 #include <ctype.h>
00069 #include <signal.h>
00070 #include <pwd.h>
00071 #ifdef USE_SYSTEM_IMAP
00072 #include <imap/c-client.h>
00073 #include <imap/imap4r1.h>
00074 #include <imap/linkage.h>
00075 #elif defined (USE_SYSTEM_CCLIENT)
00076 #include <c-client/c-client.h>
00077 #include <c-client/imap4r1.h>
00078 #include <c-client/linkage.h>
00079 #else
00080 #include "c-client.h"
00081 #include "imap4r1.h"
00082 #include "linkage.h"
00083 #endif
00084 #endif
00085
00086 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426691 $")
00087
00088 #include "asterisk/paths.h"
00089 #include <sys/time.h>
00090 #include <sys/stat.h>
00091 #include <sys/mman.h>
00092 #include <time.h>
00093 #include <dirent.h>
00094 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00095 #include <sys/wait.h>
00096 #endif
00097
00098 #include "asterisk/logger.h"
00099 #include "asterisk/lock.h"
00100 #include "asterisk/file.h"
00101 #include "asterisk/channel.h"
00102 #include "asterisk/pbx.h"
00103 #include "asterisk/config.h"
00104 #include "asterisk/say.h"
00105 #include "asterisk/module.h"
00106 #include "asterisk/adsi.h"
00107 #include "asterisk/app.h"
00108 #include "asterisk/manager.h"
00109 #include "asterisk/dsp.h"
00110 #include "asterisk/localtime.h"
00111 #include "asterisk/cli.h"
00112 #include "asterisk/utils.h"
00113 #include "asterisk/stringfields.h"
00114 #include "asterisk/smdi.h"
00115 #include "asterisk/astobj2.h"
00116 #include "asterisk/event.h"
00117 #include "asterisk/taskprocessor.h"
00118 #include "asterisk/test.h"
00119
00120 #ifdef ODBC_STORAGE
00121 #include "asterisk/res_odbc.h"
00122 #endif
00123
00124 #ifdef IMAP_STORAGE
00125 #include "asterisk/threadstorage.h"
00126 #endif
00127
00128
00129
00130
00131
00132
00133
00134
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 #ifdef IMAP_STORAGE
00367 static char imapserver[48];
00368 static char imapport[8];
00369 static char imapflags[128];
00370 static char imapfolder[64];
00371 static char imapparentfolder[64] = "\0";
00372 static char greetingfolder[64];
00373 static char authuser[32];
00374 static char authpassword[42];
00375 static int imapversion = 1;
00376
00377 static int expungeonhangup = 1;
00378 static int imapgreetings = 0;
00379 static char delimiter = '\0';
00380
00381 struct vm_state;
00382 struct ast_vm_user;
00383
00384 AST_THREADSTORAGE(ts_vmstate);
00385
00386
00387 static int init_mailstream(struct vm_state *vms, int box);
00388 static void write_file(char *filename, char *buffer, unsigned long len);
00389 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00390 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00391 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00392 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00393 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00394 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00395 static void vmstate_insert(struct vm_state *vms);
00396 static void vmstate_delete(struct vm_state *vms);
00397 static void set_update(MAILSTREAM * stream);
00398 static void init_vm_state(struct vm_state *vms);
00399 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00400 static void get_mailbox_delimiter(MAILSTREAM *stream);
00401 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00402 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00403 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);
00404 static void update_messages_by_imapuser(const char *user, unsigned long number);
00405 static int vm_delete(char *file);
00406
00407 static int imap_remove_file (char *dir, int msgnum);
00408 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00409 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00410 static void check_quota(struct vm_state *vms, char *mailbox);
00411 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00412 struct vmstate {
00413 struct vm_state *vms;
00414 AST_LIST_ENTRY(vmstate) list;
00415 };
00416
00417 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00418
00419 #endif
00420
00421 #define SMDI_MWI_WAIT_TIMEOUT 1000
00422
00423 #define COMMAND_TIMEOUT 5000
00424
00425 #define VOICEMAIL_DIR_MODE 0777
00426 #define VOICEMAIL_FILE_MODE 0666
00427 #define CHUNKSIZE 65536
00428
00429 #define VOICEMAIL_CONFIG "voicemail.conf"
00430 #define ASTERISK_USERNAME "asterisk"
00431
00432
00433
00434
00435 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00436 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00437 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00438 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00439 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00440 #define VALID_DTMF "1234567890*#"
00441
00442
00443
00444 #define SENDMAIL "/usr/sbin/sendmail -t"
00445
00446 #define INTRO "vm-intro"
00447
00448 #define MAXMSG 100
00449 #define MAXMSGLIMIT 9999
00450
00451 #define MINPASSWORD 0
00452
00453 #define BASELINELEN 72
00454 #define BASEMAXINLINE 256
00455 #ifdef IMAP_STORAGE
00456 #define ENDL "\r\n"
00457 #else
00458 #define ENDL "\n"
00459 #endif
00460
00461 #define MAX_DATETIME_FORMAT 512
00462 #define MAX_NUM_CID_CONTEXTS 10
00463
00464 #define VM_REVIEW (1 << 0)
00465 #define VM_OPERATOR (1 << 1)
00466 #define VM_SAYCID (1 << 2)
00467 #define VM_SVMAIL (1 << 3)
00468 #define VM_ENVELOPE (1 << 4)
00469 #define VM_SAYDURATION (1 << 5)
00470 #define VM_SKIPAFTERCMD (1 << 6)
00471 #define VM_FORCENAME (1 << 7)
00472 #define VM_FORCEGREET (1 << 8)
00473 #define VM_PBXSKIP (1 << 9)
00474 #define VM_DIRECFORWARD (1 << 10)
00475 #define VM_ATTACH (1 << 11)
00476 #define VM_DELETE (1 << 12)
00477 #define VM_ALLOCED (1 << 13)
00478 #define VM_SEARCH (1 << 14)
00479 #define VM_TEMPGREETWARN (1 << 15)
00480 #define VM_MOVEHEARD (1 << 16)
00481 #define VM_MESSAGEWRAP (1 << 17)
00482 #define VM_FWDURGAUTO (1 << 18)
00483 #define ERROR_LOCK_PATH -100
00484 #define OPERATOR_EXIT 300
00485
00486
00487 enum vm_box {
00488 NEW_FOLDER,
00489 OLD_FOLDER,
00490 WORK_FOLDER,
00491 FAMILY_FOLDER,
00492 FRIENDS_FOLDER,
00493 GREETINGS_FOLDER
00494 };
00495
00496 enum vm_option_flags {
00497 OPT_SILENT = (1 << 0),
00498 OPT_BUSY_GREETING = (1 << 1),
00499 OPT_UNAVAIL_GREETING = (1 << 2),
00500 OPT_RECORDGAIN = (1 << 3),
00501 OPT_PREPEND_MAILBOX = (1 << 4),
00502 OPT_AUTOPLAY = (1 << 6),
00503 OPT_DTMFEXIT = (1 << 7),
00504 OPT_MESSAGE_Urgent = (1 << 8),
00505 OPT_MESSAGE_PRIORITY = (1 << 9)
00506 };
00507
00508 enum vm_option_args {
00509 OPT_ARG_RECORDGAIN = 0,
00510 OPT_ARG_PLAYFOLDER = 1,
00511 OPT_ARG_DTMFEXIT = 2,
00512
00513 OPT_ARG_ARRAY_SIZE = 3,
00514 };
00515
00516 enum vm_passwordlocation {
00517 OPT_PWLOC_VOICEMAILCONF = 0,
00518 OPT_PWLOC_SPOOLDIR = 1,
00519 OPT_PWLOC_USERSCONF = 2,
00520 };
00521
00522 AST_APP_OPTIONS(vm_app_options, {
00523 AST_APP_OPTION('s', OPT_SILENT),
00524 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00525 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00526 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00527 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00528 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00529 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00530 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00531 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00532 });
00533
00534 static int load_config(int reload);
00535 #ifdef TEST_FRAMEWORK
00536 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00537 #endif
00538 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00539
00540
00541
00542
00543
00544
00545
00546
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 struct baseio {
00624 int iocp;
00625 int iolen;
00626 int linelength;
00627 int ateof;
00628 unsigned char iobuf[BASEMAXINLINE];
00629 };
00630
00631
00632
00633 struct ast_vm_user {
00634 char context[AST_MAX_CONTEXT];
00635 char mailbox[AST_MAX_EXTENSION];
00636 char password[80];
00637 char fullname[80];
00638 char email[80];
00639 char *emailsubject;
00640 char *emailbody;
00641 char pager[80];
00642 char serveremail[80];
00643 char language[MAX_LANGUAGE];
00644 char zonetag[80];
00645 char locale[20];
00646 char callback[80];
00647 char dialout[80];
00648 char uniqueid[80];
00649 char exit[80];
00650 char attachfmt[20];
00651 unsigned int flags;
00652 int saydurationm;
00653 int minsecs;
00654 int maxmsg;
00655 int maxdeletedmsg;
00656 int maxsecs;
00657 int passwordlocation;
00658 #ifdef IMAP_STORAGE
00659 char imapuser[80];
00660 char imappassword[80];
00661 char imapfolder[64];
00662 char imapvmshareid[80];
00663 int imapversion;
00664 #endif
00665 double volgain;
00666 AST_LIST_ENTRY(ast_vm_user) list;
00667 };
00668
00669
00670 struct vm_zone {
00671 AST_LIST_ENTRY(vm_zone) list;
00672 char name[80];
00673 char timezone[80];
00674 char msg_format[512];
00675 };
00676
00677 #define VMSTATE_MAX_MSG_ARRAY 256
00678
00679
00680 struct vm_state {
00681 char curbox[80];
00682 char username[80];
00683 char context[80];
00684 char curdir[PATH_MAX];
00685 char vmbox[PATH_MAX];
00686 char fn[PATH_MAX];
00687 char intro[PATH_MAX];
00688 int *deleted;
00689 int *heard;
00690 int dh_arraysize;
00691 int curmsg;
00692 int lastmsg;
00693 int newmessages;
00694 int oldmessages;
00695 int urgentmessages;
00696 int starting;
00697 int repeats;
00698 #ifdef IMAP_STORAGE
00699 ast_mutex_t lock;
00700 int updated;
00701 long *msgArray;
00702 unsigned msg_array_max;
00703 MAILSTREAM *mailstream;
00704 int vmArrayIndex;
00705 char imapuser[80];
00706 char imapfolder[64];
00707 int imapversion;
00708 int interactive;
00709 char introfn[PATH_MAX];
00710 unsigned int quota_limit;
00711 unsigned int quota_usage;
00712 struct vm_state *persist_vms;
00713 #endif
00714 };
00715
00716 #ifdef ODBC_STORAGE
00717 static char odbc_database[80];
00718 static char odbc_table[80];
00719 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00720 #define DISPOSE(a,b) remove_file(a,b)
00721 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00722 #define EXISTS(a,b,c,d) (message_exists(a,b))
00723 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00724 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00725 #define DELETE(a,b,c,d) (delete_file(a,b))
00726 #else
00727 #ifdef IMAP_STORAGE
00728 #define DISPOSE(a,b) (imap_remove_file(a,b))
00729 #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))
00730 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00731 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00732 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00733 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00734 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00735 #else
00736 #define RETRIEVE(a,b,c,d)
00737 #define DISPOSE(a,b)
00738 #define STORE(a,b,c,d,e,f,g,h,i,j)
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_plain_file(g,h));
00742 #define DELETE(a,b,c,d) (vm_delete(c))
00743 #endif
00744 #endif
00745
00746 static char VM_SPOOL_DIR[PATH_MAX];
00747
00748 static char ext_pass_cmd[128];
00749 static char ext_pass_check_cmd[128];
00750
00751 static int my_umask;
00752
00753 #define PWDCHANGE_INTERNAL (1 << 1)
00754 #define PWDCHANGE_EXTERNAL (1 << 2)
00755 static int pwdchange = PWDCHANGE_INTERNAL;
00756
00757 #ifdef ODBC_STORAGE
00758 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00759 #else
00760 # ifdef IMAP_STORAGE
00761 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00762 # else
00763 # define tdesc "Comedian Mail (Voicemail System)"
00764 # endif
00765 #endif
00766
00767 static char userscontext[AST_MAX_EXTENSION] = "default";
00768
00769 static char *addesc = "Comedian Mail";
00770
00771
00772 static char *app = "VoiceMail";
00773
00774
00775 static char *app2 = "VoiceMailMain";
00776
00777 static char *app3 = "MailboxExists";
00778 static char *app4 = "VMAuthenticate";
00779
00780 static char *sayname_app = "VMSayName";
00781
00782 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00783 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00784 static char zonetag[80];
00785 static char locale[20];
00786 static int maxsilence;
00787 static int maxmsg;
00788 static int maxdeletedmsg;
00789 static int silencethreshold = 128;
00790 static char serveremail[80];
00791 static char mailcmd[160];
00792 static char externnotify[160];
00793 static struct ast_smdi_interface *smdi_iface = NULL;
00794 static char vmfmts[80];
00795 static double volgain;
00796 static int vmminsecs;
00797 static int vmmaxsecs;
00798 static int maxgreet;
00799 static int skipms;
00800 static int maxlogins;
00801 static int minpassword;
00802 static int passwordlocation;
00803
00804
00805
00806 static unsigned int poll_mailboxes;
00807
00808
00809 static unsigned int poll_freq;
00810
00811 #define DEFAULT_POLL_FREQ 30
00812
00813 AST_MUTEX_DEFINE_STATIC(poll_lock);
00814 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00815 static pthread_t poll_thread = AST_PTHREADT_NULL;
00816 static unsigned char poll_thread_run;
00817
00818
00819 static struct ast_event_sub *mwi_sub_sub;
00820
00821 static struct ast_event_sub *mwi_unsub_sub;
00822
00823
00824
00825
00826
00827
00828
00829
00830 struct mwi_sub {
00831 AST_RWLIST_ENTRY(mwi_sub) entry;
00832 int old_urgent;
00833 int old_new;
00834 int old_old;
00835 uint32_t uniqueid;
00836 char mailbox[1];
00837 };
00838
00839 struct mwi_sub_task {
00840 const char *mailbox;
00841 const char *context;
00842 uint32_t uniqueid;
00843 };
00844
00845 static struct ast_taskprocessor *mwi_subscription_tps;
00846
00847 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00848
00849
00850 static char listen_control_forward_key[12];
00851 static char listen_control_reverse_key[12];
00852 static char listen_control_pause_key[12];
00853 static char listen_control_restart_key[12];
00854 static char listen_control_stop_key[12];
00855
00856
00857 static char vm_password[80] = "vm-password";
00858 static char vm_newpassword[80] = "vm-newpassword";
00859 static char vm_passchanged[80] = "vm-passchanged";
00860 static char vm_reenterpassword[80] = "vm-reenterpassword";
00861 static char vm_mismatch[80] = "vm-mismatch";
00862 static char vm_invalid_password[80] = "vm-invalid-password";
00863 static char vm_pls_try_again[80] = "vm-pls-try-again";
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875 static char vm_prepend_timeout[80] = "vm-then-pound";
00876
00877 static struct ast_flags globalflags = {0};
00878
00879 static int saydurationminfo;
00880
00881 static char dialcontext[AST_MAX_CONTEXT] = "";
00882 static char callcontext[AST_MAX_CONTEXT] = "";
00883 static char exitcontext[AST_MAX_CONTEXT] = "";
00884
00885 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00886
00887
00888 static char *emailbody = NULL;
00889 static char *emailsubject = NULL;
00890 static char *pagerbody = NULL;
00891 static char *pagersubject = NULL;
00892 static char fromstring[100];
00893 static char pagerfromstring[100];
00894 static char charset[32] = "ISO-8859-1";
00895
00896 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00897 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00898 static int adsiver = 1;
00899 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00900 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00901
00902
00903 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00904 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);
00905 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00906 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00907 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00908 signed char record_gain, struct vm_state *vms, char *flag);
00909 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00910 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00911 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);
00912 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);
00913 static void apply_options(struct ast_vm_user *vmu, const char *options);
00914 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);
00915 static int is_valid_dtmf(const char *key);
00916 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00917 static int write_password_to_file(const char *secretfn, const char *password);
00918 static const char *substitute_escapes(const char *value);
00919 static void free_user(struct ast_vm_user *vmu);
00920
00921 struct ao2_container *inprocess_container;
00922
00923 struct inprocess {
00924 int count;
00925 char *context;
00926 char mailbox[0];
00927 };
00928
00929 static int inprocess_hash_fn(const void *obj, const int flags)
00930 {
00931 const struct inprocess *i = obj;
00932 return atoi(i->mailbox);
00933 }
00934
00935 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00936 {
00937 struct inprocess *i = obj, *j = arg;
00938 if (strcmp(i->mailbox, j->mailbox)) {
00939 return 0;
00940 }
00941 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00942 }
00943
00944 static int inprocess_count(const char *context, const char *mailbox, int delta)
00945 {
00946 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00947 arg->context = arg->mailbox + strlen(mailbox) + 1;
00948 strcpy(arg->mailbox, mailbox);
00949 strcpy(arg->context, context);
00950 ao2_lock(inprocess_container);
00951 if ((i = ao2_find(inprocess_container, arg, 0))) {
00952 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00953 ao2_unlock(inprocess_container);
00954 ao2_ref(i, -1);
00955 return ret;
00956 }
00957 if (delta < 0) {
00958 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00959 }
00960 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00961 ao2_unlock(inprocess_container);
00962 return 0;
00963 }
00964 i->context = i->mailbox + strlen(mailbox) + 1;
00965 strcpy(i->mailbox, mailbox);
00966 strcpy(i->context, context);
00967 i->count = delta;
00968 ao2_link(inprocess_container, i);
00969 ao2_unlock(inprocess_container);
00970 ao2_ref(i, -1);
00971 return 0;
00972 }
00973
00974 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00975 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00976 #endif
00977
00978
00979
00980
00981
00982
00983
00984 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00985 {
00986 char *bufptr = buf;
00987 for (; *input; input++) {
00988 if (*input < 32) {
00989 continue;
00990 }
00991 *bufptr++ = *input;
00992 if (bufptr == buf + buflen - 1) {
00993 break;
00994 }
00995 }
00996 *bufptr = '\0';
00997 return buf;
00998 }
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 static void populate_defaults(struct ast_vm_user *vmu)
01015 {
01016 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01017 vmu->passwordlocation = passwordlocation;
01018 if (saydurationminfo) {
01019 vmu->saydurationm = saydurationminfo;
01020 }
01021 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01022 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01023 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01024 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01025 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01026 if (vmminsecs) {
01027 vmu->minsecs = vmminsecs;
01028 }
01029 if (vmmaxsecs) {
01030 vmu->maxsecs = vmmaxsecs;
01031 }
01032 if (maxmsg) {
01033 vmu->maxmsg = maxmsg;
01034 }
01035 if (maxdeletedmsg) {
01036 vmu->maxdeletedmsg = maxdeletedmsg;
01037 }
01038 vmu->volgain = volgain;
01039 ast_free(vmu->emailsubject);
01040 vmu->emailsubject = NULL;
01041 ast_free(vmu->emailbody);
01042 vmu->emailbody = NULL;
01043 #ifdef IMAP_STORAGE
01044 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01045 #endif
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01057 {
01058 int x;
01059 if (!strcasecmp(var, "attach")) {
01060 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01061 } else if (!strcasecmp(var, "attachfmt")) {
01062 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01063 } else if (!strcasecmp(var, "serveremail")) {
01064 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01065 } else if (!strcasecmp(var, "emailbody")) {
01066 vmu->emailbody = ast_strdup(substitute_escapes(value));
01067 } else if (!strcasecmp(var, "emailsubject")) {
01068 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01069 } else if (!strcasecmp(var, "language")) {
01070 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01071 } else if (!strcasecmp(var, "tz")) {
01072 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01073 } else if (!strcasecmp(var, "locale")) {
01074 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01075 #ifdef IMAP_STORAGE
01076 } else if (!strcasecmp(var, "imapuser")) {
01077 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01078 vmu->imapversion = imapversion;
01079 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01080 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01081 vmu->imapversion = imapversion;
01082 } else if (!strcasecmp(var, "imapfolder")) {
01083 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01084 } else if (!strcasecmp(var, "imapvmshareid")) {
01085 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01086 vmu->imapversion = imapversion;
01087 #endif
01088 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01089 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01090 } else if (!strcasecmp(var, "saycid")){
01091 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01092 } else if (!strcasecmp(var, "sendvoicemail")){
01093 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01094 } else if (!strcasecmp(var, "review")){
01095 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01096 } else if (!strcasecmp(var, "tempgreetwarn")){
01097 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01098 } else if (!strcasecmp(var, "messagewrap")){
01099 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01100 } else if (!strcasecmp(var, "operator")) {
01101 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01102 } else if (!strcasecmp(var, "envelope")){
01103 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01104 } else if (!strcasecmp(var, "moveheard")){
01105 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01106 } else if (!strcasecmp(var, "sayduration")){
01107 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01108 } else if (!strcasecmp(var, "saydurationm")){
01109 if (sscanf(value, "%30d", &x) == 1) {
01110 vmu->saydurationm = x;
01111 } else {
01112 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01113 }
01114 } else if (!strcasecmp(var, "forcename")){
01115 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01116 } else if (!strcasecmp(var, "forcegreetings")){
01117 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01118 } else if (!strcasecmp(var, "callback")) {
01119 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01120 } else if (!strcasecmp(var, "dialout")) {
01121 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01122 } else if (!strcasecmp(var, "exitcontext")) {
01123 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01124 } else if (!strcasecmp(var, "minsecs")) {
01125 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01126 vmu->minsecs = x;
01127 } else {
01128 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01129 vmu->minsecs = vmminsecs;
01130 }
01131 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01132 vmu->maxsecs = atoi(value);
01133 if (vmu->maxsecs <= 0) {
01134 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01135 vmu->maxsecs = vmmaxsecs;
01136 } else {
01137 vmu->maxsecs = atoi(value);
01138 }
01139 if (!strcasecmp(var, "maxmessage"))
01140 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01141 } else if (!strcasecmp(var, "maxmsg")) {
01142 vmu->maxmsg = atoi(value);
01143
01144 if (vmu->maxmsg < 0) {
01145 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01146 vmu->maxmsg = MAXMSG;
01147 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01148 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01149 vmu->maxmsg = MAXMSGLIMIT;
01150 }
01151 } else if (!strcasecmp(var, "nextaftercmd")) {
01152 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01153 } else if (!strcasecmp(var, "backupdeleted")) {
01154 if (sscanf(value, "%30d", &x) == 1)
01155 vmu->maxdeletedmsg = x;
01156 else if (ast_true(value))
01157 vmu->maxdeletedmsg = MAXMSG;
01158 else
01159 vmu->maxdeletedmsg = 0;
01160
01161 if (vmu->maxdeletedmsg < 0) {
01162 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01163 vmu->maxdeletedmsg = MAXMSG;
01164 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01165 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01166 vmu->maxdeletedmsg = MAXMSGLIMIT;
01167 }
01168 } else if (!strcasecmp(var, "volgain")) {
01169 sscanf(value, "%30lf", &vmu->volgain);
01170 } else if (!strcasecmp(var, "passwordlocation")) {
01171 if (!strcasecmp(value, "spooldir")) {
01172 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01173 } else {
01174 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01175 }
01176 } else if (!strcasecmp(var, "options")) {
01177 apply_options(vmu, value);
01178 }
01179 }
01180
01181 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01182 {
01183 int fds[2], pid = 0;
01184
01185 memset(buf, 0, len);
01186
01187 if (pipe(fds)) {
01188 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01189 } else {
01190
01191 pid = ast_safe_fork(0);
01192
01193 if (pid < 0) {
01194
01195 close(fds[0]);
01196 close(fds[1]);
01197 snprintf(buf, len, "FAILURE: Fork failed");
01198 } else if (pid) {
01199
01200 close(fds[1]);
01201 if (read(fds[0], buf, len) < 0) {
01202 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01203 }
01204 close(fds[0]);
01205 } else {
01206
01207 AST_DECLARE_APP_ARGS(arg,
01208 AST_APP_ARG(v)[20];
01209 );
01210 char *mycmd = ast_strdupa(command);
01211
01212 close(fds[0]);
01213 dup2(fds[1], STDOUT_FILENO);
01214 close(fds[1]);
01215 ast_close_fds_above_n(STDOUT_FILENO);
01216
01217 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01218
01219 execv(arg.v[0], arg.v);
01220 printf("FAILURE: %s", strerror(errno));
01221 _exit(0);
01222 }
01223 }
01224 return buf;
01225 }
01226
01227
01228
01229
01230
01231
01232
01233
01234 static int check_password(struct ast_vm_user *vmu, char *password)
01235 {
01236
01237 if (strlen(password) < minpassword)
01238 return 1;
01239
01240 if (!ast_strlen_zero(password) && password[0] == '*')
01241 return 1;
01242 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01243 char cmd[255], buf[255];
01244
01245 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01246
01247 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01248 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01249 ast_debug(5, "Result: %s\n", buf);
01250 if (!strncasecmp(buf, "VALID", 5)) {
01251 ast_debug(3, "Passed password check: '%s'\n", buf);
01252 return 0;
01253 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01254 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01255 return 0;
01256 } else {
01257 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01258 return 1;
01259 }
01260 }
01261 }
01262 return 0;
01263 }
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01276 {
01277 int res = -1;
01278 if (!strcmp(vmu->password, password)) {
01279
01280 return 0;
01281 }
01282
01283 if (strlen(password) > 10) {
01284 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01285 }
01286 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01287 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01288 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01289 res = 0;
01290 }
01291 return res;
01292 }
01293
01294
01295
01296
01297 static void apply_options(struct ast_vm_user *vmu, const char *options)
01298 {
01299 char *stringp;
01300 char *s;
01301 char *var, *value;
01302 stringp = ast_strdupa(options);
01303 while ((s = strsep(&stringp, "|"))) {
01304 value = s;
01305 if ((var = strsep(&value, "=")) && value) {
01306 apply_option(vmu, var, value);
01307 }
01308 }
01309 }
01310
01311
01312
01313
01314
01315
01316 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01317 {
01318 for (; var; var = var->next) {
01319 if (!strcasecmp(var->name, "vmsecret")) {
01320 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01321 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01322 if (ast_strlen_zero(retval->password)) {
01323 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01324 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01325 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01326 } else {
01327 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01328 }
01329 }
01330 } else if (!strcasecmp(var->name, "uniqueid")) {
01331 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01332 } else if (!strcasecmp(var->name, "pager")) {
01333 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01334 } else if (!strcasecmp(var->name, "email")) {
01335 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01336 } else if (!strcasecmp(var->name, "fullname")) {
01337 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01338 } else if (!strcasecmp(var->name, "context")) {
01339 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01340 } else if (!strcasecmp(var->name, "emailsubject")) {
01341 ast_free(retval->emailsubject);
01342 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01343 } else if (!strcasecmp(var->name, "emailbody")) {
01344 ast_free(retval->emailbody);
01345 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01346 #ifdef IMAP_STORAGE
01347 } else if (!strcasecmp(var->name, "imapuser")) {
01348 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01349 retval->imapversion = imapversion;
01350 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01351 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01352 retval->imapversion = imapversion;
01353 } else if (!strcasecmp(var->name, "imapfolder")) {
01354 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01355 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01356 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01357 retval->imapversion = imapversion;
01358 #endif
01359 } else
01360 apply_option(retval, var->name, var->value);
01361 }
01362 }
01363
01364
01365
01366
01367
01368
01369
01370
01371 static int is_valid_dtmf(const char *key)
01372 {
01373 int i;
01374 char *local_key = ast_strdupa(key);
01375
01376 for (i = 0; i < strlen(key); ++i) {
01377 if (!strchr(VALID_DTMF, *local_key)) {
01378 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01379 return 0;
01380 }
01381 local_key++;
01382 }
01383 return 1;
01384 }
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01397 {
01398 struct ast_variable *var;
01399 struct ast_vm_user *retval;
01400
01401 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01402 if (ivm) {
01403 memset(retval, 0, sizeof(*retval));
01404 }
01405 populate_defaults(retval);
01406 if (!ivm) {
01407 ast_set_flag(retval, VM_ALLOCED);
01408 }
01409 if (mailbox) {
01410 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01411 }
01412 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01413 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01414 } else {
01415 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01416 }
01417 if (var) {
01418 apply_options_full(retval, var);
01419 ast_variables_destroy(var);
01420 } else {
01421 if (!ivm)
01422 free_user(retval);
01423 retval = NULL;
01424 }
01425 }
01426 return retval;
01427 }
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01438 {
01439
01440 struct ast_vm_user *vmu = NULL, *cur;
01441 AST_LIST_LOCK(&users);
01442
01443 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01444 context = "default";
01445
01446 AST_LIST_TRAVERSE(&users, cur, list) {
01447 #ifdef IMAP_STORAGE
01448 if (cur->imapversion != imapversion) {
01449 continue;
01450 }
01451 #endif
01452 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01453 break;
01454 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01455 break;
01456 }
01457 if (cur) {
01458
01459 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01460 *vmu = *cur;
01461 if (!ivm) {
01462 vmu->emailbody = ast_strdup(cur->emailbody);
01463 vmu->emailsubject = ast_strdup(cur->emailsubject);
01464 }
01465 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01466 AST_LIST_NEXT(vmu, list) = NULL;
01467 }
01468 } else
01469 vmu = find_user_realtime(ivm, context, mailbox);
01470 AST_LIST_UNLOCK(&users);
01471 return vmu;
01472 }
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01485 {
01486
01487 struct ast_vm_user *cur;
01488 int res = -1;
01489 AST_LIST_LOCK(&users);
01490 AST_LIST_TRAVERSE(&users, cur, list) {
01491 if ((!context || !strcasecmp(context, cur->context)) &&
01492 (!strcasecmp(mailbox, cur->mailbox)))
01493 break;
01494 }
01495 if (cur) {
01496 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01497 res = 0;
01498 }
01499 AST_LIST_UNLOCK(&users);
01500 return res;
01501 }
01502
01503
01504
01505
01506 static inline int valid_config(const struct ast_config *cfg)
01507 {
01508 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01509 }
01510
01511
01512
01513
01514
01515
01516
01517
01518 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01519 {
01520 struct ast_config *cfg = NULL;
01521 struct ast_variable *var = NULL;
01522 struct ast_category *cat = NULL;
01523 char *category = NULL, *value = NULL, *new = NULL;
01524 const char *tmp = NULL;
01525 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01526 char secretfn[PATH_MAX] = "";
01527 int found = 0;
01528
01529 if (!change_password_realtime(vmu, newpassword))
01530 return;
01531
01532
01533 switch (vmu->passwordlocation) {
01534 case OPT_PWLOC_SPOOLDIR:
01535 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01536 if (write_password_to_file(secretfn, newpassword) == 0) {
01537 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01538 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01539 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01540 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01541 break;
01542 } else {
01543 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01544 }
01545
01546 case OPT_PWLOC_VOICEMAILCONF:
01547 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01548 while ((category = ast_category_browse(cfg, category))) {
01549 if (!strcasecmp(category, vmu->context)) {
01550 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01551 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01552 break;
01553 }
01554 value = strstr(tmp, ",");
01555 if (!value) {
01556 new = ast_alloca(strlen(newpassword)+1);
01557 sprintf(new, "%s", newpassword);
01558 } else {
01559 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01560 sprintf(new, "%s%s", newpassword, value);
01561 }
01562 if (!(cat = ast_category_get(cfg, category))) {
01563 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01564 break;
01565 }
01566 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01567 found = 1;
01568 }
01569 }
01570
01571 if (found) {
01572 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01573 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01574 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01575 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01576 ast_config_destroy(cfg);
01577 break;
01578 }
01579
01580 ast_config_destroy(cfg);
01581 }
01582
01583 case OPT_PWLOC_USERSCONF:
01584
01585
01586 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01587 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01588 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01589 ast_debug(4, "users.conf: %s\n", category);
01590 if (!strcasecmp(category, vmu->mailbox)) {
01591 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01592 ast_debug(3, "looks like we need to make vmsecret!\n");
01593 var = ast_variable_new("vmsecret", newpassword, "");
01594 } else {
01595 var = NULL;
01596 }
01597 new = ast_alloca(strlen(newpassword) + 1);
01598 sprintf(new, "%s", newpassword);
01599 if (!(cat = ast_category_get(cfg, category))) {
01600 ast_debug(4, "failed to get category!\n");
01601 ast_free(var);
01602 break;
01603 }
01604 if (!var) {
01605 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01606 } else {
01607 ast_variable_append(cat, var);
01608 }
01609 found = 1;
01610 break;
01611 }
01612 }
01613
01614 if (found) {
01615 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01616 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01617 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01618 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01619 }
01620
01621 ast_config_destroy(cfg);
01622 }
01623 }
01624 }
01625
01626 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01627 {
01628 char buf[255];
01629 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01630 ast_debug(1, "External password: %s\n",buf);
01631 if (!ast_safe_system(buf)) {
01632 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01633 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01634
01635 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01636 }
01637 }
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01653 {
01654 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669 static int make_file(char *dest, const int len, const char *dir, const int num)
01670 {
01671 return snprintf(dest, len, "%s/msg%04d", dir, num);
01672 }
01673
01674
01675 static FILE *vm_mkftemp(char *template)
01676 {
01677 FILE *p = NULL;
01678 int pfd = mkstemp(template);
01679 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01680 if (pfd > -1) {
01681 p = fdopen(pfd, "w+");
01682 if (!p) {
01683 close(pfd);
01684 pfd = -1;
01685 }
01686 }
01687 return p;
01688 }
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01699 {
01700 mode_t mode = VOICEMAIL_DIR_MODE;
01701 int res;
01702
01703 make_dir(dest, len, context, ext, folder);
01704 if ((res = ast_mkdir(dest, mode))) {
01705 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01706 return -1;
01707 }
01708 return 0;
01709 }
01710
01711 static const char * const mailbox_folders[] = {
01712 #ifdef IMAP_STORAGE
01713 imapfolder,
01714 #else
01715 "INBOX",
01716 #endif
01717 "Old",
01718 "Work",
01719 "Family",
01720 "Friends",
01721 "Cust1",
01722 "Cust2",
01723 "Cust3",
01724 "Cust4",
01725 "Cust5",
01726 "Deleted",
01727 "Urgent",
01728 };
01729
01730 static const char *mbox(struct ast_vm_user *vmu, int id)
01731 {
01732 #ifdef IMAP_STORAGE
01733 if (vmu && id == 0) {
01734 return vmu->imapfolder;
01735 }
01736 #endif
01737 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01738 }
01739
01740 static int get_folder_by_name(const char *name)
01741 {
01742 size_t i;
01743
01744 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01745 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01746 return i;
01747 }
01748 }
01749
01750 return -1;
01751 }
01752
01753 static void free_user(struct ast_vm_user *vmu)
01754 {
01755 if (ast_test_flag(vmu, VM_ALLOCED)) {
01756
01757 ast_free(vmu->emailbody);
01758 vmu->emailbody = NULL;
01759
01760 ast_free(vmu->emailsubject);
01761 vmu->emailsubject = NULL;
01762
01763 ast_free(vmu);
01764 }
01765 }
01766
01767 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01768
01769 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01770
01771
01772 if (vms->deleted) {
01773 ast_free(vms->deleted);
01774 vms->deleted = NULL;
01775 }
01776 if (vms->heard) {
01777 ast_free(vms->heard);
01778 vms->heard = NULL;
01779 }
01780 vms->dh_arraysize = 0;
01781
01782 if (arraysize > 0) {
01783 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01784 return -1;
01785 }
01786 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01787 ast_free(vms->deleted);
01788 vms->deleted = NULL;
01789 return -1;
01790 }
01791 vms->dh_arraysize = arraysize;
01792 }
01793
01794 return 0;
01795 }
01796
01797
01798
01799 #ifdef IMAP_STORAGE
01800 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01801 {
01802 char arg[10];
01803 struct vm_state *vms;
01804 unsigned long messageNum;
01805
01806
01807 if (msgnum < 0 && !imapgreetings) {
01808 ast_filedelete(file, NULL);
01809 return;
01810 }
01811
01812 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01813 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);
01814 return;
01815 }
01816
01817 if (msgnum < 0) {
01818 imap_delete_old_greeting(file, vms);
01819 return;
01820 }
01821
01822
01823
01824 messageNum = vms->msgArray[msgnum];
01825 if (messageNum == 0) {
01826 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01827 return;
01828 }
01829 if (option_debug > 2)
01830 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01831
01832 snprintf (arg, sizeof(arg), "%lu", messageNum);
01833 ast_mutex_lock(&vms->lock);
01834 mail_setflag (vms->mailstream, arg, "\\DELETED");
01835 mail_expunge(vms->mailstream);
01836 ast_mutex_unlock(&vms->lock);
01837 }
01838
01839 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01840 {
01841 struct vm_state *vms_p;
01842 char *file, *filename;
01843 char *attachment;
01844 int i;
01845 BODY *body;
01846
01847
01848
01849
01850 if (msgnum > -1 || !imapgreetings) {
01851 return 0;
01852 } else {
01853 file = strrchr(ast_strdupa(dir), '/');
01854 if (file)
01855 *file++ = '\0';
01856 else {
01857 ast_debug (1, "Failed to procure file name from directory passed.\n");
01858 return -1;
01859 }
01860 }
01861
01862
01863 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01864 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01865
01866
01867
01868
01869 if (!(vms_p = create_vm_state_from_user(vmu))) {
01870 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01871 return -1;
01872 }
01873 }
01874
01875
01876 *vms_p->introfn = '\0';
01877
01878 ast_mutex_lock(&vms_p->lock);
01879 init_mailstream(vms_p, GREETINGS_FOLDER);
01880 if (!vms_p->mailstream) {
01881 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01882 ast_mutex_unlock(&vms_p->lock);
01883 return -1;
01884 }
01885
01886
01887 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01888 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01889
01890 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01891 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01892 } else {
01893 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01894 ast_mutex_unlock(&vms_p->lock);
01895 return -1;
01896 }
01897 filename = strsep(&attachment, ".");
01898 if (!strcmp(filename, file)) {
01899 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01900 vms_p->msgArray[vms_p->curmsg] = i + 1;
01901 save_body(body, vms_p, "2", attachment, 0);
01902 ast_mutex_unlock(&vms_p->lock);
01903 return 0;
01904 }
01905 }
01906 ast_mutex_unlock(&vms_p->lock);
01907
01908 return -1;
01909 }
01910
01911 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01912 {
01913 BODY *body;
01914 char *header_content;
01915 char *attachedfilefmt;
01916 char buf[80];
01917 struct vm_state *vms;
01918 char text_file[PATH_MAX];
01919 FILE *text_file_ptr;
01920 int res = 0;
01921 struct ast_vm_user *vmu;
01922
01923 if (!(vmu = find_user(NULL, context, mailbox))) {
01924 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01925 return -1;
01926 }
01927
01928 if (msgnum < 0) {
01929 if (imapgreetings) {
01930 res = imap_retrieve_greeting(dir, msgnum, vmu);
01931 goto exit;
01932 } else {
01933 res = 0;
01934 goto exit;
01935 }
01936 }
01937
01938
01939
01940
01941 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01942
01943
01944
01945
01946
01947
01948
01949 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01950 res = -1;
01951 goto exit;
01952 }
01953
01954 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01955 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01956
01957
01958 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01959 res = 0;
01960 goto exit;
01961 }
01962
01963 if (option_debug > 2)
01964 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01965 if (vms->msgArray[msgnum] == 0) {
01966 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01967 res = -1;
01968 goto exit;
01969 }
01970
01971
01972 ast_mutex_lock(&vms->lock);
01973 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01974 ast_mutex_unlock(&vms->lock);
01975
01976 if (ast_strlen_zero(header_content)) {
01977 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01978 res = -1;
01979 goto exit;
01980 }
01981
01982 ast_mutex_lock(&vms->lock);
01983 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01984 ast_mutex_unlock(&vms->lock);
01985
01986
01987 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01988 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01989 } else {
01990 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01991 res = -1;
01992 goto exit;
01993 }
01994
01995
01996
01997 strsep(&attachedfilefmt, ".");
01998 if (!attachedfilefmt) {
01999 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02000 res = -1;
02001 goto exit;
02002 }
02003
02004 save_body(body, vms, "2", attachedfilefmt, 0);
02005 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02006 *vms->introfn = '\0';
02007 }
02008
02009
02010 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02011
02012 if (!(text_file_ptr = fopen(text_file, "w"))) {
02013 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02014 }
02015
02016 fprintf(text_file_ptr, "%s\n", "[message]");
02017
02018 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02019 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02020 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02021 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02022 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02023 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02024 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02025 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02026 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02027 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02028 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02029 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02030 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02031 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02032 fclose(text_file_ptr);
02033
02034 exit:
02035 free_user(vmu);
02036 return res;
02037 }
02038
02039 static int folder_int(const char *folder)
02040 {
02041
02042 if (!folder) {
02043 return 0;
02044 }
02045 if (!strcasecmp(folder, imapfolder)) {
02046 return 0;
02047 } else if (!strcasecmp(folder, "Old")) {
02048 return 1;
02049 } else if (!strcasecmp(folder, "Work")) {
02050 return 2;
02051 } else if (!strcasecmp(folder, "Family")) {
02052 return 3;
02053 } else if (!strcasecmp(folder, "Friends")) {
02054 return 4;
02055 } else if (!strcasecmp(folder, "Cust1")) {
02056 return 5;
02057 } else if (!strcasecmp(folder, "Cust2")) {
02058 return 6;
02059 } else if (!strcasecmp(folder, "Cust3")) {
02060 return 7;
02061 } else if (!strcasecmp(folder, "Cust4")) {
02062 return 8;
02063 } else if (!strcasecmp(folder, "Cust5")) {
02064 return 9;
02065 } else if (!strcasecmp(folder, "Urgent")) {
02066 return 11;
02067 } else {
02068 return 0;
02069 }
02070 }
02071
02072 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02073 {
02074 SEARCHPGM *pgm;
02075 SEARCHHEADER *hdr;
02076
02077 struct ast_vm_user *vmu, vmus;
02078 struct vm_state *vms_p;
02079 int ret = 0;
02080 int fold = folder_int(folder);
02081 int urgent = 0;
02082
02083
02084 if (fold == 11) {
02085 fold = NEW_FOLDER;
02086 urgent = 1;
02087 }
02088
02089 if (ast_strlen_zero(mailbox))
02090 return 0;
02091
02092
02093 vmu = find_user(&vmus, context, mailbox);
02094 if (!vmu) {
02095 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02096 return -1;
02097 } else {
02098
02099 if (vmu->imapuser[0] == '\0') {
02100 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02101 return -1;
02102 }
02103 }
02104
02105
02106 if (vmu->imapuser[0] == '\0') {
02107 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02108 free_user(vmu);
02109 return -1;
02110 }
02111 ast_assert(msgnum < vms->msg_array_max);
02112
02113
02114 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02115 if (!vms_p) {
02116 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02117 }
02118 if (vms_p) {
02119 ast_debug(3, "Returning before search - user is logged in\n");
02120 if (fold == 0) {
02121 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02122 }
02123 if (fold == 1) {
02124 return vms_p->oldmessages;
02125 }
02126 }
02127
02128
02129 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02130 if (!vms_p) {
02131 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02132 }
02133
02134 if (!vms_p) {
02135 vms_p = create_vm_state_from_user(vmu);
02136 }
02137 ret = init_mailstream(vms_p, fold);
02138 if (!vms_p->mailstream) {
02139 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02140 return -1;
02141 }
02142 if (ret == 0) {
02143 ast_mutex_lock(&vms_p->lock);
02144 pgm = mail_newsearchpgm ();
02145 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02146 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02147 pgm->header = hdr;
02148 if (fold != OLD_FOLDER) {
02149 pgm->unseen = 1;
02150 pgm->seen = 0;
02151 }
02152
02153
02154
02155 else {
02156 pgm->unseen = 0;
02157 pgm->seen = 1;
02158 }
02159
02160 if (fold == NEW_FOLDER) {
02161 if (urgent) {
02162 pgm->flagged = 1;
02163 pgm->unflagged = 0;
02164 } else {
02165 pgm->flagged = 0;
02166 pgm->unflagged = 1;
02167 }
02168 }
02169 pgm->undeleted = 1;
02170 pgm->deleted = 0;
02171
02172 vms_p->vmArrayIndex = 0;
02173 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02174 if (fold == 0 && urgent == 0)
02175 vms_p->newmessages = vms_p->vmArrayIndex;
02176 if (fold == 1)
02177 vms_p->oldmessages = vms_p->vmArrayIndex;
02178 if (fold == 0 && urgent == 1)
02179 vms_p->urgentmessages = vms_p->vmArrayIndex;
02180
02181 mail_free_searchpgm(&pgm);
02182 ast_mutex_unlock(&vms_p->lock);
02183 vms_p->updated = 0;
02184 return vms_p->vmArrayIndex;
02185 } else {
02186 ast_mutex_lock(&vms_p->lock);
02187 mail_ping(vms_p->mailstream);
02188 ast_mutex_unlock(&vms_p->lock);
02189 }
02190 return 0;
02191 }
02192
02193 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02194 {
02195
02196 check_quota(vms, vmu->imapfolder);
02197 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02198 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02199 ast_play_and_wait(chan, "vm-mailboxfull");
02200 return -1;
02201 }
02202
02203
02204 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));
02205 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02206 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02207 ast_play_and_wait(chan, "vm-mailboxfull");
02208 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02209 return -1;
02210 }
02211
02212 return 0;
02213 }
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224 static int messagecount(const char *context, const char *mailbox, const char *folder)
02225 {
02226 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02227 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02228 } else {
02229 return __messagecount(context, mailbox, folder);
02230 }
02231 }
02232
02233 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)
02234 {
02235 char *myserveremail = serveremail;
02236 char fn[PATH_MAX];
02237 char introfn[PATH_MAX];
02238 char mailbox[256];
02239 char *stringp;
02240 FILE *p = NULL;
02241 char tmp[80] = "/tmp/astmail-XXXXXX";
02242 long len;
02243 void *buf;
02244 int tempcopy = 0;
02245 STRING str;
02246 int ret;
02247 char *imap_flags = NIL;
02248 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02249 int box = NEW_FOLDER;
02250
02251
02252 if (msgnum < 0) {
02253 if(!imapgreetings) {
02254 return 0;
02255 } else {
02256 box = GREETINGS_FOLDER;
02257 }
02258 }
02259
02260 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02261 return -1;
02262 }
02263
02264
02265 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02266 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02267 imap_flags = "\\FLAGGED";
02268 }
02269
02270
02271 fmt = ast_strdupa(fmt);
02272 stringp = fmt;
02273 strsep(&stringp, "|");
02274
02275 if (!ast_strlen_zero(vmu->serveremail))
02276 myserveremail = vmu->serveremail;
02277
02278 if (msgnum > -1)
02279 make_file(fn, sizeof(fn), dir, msgnum);
02280 else
02281 ast_copy_string (fn, dir, sizeof(fn));
02282
02283 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02284 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02285 *introfn = '\0';
02286 }
02287
02288 if (ast_strlen_zero(vmu->email)) {
02289
02290
02291
02292
02293
02294 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02295 tempcopy = 1;
02296 }
02297
02298 if (!strcmp(fmt, "wav49"))
02299 fmt = "WAV";
02300 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02301
02302
02303
02304 if (!(p = vm_mkftemp(tmp))) {
02305 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02306 if (tempcopy)
02307 *(vmu->email) = '\0';
02308 return -1;
02309 }
02310
02311 if (msgnum < 0 && imapgreetings) {
02312 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02313 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02314 return -1;
02315 }
02316 imap_delete_old_greeting(fn, vms);
02317 }
02318
02319 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02320 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02321 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02322 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02323
02324 len = ftell(p);
02325 rewind(p);
02326 if (!(buf = ast_malloc(len + 1))) {
02327 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02328 fclose(p);
02329 if (tempcopy)
02330 *(vmu->email) = '\0';
02331 return -1;
02332 }
02333 if (fread(buf, len, 1, p) < len) {
02334 if (ferror(p)) {
02335 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02336 return -1;
02337 }
02338 }
02339 ((char *) buf)[len] = '\0';
02340 INIT(&str, mail_string, buf, len);
02341 ret = init_mailstream(vms, box);
02342 if (ret == 0) {
02343 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02344 ast_mutex_lock(&vms->lock);
02345 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02346 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02347 ast_mutex_unlock(&vms->lock);
02348 fclose(p);
02349 unlink(tmp);
02350 ast_free(buf);
02351 } else {
02352 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02353 fclose(p);
02354 unlink(tmp);
02355 ast_free(buf);
02356 return -1;
02357 }
02358 ast_debug(3, "%s stored\n", fn);
02359
02360 if (tempcopy)
02361 *(vmu->email) = '\0';
02362 inprocess_count(vmu->mailbox, vmu->context, -1);
02363 return 0;
02364
02365 }
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02381 {
02382 char tmp[PATH_MAX] = "";
02383 char *mailboxnc;
02384 char *context;
02385 char *mb;
02386 char *cur;
02387 if (newmsgs)
02388 *newmsgs = 0;
02389 if (oldmsgs)
02390 *oldmsgs = 0;
02391 if (urgentmsgs)
02392 *urgentmsgs = 0;
02393
02394 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02395
02396 if (ast_strlen_zero(mailbox_context))
02397 return 0;
02398
02399 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02400 context = strchr(tmp, '@');
02401 if (strchr(mailbox_context, ',')) {
02402 int tmpnew, tmpold, tmpurgent;
02403 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02404 mb = tmp;
02405 while ((cur = strsep(&mb, ", "))) {
02406 if (!ast_strlen_zero(cur)) {
02407 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02408 return -1;
02409 else {
02410 if (newmsgs)
02411 *newmsgs += tmpnew;
02412 if (oldmsgs)
02413 *oldmsgs += tmpold;
02414 if (urgentmsgs)
02415 *urgentmsgs += tmpurgent;
02416 }
02417 }
02418 }
02419 return 0;
02420 }
02421 if (context) {
02422 *context = '\0';
02423 mailboxnc = tmp;
02424 context++;
02425 } else {
02426 context = "default";
02427 mailboxnc = (char *) mailbox_context;
02428 }
02429
02430 if (newmsgs) {
02431 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02432 if (!vmu) {
02433 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02434 return -1;
02435 }
02436 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02437 free_user(vmu);
02438 return -1;
02439 }
02440 free_user(vmu);
02441 }
02442 if (oldmsgs) {
02443 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02444 return -1;
02445 }
02446 }
02447 if (urgentmsgs) {
02448 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02449 return -1;
02450 }
02451 }
02452 return 0;
02453 }
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465 static int has_voicemail(const char *mailbox, const char *folder)
02466 {
02467 char tmp[256], *tmp2, *box, *context;
02468 ast_copy_string(tmp, mailbox, sizeof(tmp));
02469 tmp2 = tmp;
02470 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02471 while ((box = strsep(&tmp2, ",&"))) {
02472 if (!ast_strlen_zero(box)) {
02473 if (has_voicemail(box, folder)) {
02474 return 1;
02475 }
02476 }
02477 }
02478 }
02479 if ((context = strchr(tmp, '@'))) {
02480 *context++ = '\0';
02481 } else {
02482 context = "default";
02483 }
02484 return __messagecount(context, tmp, folder) ? 1 : 0;
02485 }
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502 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)
02503 {
02504 struct vm_state *sendvms = NULL, *destvms = NULL;
02505 char messagestring[10];
02506 if (msgnum >= recip->maxmsg) {
02507 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02508 return -1;
02509 }
02510 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02511 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02512 return -1;
02513 }
02514 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02515 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02516 return -1;
02517 }
02518 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02519 ast_mutex_lock(&sendvms->lock);
02520 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02521 ast_mutex_unlock(&sendvms->lock);
02522 return 0;
02523 }
02524 ast_mutex_unlock(&sendvms->lock);
02525 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02526 return -1;
02527 }
02528
02529 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02530 {
02531 char tmp[256], *t = tmp;
02532 size_t left = sizeof(tmp);
02533
02534 if (box == OLD_FOLDER) {
02535 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02536 } else {
02537 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02538 }
02539
02540 if (box == NEW_FOLDER) {
02541 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02542 } else {
02543 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02544 }
02545
02546
02547 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02548
02549
02550 if (!ast_strlen_zero(authuser))
02551 ast_build_string(&t, &left, "/authuser=%s", authuser);
02552
02553
02554 if (!ast_strlen_zero(imapflags))
02555 ast_build_string(&t, &left, "/%s", imapflags);
02556
02557
02558 #if 1
02559 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02560 #else
02561 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02562 #endif
02563 if (box == NEW_FOLDER || box == OLD_FOLDER)
02564 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02565 else if (box == GREETINGS_FOLDER)
02566 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02567 else {
02568 if (!ast_strlen_zero(imapparentfolder)) {
02569
02570 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02571 } else {
02572 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02573 }
02574 }
02575 }
02576
02577 static int init_mailstream(struct vm_state *vms, int box)
02578 {
02579 MAILSTREAM *stream = NIL;
02580 long debug;
02581 char tmp[256];
02582
02583 if (!vms) {
02584 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02585 return -1;
02586 }
02587 if (option_debug > 2)
02588 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02589 if (vms->mailstream == NIL || !vms->mailstream) {
02590 if (option_debug)
02591 ast_log(LOG_DEBUG, "mailstream not set.\n");
02592 } else {
02593 stream = vms->mailstream;
02594 }
02595
02596 debug = NIL;
02597
02598 if (delimiter == '\0') {
02599 char *cp;
02600 #ifdef USE_SYSTEM_IMAP
02601 #include <imap/linkage.c>
02602 #elif defined(USE_SYSTEM_CCLIENT)
02603 #include <c-client/linkage.c>
02604 #else
02605 #include "linkage.c"
02606 #endif
02607
02608 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02609 ast_mutex_lock(&vms->lock);
02610 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02611 ast_mutex_unlock(&vms->lock);
02612 if (stream == NIL) {
02613 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02614 return -1;
02615 }
02616 get_mailbox_delimiter(stream);
02617
02618 for (cp = vms->imapfolder; *cp; cp++)
02619 if (*cp == '/')
02620 *cp = delimiter;
02621 }
02622
02623 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02624 if (option_debug > 2)
02625 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02626 ast_mutex_lock(&vms->lock);
02627 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02628 ast_mutex_unlock(&vms->lock);
02629 if (vms->mailstream == NIL) {
02630 return -1;
02631 } else {
02632 return 0;
02633 }
02634 }
02635
02636 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02637 {
02638 SEARCHPGM *pgm;
02639 SEARCHHEADER *hdr;
02640 int ret, urgent = 0;
02641
02642
02643 if (box == 11) {
02644 box = NEW_FOLDER;
02645 urgent = 1;
02646 }
02647
02648 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02649 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02650 vms->imapversion = vmu->imapversion;
02651 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02652
02653 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02654 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02655 return -1;
02656 }
02657
02658 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02659
02660
02661 if (box == 0) {
02662 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02663 check_quota(vms, (char *) mbox(vmu, box));
02664 }
02665
02666 ast_mutex_lock(&vms->lock);
02667 pgm = mail_newsearchpgm();
02668
02669
02670 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02671 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02672 pgm->header = hdr;
02673 pgm->deleted = 0;
02674 pgm->undeleted = 1;
02675
02676
02677 if (box == NEW_FOLDER && urgent == 1) {
02678 pgm->unseen = 1;
02679 pgm->seen = 0;
02680 pgm->flagged = 1;
02681 pgm->unflagged = 0;
02682 } else if (box == NEW_FOLDER && urgent == 0) {
02683 pgm->unseen = 1;
02684 pgm->seen = 0;
02685 pgm->flagged = 0;
02686 pgm->unflagged = 1;
02687 } else if (box == OLD_FOLDER) {
02688 pgm->seen = 1;
02689 pgm->unseen = 0;
02690 }
02691
02692 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02693
02694 vms->vmArrayIndex = 0;
02695 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02696 vms->lastmsg = vms->vmArrayIndex - 1;
02697 mail_free_searchpgm(&pgm);
02698
02699
02700
02701
02702 if (box == 0 && !vms->dh_arraysize) {
02703 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02704 }
02705 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02706 ast_mutex_unlock(&vms->lock);
02707 return -1;
02708 }
02709
02710 ast_mutex_unlock(&vms->lock);
02711 return 0;
02712 }
02713
02714 static void write_file(char *filename, char *buffer, unsigned long len)
02715 {
02716 FILE *output;
02717
02718 output = fopen (filename, "w");
02719 if (fwrite(buffer, len, 1, output) != 1) {
02720 if (ferror(output)) {
02721 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02722 }
02723 }
02724 fclose (output);
02725 }
02726
02727 static void update_messages_by_imapuser(const char *user, unsigned long number)
02728 {
02729 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02730
02731 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02732 return;
02733 }
02734
02735 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02736
02737
02738 if (vms->vmArrayIndex >= vms->msg_array_max) {
02739 long *new_mem = ast_realloc(vms->msgArray, 2 * vms->msg_array_max * sizeof(long));
02740 if (!new_mem) {
02741 return;
02742 }
02743 vms->msgArray = new_mem;
02744 vms->msg_array_max *= 2;
02745 }
02746
02747 vms->msgArray[vms->vmArrayIndex++] = number;
02748 }
02749
02750 void mm_searched(MAILSTREAM *stream, unsigned long number)
02751 {
02752 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02753
02754 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02755 return;
02756
02757 update_messages_by_imapuser(user, number);
02758 }
02759
02760 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02761 {
02762 struct ast_variable *var;
02763 struct ast_vm_user *vmu;
02764
02765 vmu = ast_calloc(1, sizeof *vmu);
02766 if (!vmu)
02767 return NULL;
02768
02769 populate_defaults(vmu);
02770 ast_set_flag(vmu, VM_ALLOCED);
02771
02772 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02773 if (var) {
02774 apply_options_full(vmu, var);
02775 ast_variables_destroy(var);
02776 return vmu;
02777 } else {
02778 ast_free(vmu);
02779 return NULL;
02780 }
02781 }
02782
02783
02784
02785 void mm_exists(MAILSTREAM * stream, unsigned long number)
02786 {
02787
02788 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02789 if (number == 0) return;
02790 set_update(stream);
02791 }
02792
02793
02794 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02795 {
02796
02797 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02798 if (number == 0) return;
02799 set_update(stream);
02800 }
02801
02802
02803 void mm_flags(MAILSTREAM * stream, unsigned long number)
02804 {
02805
02806 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02807 if (number == 0) return;
02808 set_update(stream);
02809 }
02810
02811
02812 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02813 {
02814 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02815 mm_log (string, errflg);
02816 }
02817
02818
02819 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02820 {
02821 if (delimiter == '\0') {
02822 delimiter = delim;
02823 }
02824
02825 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02826 if (attributes & LATT_NOINFERIORS)
02827 ast_debug(5, "no inferiors\n");
02828 if (attributes & LATT_NOSELECT)
02829 ast_debug(5, "no select\n");
02830 if (attributes & LATT_MARKED)
02831 ast_debug(5, "marked\n");
02832 if (attributes & LATT_UNMARKED)
02833 ast_debug(5, "unmarked\n");
02834 }
02835
02836
02837 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02838 {
02839 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02840 if (attributes & LATT_NOINFERIORS)
02841 ast_debug(5, "no inferiors\n");
02842 if (attributes & LATT_NOSELECT)
02843 ast_debug(5, "no select\n");
02844 if (attributes & LATT_MARKED)
02845 ast_debug(5, "marked\n");
02846 if (attributes & LATT_UNMARKED)
02847 ast_debug(5, "unmarked\n");
02848 }
02849
02850
02851 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02852 {
02853 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02854 if (status->flags & SA_MESSAGES)
02855 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02856 if (status->flags & SA_RECENT)
02857 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02858 if (status->flags & SA_UNSEEN)
02859 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02860 if (status->flags & SA_UIDVALIDITY)
02861 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02862 if (status->flags & SA_UIDNEXT)
02863 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02864 ast_log(AST_LOG_NOTICE, "\n");
02865 }
02866
02867
02868 void mm_log(char *string, long errflg)
02869 {
02870 switch ((short) errflg) {
02871 case NIL:
02872 ast_debug(1, "IMAP Info: %s\n", string);
02873 break;
02874 case PARSE:
02875 case WARN:
02876 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02877 break;
02878 case ERROR:
02879 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02880 break;
02881 }
02882 }
02883
02884
02885 void mm_dlog(char *string)
02886 {
02887 ast_log(AST_LOG_NOTICE, "%s\n", string);
02888 }
02889
02890
02891 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02892 {
02893 struct ast_vm_user *vmu;
02894
02895 ast_debug(4, "Entering callback mm_login\n");
02896
02897 ast_copy_string(user, mb->user, MAILTMPLEN);
02898
02899
02900 if (!ast_strlen_zero(authpassword)) {
02901 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02902 } else {
02903 AST_LIST_TRAVERSE(&users, vmu, list) {
02904 if (!strcasecmp(mb->user, vmu->imapuser)) {
02905 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02906 break;
02907 }
02908 }
02909 if (!vmu) {
02910 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02911 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02912 free_user(vmu);
02913 }
02914 }
02915 }
02916 }
02917
02918
02919 void mm_critical(MAILSTREAM * stream)
02920 {
02921 }
02922
02923
02924 void mm_nocritical(MAILSTREAM * stream)
02925 {
02926 }
02927
02928
02929 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02930 {
02931 kill (getpid (), SIGSTOP);
02932 return NIL;
02933 }
02934
02935
02936 void mm_fatal(char *string)
02937 {
02938 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02939 }
02940
02941
02942 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02943 {
02944 struct vm_state *vms;
02945 char *mailbox = stream->mailbox, *user;
02946 char buf[1024] = "";
02947 unsigned long usage = 0, limit = 0;
02948
02949 while (pquota) {
02950 usage = pquota->usage;
02951 limit = pquota->limit;
02952 pquota = pquota->next;
02953 }
02954
02955 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)))) {
02956 ast_log(AST_LOG_ERROR, "No state found.\n");
02957 return;
02958 }
02959
02960 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02961
02962 vms->quota_usage = usage;
02963 vms->quota_limit = limit;
02964 }
02965
02966 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02967 {
02968 char *start, *eol_pnt;
02969 int taglen;
02970
02971 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02972 return NULL;
02973
02974 taglen = strlen(tag) + 1;
02975 if (taglen < 1)
02976 return NULL;
02977
02978 if (!(start = strstr(header, tag)))
02979 return NULL;
02980
02981
02982 memset(buf, 0, len);
02983
02984 ast_copy_string(buf, start+taglen, len);
02985 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02986 *eol_pnt = '\0';
02987 return buf;
02988 }
02989
02990 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02991 {
02992 char *start, *quote, *eol_pnt;
02993
02994 if (ast_strlen_zero(mailbox))
02995 return NULL;
02996
02997 if (!(start = strstr(mailbox, "/user=")))
02998 return NULL;
02999
03000 ast_copy_string(buf, start+6, len);
03001
03002 if (!(quote = strchr(buf, '\"'))) {
03003 if (!(eol_pnt = strchr(buf, '/')))
03004 eol_pnt = strchr(buf,'}');
03005 *eol_pnt = '\0';
03006 return buf;
03007 } else {
03008 eol_pnt = strchr(buf+1,'\"');
03009 *eol_pnt = '\0';
03010 return buf+1;
03011 }
03012 }
03013
03014 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03015 {
03016 struct vm_state *vms_p;
03017
03018 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03019 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03020 return vms_p;
03021 }
03022 if (option_debug > 4)
03023 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03024
03025 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03026 return NULL;
03027 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03028 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03029 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03030 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03031 vms_p->mailstream = NIL;
03032 vms_p->imapversion = vmu->imapversion;
03033 if (option_debug > 4)
03034 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03035 vms_p->updated = 1;
03036
03037 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03038 init_vm_state(vms_p);
03039 vmstate_insert(vms_p);
03040 return vms_p;
03041 }
03042
03043 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03044 {
03045 struct vmstate *vlist = NULL;
03046
03047 if (interactive) {
03048 struct vm_state *vms;
03049 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03050 vms = pthread_getspecific(ts_vmstate.key);
03051 return vms;
03052 }
03053
03054 AST_LIST_LOCK(&vmstates);
03055 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03056 if (!vlist->vms) {
03057 ast_debug(3, "error: vms is NULL for %s\n", user);
03058 continue;
03059 }
03060 if (vlist->vms->imapversion != imapversion) {
03061 continue;
03062 }
03063 if (!vlist->vms->imapuser) {
03064 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03065 continue;
03066 }
03067
03068 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03069 AST_LIST_UNLOCK(&vmstates);
03070 return vlist->vms;
03071 }
03072 }
03073 AST_LIST_UNLOCK(&vmstates);
03074
03075 ast_debug(3, "%s not found in vmstates\n", user);
03076
03077 return NULL;
03078 }
03079
03080 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03081 {
03082
03083 struct vmstate *vlist = NULL;
03084 const char *local_context = S_OR(context, "default");
03085
03086 if (interactive) {
03087 struct vm_state *vms;
03088 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03089 vms = pthread_getspecific(ts_vmstate.key);
03090 return vms;
03091 }
03092
03093 AST_LIST_LOCK(&vmstates);
03094 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03095 if (!vlist->vms) {
03096 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03097 continue;
03098 }
03099 if (vlist->vms->imapversion != imapversion) {
03100 continue;
03101 }
03102 if (!vlist->vms->username || !vlist->vms->context) {
03103 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03104 continue;
03105 }
03106
03107 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);
03108
03109 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03110 ast_debug(3, "Found it!\n");
03111 AST_LIST_UNLOCK(&vmstates);
03112 return vlist->vms;
03113 }
03114 }
03115 AST_LIST_UNLOCK(&vmstates);
03116
03117 ast_debug(3, "%s not found in vmstates\n", mailbox);
03118
03119 return NULL;
03120 }
03121
03122 static void vmstate_insert(struct vm_state *vms)
03123 {
03124 struct vmstate *v;
03125 struct vm_state *altvms;
03126
03127
03128
03129
03130 if (vms->interactive == 1) {
03131 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03132 if (altvms) {
03133 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03134 vms->newmessages = altvms->newmessages;
03135 vms->oldmessages = altvms->oldmessages;
03136 vms->vmArrayIndex = altvms->vmArrayIndex;
03137
03138 vms->lastmsg = altvms->lastmsg;
03139 vms->curmsg = altvms->curmsg;
03140
03141 vms->persist_vms = altvms;
03142
03143 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03144 vms->mailstream = altvms->mailstream;
03145 #else
03146 vms->mailstream = NIL;
03147 #endif
03148 }
03149 return;
03150 }
03151
03152 if (!(v = ast_calloc(1, sizeof(*v))))
03153 return;
03154
03155 v->vms = vms;
03156
03157 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03158
03159 AST_LIST_LOCK(&vmstates);
03160 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03161 AST_LIST_UNLOCK(&vmstates);
03162 }
03163
03164 static void vmstate_delete(struct vm_state *vms)
03165 {
03166 struct vmstate *vc = NULL;
03167 struct vm_state *altvms = NULL;
03168
03169
03170
03171 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03172 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03173 altvms->newmessages = vms->newmessages;
03174 altvms->oldmessages = vms->oldmessages;
03175 altvms->updated = 1;
03176 vms->mailstream = mail_close(vms->mailstream);
03177
03178
03179 return;
03180 }
03181
03182 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03183
03184 AST_LIST_LOCK(&vmstates);
03185 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03186 if (vc->vms == vms) {
03187 AST_LIST_REMOVE_CURRENT(list);
03188 break;
03189 }
03190 }
03191 AST_LIST_TRAVERSE_SAFE_END
03192 AST_LIST_UNLOCK(&vmstates);
03193
03194 if (vc) {
03195 ast_mutex_destroy(&vc->vms->lock);
03196 ast_free(vc->vms->msgArray);
03197 vc->vms->msgArray = NULL;
03198 vc->vms->msg_array_max = 0;
03199
03200 ast_free(vc);
03201 } else {
03202 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03203 }
03204 }
03205
03206 static void set_update(MAILSTREAM * stream)
03207 {
03208 struct vm_state *vms;
03209 char *mailbox = stream->mailbox, *user;
03210 char buf[1024] = "";
03211
03212 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03213 if (user && option_debug > 2)
03214 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03215 return;
03216 }
03217
03218 ast_debug(3, "User %s mailbox set for update.\n", user);
03219
03220 vms->updated = 1;
03221 }
03222
03223 static void init_vm_state(struct vm_state *vms)
03224 {
03225 vms->msg_array_max = VMSTATE_MAX_MSG_ARRAY;
03226 vms->msgArray = ast_calloc(vms->msg_array_max, sizeof(long));
03227 if (!vms->msgArray) {
03228
03229 vms->msg_array_max = 0;
03230 }
03231 vms->vmArrayIndex = 0;
03232 ast_mutex_init(&vms->lock);
03233 }
03234
03235 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03236 {
03237 char *body_content;
03238 char *body_decoded;
03239 char *fn = is_intro ? vms->introfn : vms->fn;
03240 unsigned long len;
03241 unsigned long newlen;
03242 char filename[256];
03243
03244 if (!body || body == NIL)
03245 return -1;
03246
03247 ast_mutex_lock(&vms->lock);
03248 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03249 ast_mutex_unlock(&vms->lock);
03250 if (body_content != NIL) {
03251 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03252
03253 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03254
03255 if (!newlen) {
03256 return -1;
03257 }
03258 write_file(filename, (char *) body_decoded, newlen);
03259 } else {
03260 ast_debug(5, "Body of message is NULL.\n");
03261 return -1;
03262 }
03263 return 0;
03264 }
03265
03266
03267
03268
03269
03270
03271
03272
03273 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03274 char tmp[50];
03275 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03276 mail_list(stream, tmp, "*");
03277 }
03278
03279
03280
03281
03282
03283
03284
03285
03286 static void check_quota(struct vm_state *vms, char *mailbox) {
03287 ast_mutex_lock(&vms->lock);
03288 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03289 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03290 if (vms && vms->mailstream != NULL) {
03291 imap_getquotaroot(vms->mailstream, mailbox);
03292 } else {
03293 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03294 }
03295 ast_mutex_unlock(&vms->lock);
03296 }
03297
03298 #endif
03299
03300
03301
03302
03303
03304 static int vm_lock_path(const char *path)
03305 {
03306 switch (ast_lock_path(path)) {
03307 case AST_LOCK_TIMEOUT:
03308 return -1;
03309 default:
03310 return 0;
03311 }
03312 }
03313
03314
03315 #ifdef ODBC_STORAGE
03316 struct generic_prepare_struct {
03317 char *sql;
03318 int argc;
03319 char **argv;
03320 };
03321
03322 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03323 {
03324 struct generic_prepare_struct *gps = data;
03325 int res, i;
03326 SQLHSTMT stmt;
03327
03328 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03329 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03330 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03331 return NULL;
03332 }
03333 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03334 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03335 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03336 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03337 return NULL;
03338 }
03339 for (i = 0; i < gps->argc; i++)
03340 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03341
03342 return stmt;
03343 }
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359 static int retrieve_file(char *dir, int msgnum)
03360 {
03361 int x = 0;
03362 int res;
03363 int fd = -1;
03364 size_t fdlen = 0;
03365 void *fdm = MAP_FAILED;
03366 SQLSMALLINT colcount = 0;
03367 SQLHSTMT stmt;
03368 char sql[PATH_MAX];
03369 char fmt[80]="";
03370 char *c;
03371 char coltitle[256];
03372 SQLSMALLINT collen;
03373 SQLSMALLINT datatype;
03374 SQLSMALLINT decimaldigits;
03375 SQLSMALLINT nullable;
03376 SQLULEN colsize;
03377 SQLLEN colsize2;
03378 FILE *f = NULL;
03379 char rowdata[80];
03380 char fn[PATH_MAX];
03381 char full_fn[PATH_MAX];
03382 char msgnums[80];
03383 char *argv[] = { dir, msgnums };
03384 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03385
03386 struct odbc_obj *obj;
03387 obj = ast_odbc_request_obj(odbc_database, 0);
03388 if (obj) {
03389 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03390 c = strchr(fmt, '|');
03391 if (c)
03392 *c = '\0';
03393 if (!strcasecmp(fmt, "wav49"))
03394 strcpy(fmt, "WAV");
03395 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03396 if (msgnum > -1)
03397 make_file(fn, sizeof(fn), dir, msgnum);
03398 else
03399 ast_copy_string(fn, dir, sizeof(fn));
03400
03401
03402 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03403
03404 if (!(f = fopen(full_fn, "w+"))) {
03405 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03406 goto yuck;
03407 }
03408
03409 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03410 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03411 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03412 if (!stmt) {
03413 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03414 ast_odbc_release_obj(obj);
03415 goto yuck;
03416 }
03417 res = SQLFetch(stmt);
03418 if (res == SQL_NO_DATA) {
03419 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03420 ast_odbc_release_obj(obj);
03421 goto yuck;
03422 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03423 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03424 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03425 ast_odbc_release_obj(obj);
03426 goto yuck;
03427 }
03428 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03429 if (fd < 0) {
03430 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03431 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03432 ast_odbc_release_obj(obj);
03433 goto yuck;
03434 }
03435 res = SQLNumResultCols(stmt, &colcount);
03436 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03437 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03438 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03439 ast_odbc_release_obj(obj);
03440 goto yuck;
03441 }
03442 if (f)
03443 fprintf(f, "[message]\n");
03444 for (x = 0; x < colcount; x++) {
03445 rowdata[0] = '\0';
03446 colsize = 0;
03447 collen = sizeof(coltitle);
03448 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03449 &datatype, &colsize, &decimaldigits, &nullable);
03450 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03451 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03452 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03453 ast_odbc_release_obj(obj);
03454 goto yuck;
03455 }
03456 if (!strcasecmp(coltitle, "recording")) {
03457 off_t offset;
03458 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03459 fdlen = colsize2;
03460 if (fd > -1) {
03461 char tmp[1]="";
03462 lseek(fd, fdlen - 1, SEEK_SET);
03463 if (write(fd, tmp, 1) != 1) {
03464 close(fd);
03465 fd = -1;
03466 continue;
03467 }
03468
03469 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03470 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03471 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03472 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03473 ast_odbc_release_obj(obj);
03474 goto yuck;
03475 } else {
03476 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03477 munmap(fdm, CHUNKSIZE);
03478 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03479 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03480 unlink(full_fn);
03481 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03482 ast_odbc_release_obj(obj);
03483 goto yuck;
03484 }
03485 }
03486 }
03487 if (truncate(full_fn, fdlen) < 0) {
03488 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03489 }
03490 }
03491 } else {
03492 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03493 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03494 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03495 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03496 ast_odbc_release_obj(obj);
03497 goto yuck;
03498 }
03499 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03500 fprintf(f, "%s=%s\n", coltitle, rowdata);
03501 }
03502 }
03503 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03504 ast_odbc_release_obj(obj);
03505 } else
03506 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03507 yuck:
03508 if (f)
03509 fclose(f);
03510 if (fd > -1)
03511 close(fd);
03512 return x - 1;
03513 }
03514
03515
03516
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03527 {
03528 int x = 0;
03529 int res;
03530 SQLHSTMT stmt;
03531 char sql[PATH_MAX];
03532 char rowdata[20];
03533 char *argv[] = { dir };
03534 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03535
03536 struct odbc_obj *obj;
03537 obj = ast_odbc_request_obj(odbc_database, 0);
03538 if (obj) {
03539 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03540
03541 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03542 if (!stmt) {
03543 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03544 ast_odbc_release_obj(obj);
03545 goto yuck;
03546 }
03547 res = SQLFetch(stmt);
03548 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03549 if (res == SQL_NO_DATA) {
03550 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03551 } else {
03552 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03553 }
03554
03555 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03556 ast_odbc_release_obj(obj);
03557 goto yuck;
03558 }
03559 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03560 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03561 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03562 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03563 ast_odbc_release_obj(obj);
03564 goto yuck;
03565 }
03566 if (sscanf(rowdata, "%30d", &x) != 1)
03567 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03568 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03569 ast_odbc_release_obj(obj);
03570 return x;
03571 } else
03572 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03573 yuck:
03574 return x - 1;
03575 }
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586 static int message_exists(char *dir, int msgnum)
03587 {
03588 int x = 0;
03589 int res;
03590 SQLHSTMT stmt;
03591 char sql[PATH_MAX];
03592 char rowdata[20];
03593 char msgnums[20];
03594 char *argv[] = { dir, msgnums };
03595 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03596
03597 struct odbc_obj *obj;
03598 obj = ast_odbc_request_obj(odbc_database, 0);
03599 if (obj) {
03600 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03601 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03602 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03603 if (!stmt) {
03604 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03605 ast_odbc_release_obj(obj);
03606 goto yuck;
03607 }
03608 res = SQLFetch(stmt);
03609 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03610 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03611 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03612 ast_odbc_release_obj(obj);
03613 goto yuck;
03614 }
03615 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03616 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03617 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03618 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03619 ast_odbc_release_obj(obj);
03620 goto yuck;
03621 }
03622 if (sscanf(rowdata, "%30d", &x) != 1)
03623 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03624 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03625 ast_odbc_release_obj(obj);
03626 } else
03627 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03628 yuck:
03629 return x;
03630 }
03631
03632
03633
03634
03635
03636
03637
03638
03639
03640
03641 static int count_messages(struct ast_vm_user *vmu, char *dir)
03642 {
03643 int x = 0;
03644 int res;
03645 SQLHSTMT stmt;
03646 char sql[PATH_MAX];
03647 char rowdata[20];
03648 char *argv[] = { dir };
03649 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03650
03651 struct odbc_obj *obj;
03652 obj = ast_odbc_request_obj(odbc_database, 0);
03653 if (obj) {
03654 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03655 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03656 if (!stmt) {
03657 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03658 ast_odbc_release_obj(obj);
03659 goto yuck;
03660 }
03661 res = SQLFetch(stmt);
03662 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03663 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03664 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03665 ast_odbc_release_obj(obj);
03666 goto yuck;
03667 }
03668 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03669 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03670 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03671 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03672 ast_odbc_release_obj(obj);
03673 goto yuck;
03674 }
03675 if (sscanf(rowdata, "%30d", &x) != 1)
03676 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03677 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03678 ast_odbc_release_obj(obj);
03679 return x;
03680 } else
03681 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03682 yuck:
03683 return x - 1;
03684
03685 }
03686
03687
03688
03689
03690
03691
03692
03693
03694
03695
03696
03697 static void delete_file(const char *sdir, int smsg)
03698 {
03699 SQLHSTMT stmt;
03700 char sql[PATH_MAX];
03701 char msgnums[20];
03702 char *argv[] = { NULL, msgnums };
03703 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03704 struct odbc_obj *obj;
03705
03706 argv[0] = ast_strdupa(sdir);
03707
03708 obj = ast_odbc_request_obj(odbc_database, 0);
03709 if (obj) {
03710 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03711 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03712 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03713 if (!stmt)
03714 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03715 else
03716 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03717 ast_odbc_release_obj(obj);
03718 } else
03719 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03720 return;
03721 }
03722
03723
03724
03725
03726
03727
03728
03729
03730
03731
03732
03733
03734 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03735 {
03736 SQLHSTMT stmt;
03737 char sql[512];
03738 char msgnums[20];
03739 char msgnumd[20];
03740 struct odbc_obj *obj;
03741 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03742 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03743
03744 delete_file(ddir, dmsg);
03745 obj = ast_odbc_request_obj(odbc_database, 0);
03746 if (obj) {
03747 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03748 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03749 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);
03750 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03751 if (!stmt)
03752 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03753 else
03754 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03755 ast_odbc_release_obj(obj);
03756 } else
03757 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03758 return;
03759 }
03760
03761 struct insert_data {
03762 char *sql;
03763 const char *dir;
03764 const char *msgnums;
03765 void *data;
03766 SQLLEN datalen;
03767 SQLLEN indlen;
03768 const char *context;
03769 const char *macrocontext;
03770 const char *callerid;
03771 const char *origtime;
03772 const char *duration;
03773 const char *mailboxuser;
03774 const char *mailboxcontext;
03775 const char *category;
03776 const char *flag;
03777 };
03778
03779 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03780 {
03781 struct insert_data *data = vdata;
03782 int res;
03783 SQLHSTMT stmt;
03784
03785 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03786 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03787 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03788 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03789 return NULL;
03790 }
03791
03792 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03793 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03794 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03795 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03796 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03797 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03798 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03799 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03800 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03801 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03802 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03803 if (!ast_strlen_zero(data->category)) {
03804 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03805 }
03806 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03807 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03808 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03809 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03810 return NULL;
03811 }
03812
03813 return stmt;
03814 }
03815
03816
03817
03818
03819
03820
03821
03822
03823
03824
03825
03826
03827
03828
03829 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03830 {
03831 int res = 0;
03832 int fd = -1;
03833 void *fdm = MAP_FAILED;
03834 off_t fdlen = -1;
03835 SQLHSTMT stmt;
03836 char sql[PATH_MAX];
03837 char msgnums[20];
03838 char fn[PATH_MAX];
03839 char full_fn[PATH_MAX];
03840 char fmt[80]="";
03841 char *c;
03842 struct ast_config *cfg = NULL;
03843 struct odbc_obj *obj;
03844 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03845 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03846 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03847
03848 delete_file(dir, msgnum);
03849 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03850 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03851 return -1;
03852 }
03853
03854 do {
03855 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03856 c = strchr(fmt, '|');
03857 if (c)
03858 *c = '\0';
03859 if (!strcasecmp(fmt, "wav49"))
03860 strcpy(fmt, "WAV");
03861 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03862 if (msgnum > -1)
03863 make_file(fn, sizeof(fn), dir, msgnum);
03864 else
03865 ast_copy_string(fn, dir, sizeof(fn));
03866 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03867 cfg = ast_config_load(full_fn, config_flags);
03868 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03869 fd = open(full_fn, O_RDWR);
03870 if (fd < 0) {
03871 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03872 res = -1;
03873 break;
03874 }
03875 if (valid_config(cfg)) {
03876 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03877 idata.context = "";
03878 }
03879 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03880 idata.macrocontext = "";
03881 }
03882 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03883 idata.callerid = "";
03884 }
03885 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03886 idata.origtime = "";
03887 }
03888 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03889 idata.duration = "";
03890 }
03891 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03892 idata.category = "";
03893 }
03894 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03895 idata.flag = "";
03896 }
03897 }
03898 fdlen = lseek(fd, 0, SEEK_END);
03899 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03900 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03901 res = -1;
03902 break;
03903 }
03904 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03905 if (fdm == MAP_FAILED) {
03906 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03907 res = -1;
03908 break;
03909 }
03910 idata.data = fdm;
03911 idata.datalen = idata.indlen = fdlen;
03912
03913 if (!ast_strlen_zero(idata.category))
03914 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03915 else
03916 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03917
03918 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03919 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03920 } else {
03921 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03922 res = -1;
03923 }
03924 } while (0);
03925 if (obj) {
03926 ast_odbc_release_obj(obj);
03927 }
03928 if (valid_config(cfg))
03929 ast_config_destroy(cfg);
03930 if (fdm != MAP_FAILED)
03931 munmap(fdm, fdlen);
03932 if (fd > -1)
03933 close(fd);
03934 return res;
03935 }
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03951 {
03952 SQLHSTMT stmt;
03953 char sql[PATH_MAX];
03954 char msgnums[20];
03955 char msgnumd[20];
03956 struct odbc_obj *obj;
03957 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03958 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03959
03960 delete_file(ddir, dmsg);
03961 obj = ast_odbc_request_obj(odbc_database, 0);
03962 if (obj) {
03963 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03964 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03965 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03966 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03967 if (!stmt)
03968 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03969 else
03970 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03971 ast_odbc_release_obj(obj);
03972 } else
03973 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03974 return;
03975 }
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988 static int remove_file(char *dir, int msgnum)
03989 {
03990 char fn[PATH_MAX];
03991 char full_fn[PATH_MAX];
03992 char msgnums[80];
03993
03994 if (msgnum > -1) {
03995 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03996 make_file(fn, sizeof(fn), dir, msgnum);
03997 } else
03998 ast_copy_string(fn, dir, sizeof(fn));
03999 ast_filedelete(fn, NULL);
04000 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
04001 unlink(full_fn);
04002 return 0;
04003 }
04004 #else
04005 #ifndef IMAP_STORAGE
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015 static int count_messages(struct ast_vm_user *vmu, char *dir)
04016 {
04017
04018 int vmcount = 0;
04019 DIR *vmdir = NULL;
04020 struct dirent *vment = NULL;
04021
04022 if (vm_lock_path(dir))
04023 return ERROR_LOCK_PATH;
04024
04025 if ((vmdir = opendir(dir))) {
04026 while ((vment = readdir(vmdir))) {
04027 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04028 vmcount++;
04029 }
04030 }
04031 closedir(vmdir);
04032 }
04033 ast_unlock_path(dir);
04034
04035 return vmcount;
04036 }
04037
04038
04039
04040
04041
04042
04043
04044
04045 static void rename_file(char *sfn, char *dfn)
04046 {
04047 char stxt[PATH_MAX];
04048 char dtxt[PATH_MAX];
04049 ast_filerename(sfn, dfn, NULL);
04050 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04051 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04052 if (ast_check_realtime("voicemail_data")) {
04053 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04054 }
04055 rename(stxt, dtxt);
04056 }
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04070 {
04071 int x;
04072 unsigned char map[MAXMSGLIMIT] = "";
04073 DIR *msgdir;
04074 struct dirent *msgdirent;
04075 int msgdirint;
04076 char extension[4];
04077 int stopcount = 0;
04078
04079
04080
04081
04082
04083 if (!(msgdir = opendir(dir))) {
04084 return -1;
04085 }
04086
04087 while ((msgdirent = readdir(msgdir))) {
04088 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04089 map[msgdirint] = 1;
04090 stopcount++;
04091 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04092 }
04093 }
04094 closedir(msgdir);
04095
04096 for (x = 0; x < vmu->maxmsg; x++) {
04097 if (map[x] == 1) {
04098 stopcount--;
04099 } else if (map[x] == 0 && !stopcount) {
04100 break;
04101 }
04102 }
04103
04104 return x - 1;
04105 }
04106
04107 #endif
04108 #endif
04109 #ifndef IMAP_STORAGE
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120 static int copy(char *infile, char *outfile)
04121 {
04122 int ifd;
04123 int ofd;
04124 int res;
04125 int len;
04126 char buf[4096];
04127
04128 #ifdef HARDLINK_WHEN_POSSIBLE
04129
04130 if (link(infile, outfile)) {
04131 #endif
04132 if ((ifd = open(infile, O_RDONLY)) < 0) {
04133 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04134 return -1;
04135 }
04136 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04137 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04138 close(ifd);
04139 return -1;
04140 }
04141 do {
04142 len = read(ifd, buf, sizeof(buf));
04143 if (len < 0) {
04144 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04145 close(ifd);
04146 close(ofd);
04147 unlink(outfile);
04148 } else if (len) {
04149 res = write(ofd, buf, len);
04150 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04151 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04152 close(ifd);
04153 close(ofd);
04154 unlink(outfile);
04155 }
04156 }
04157 } while (len);
04158 close(ifd);
04159 close(ofd);
04160 return 0;
04161 #ifdef HARDLINK_WHEN_POSSIBLE
04162 } else {
04163
04164 return 0;
04165 }
04166 #endif
04167 }
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178 static void copy_plain_file(char *frompath, char *topath)
04179 {
04180 char frompath2[PATH_MAX], topath2[PATH_MAX];
04181 struct ast_variable *tmp,*var = NULL;
04182 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04183 ast_filecopy(frompath, topath, NULL);
04184 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04185 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04186 if (ast_check_realtime("voicemail_data")) {
04187 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04188
04189 for (tmp = var; tmp; tmp = tmp->next) {
04190 if (!strcasecmp(tmp->name, "origmailbox")) {
04191 origmailbox = tmp->value;
04192 } else if (!strcasecmp(tmp->name, "context")) {
04193 context = tmp->value;
04194 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04195 macrocontext = tmp->value;
04196 } else if (!strcasecmp(tmp->name, "exten")) {
04197 exten = tmp->value;
04198 } else if (!strcasecmp(tmp->name, "priority")) {
04199 priority = tmp->value;
04200 } else if (!strcasecmp(tmp->name, "callerchan")) {
04201 callerchan = tmp->value;
04202 } else if (!strcasecmp(tmp->name, "callerid")) {
04203 callerid = tmp->value;
04204 } else if (!strcasecmp(tmp->name, "origdate")) {
04205 origdate = tmp->value;
04206 } else if (!strcasecmp(tmp->name, "origtime")) {
04207 origtime = tmp->value;
04208 } else if (!strcasecmp(tmp->name, "category")) {
04209 category = tmp->value;
04210 } else if (!strcasecmp(tmp->name, "duration")) {
04211 duration = tmp->value;
04212 }
04213 }
04214 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);
04215 }
04216 copy(frompath2, topath2);
04217 ast_variables_destroy(var);
04218 }
04219 #endif
04220
04221
04222
04223
04224
04225
04226
04227
04228
04229 static int vm_delete(char *file)
04230 {
04231 char *txt;
04232 int txtsize = 0;
04233
04234 txtsize = (strlen(file) + 5)*sizeof(char);
04235 txt = ast_alloca(txtsize);
04236
04237
04238
04239 if (ast_check_realtime("voicemail_data")) {
04240 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04241 }
04242 snprintf(txt, txtsize, "%s.txt", file);
04243 unlink(txt);
04244 return ast_filedelete(file, NULL);
04245 }
04246
04247
04248
04249
04250 static int inbuf(struct baseio *bio, FILE *fi)
04251 {
04252 int l;
04253
04254 if (bio->ateof)
04255 return 0;
04256
04257 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04258 if (ferror(fi))
04259 return -1;
04260
04261 bio->ateof = 1;
04262 return 0;
04263 }
04264
04265 bio->iolen = l;
04266 bio->iocp = 0;
04267
04268 return 1;
04269 }
04270
04271
04272
04273
04274 static int inchar(struct baseio *bio, FILE *fi)
04275 {
04276 if (bio->iocp>=bio->iolen) {
04277 if (!inbuf(bio, fi))
04278 return EOF;
04279 }
04280
04281 return bio->iobuf[bio->iocp++];
04282 }
04283
04284
04285
04286
04287 static int ochar(struct baseio *bio, int c, FILE *so)
04288 {
04289 if (bio->linelength >= BASELINELEN) {
04290 if (fputs(ENDL, so) == EOF) {
04291 return -1;
04292 }
04293
04294 bio->linelength = 0;
04295 }
04296
04297 if (putc(((unsigned char) c), so) == EOF) {
04298 return -1;
04299 }
04300
04301 bio->linelength++;
04302
04303 return 1;
04304 }
04305
04306
04307
04308
04309
04310
04311
04312
04313
04314
04315 static int base_encode(char *filename, FILE *so)
04316 {
04317 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04318 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04319 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04320 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04321 int i, hiteof = 0;
04322 FILE *fi;
04323 struct baseio bio;
04324
04325 memset(&bio, 0, sizeof(bio));
04326 bio.iocp = BASEMAXINLINE;
04327
04328 if (!(fi = fopen(filename, "rb"))) {
04329 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04330 return -1;
04331 }
04332
04333 while (!hiteof){
04334 unsigned char igroup[3], ogroup[4];
04335 int c, n;
04336
04337 memset(igroup, 0, sizeof(igroup));
04338
04339 for (n = 0; n < 3; n++) {
04340 if ((c = inchar(&bio, fi)) == EOF) {
04341 hiteof = 1;
04342 break;
04343 }
04344
04345 igroup[n] = (unsigned char) c;
04346 }
04347
04348 if (n > 0) {
04349 ogroup[0]= dtable[igroup[0] >> 2];
04350 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04351 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04352 ogroup[3]= dtable[igroup[2] & 0x3F];
04353
04354 if (n < 3) {
04355 ogroup[3] = '=';
04356
04357 if (n < 2)
04358 ogroup[2] = '=';
04359 }
04360
04361 for (i = 0; i < 4; i++)
04362 ochar(&bio, ogroup[i], so);
04363 }
04364 }
04365
04366 fclose(fi);
04367
04368 if (fputs(ENDL, so) == EOF) {
04369 return 0;
04370 }
04371
04372 return 1;
04373 }
04374
04375 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)
04376 {
04377 char callerid[256];
04378 char num[12];
04379 char fromdir[256], fromfile[256];
04380 struct ast_config *msg_cfg;
04381 const char *origcallerid, *origtime;
04382 char origcidname[80], origcidnum[80], origdate[80];
04383 int inttime;
04384 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04385
04386
04387 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04388 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04389 snprintf(num, sizeof(num), "%d", msgnum);
04390 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04391 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04392 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04393 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04394 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04395 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04396 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04397 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04398 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04399 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04400
04401
04402 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04403 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04404 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04405 strcat(fromfile, ".txt");
04406 }
04407 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04408 if (option_debug > 0) {
04409 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04410 }
04411 return;
04412 }
04413
04414 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04415 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04416 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04417 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04418 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04419 }
04420
04421 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04422 struct timeval tv = { inttime, };
04423 struct ast_tm tm;
04424 ast_localtime(&tv, &tm, NULL);
04425 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04426 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04427 }
04428 ast_config_destroy(msg_cfg);
04429 }
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04440 {
04441 const char *ptr;
04442
04443
04444 ast_str_set(buf, maxlen, "\"");
04445 for (ptr = from; *ptr; ptr++) {
04446 if (*ptr == '"' || *ptr == '\\') {
04447 ast_str_append(buf, maxlen, "\\%c", *ptr);
04448 } else {
04449 ast_str_append(buf, maxlen, "%c", *ptr);
04450 }
04451 }
04452 ast_str_append(buf, maxlen, "\"");
04453
04454 return ast_str_buffer(*buf);
04455 }
04456
04457
04458
04459
04460
04461 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04462 {
04463 const struct vm_zone *z = NULL;
04464 struct timeval t = ast_tvnow();
04465
04466
04467 if (!ast_strlen_zero(vmu->zonetag)) {
04468
04469 AST_LIST_LOCK(&zones);
04470 AST_LIST_TRAVERSE(&zones, z, list) {
04471 if (!strcmp(z->name, vmu->zonetag))
04472 break;
04473 }
04474 AST_LIST_UNLOCK(&zones);
04475 }
04476 ast_localtime(&t, tm, z ? z->timezone : NULL);
04477 return tm;
04478 }
04479
04480
04481
04482
04483
04484 static int check_mime(const char *str)
04485 {
04486 for (; *str; str++) {
04487 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04488 return 1;
04489 }
04490 }
04491 return 0;
04492 }
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04512 {
04513 struct ast_str *tmp = ast_str_alloca(80);
04514 int first_section = 1;
04515
04516 ast_str_reset(*end);
04517 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04518 for (; *start; start++) {
04519 int need_encoding = 0;
04520 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04521 need_encoding = 1;
04522 }
04523 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04524 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04525 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04526 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04527
04528 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04529 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04530 first_section = 0;
04531 }
04532 if (need_encoding && *start == ' ') {
04533 ast_str_append(&tmp, -1, "_");
04534 } else if (need_encoding) {
04535 ast_str_append(&tmp, -1, "=%hhX", *start);
04536 } else {
04537 ast_str_append(&tmp, -1, "%c", *start);
04538 }
04539 }
04540 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04541 return ast_str_buffer(*end);
04542 }
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566
04567 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)
04568 {
04569 char date[256];
04570 char host[MAXHOSTNAMELEN] = "";
04571 char who[256];
04572 char bound[256];
04573 char dur[256];
04574 struct ast_tm tm;
04575 char enc_cidnum[256] = "", enc_cidname[256] = "";
04576 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04577 char *greeting_attachment;
04578 char filename[256];
04579
04580 if (!str1 || !str2) {
04581 ast_free(str1);
04582 ast_free(str2);
04583 return;
04584 }
04585
04586 if (cidnum) {
04587 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04588 }
04589 if (cidname) {
04590 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04591 }
04592 gethostname(host, sizeof(host) - 1);
04593
04594 if (strchr(srcemail, '@')) {
04595 ast_copy_string(who, srcemail, sizeof(who));
04596 } else {
04597 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04598 }
04599
04600 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04601 if (greeting_attachment) {
04602 *greeting_attachment++ = '\0';
04603 }
04604
04605 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04606 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04607 fprintf(p, "Date: %s" ENDL, date);
04608
04609
04610 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04611
04612 if (!ast_strlen_zero(fromstring)) {
04613 struct ast_channel *ast;
04614 if ((ast = ast_dummy_channel_alloc())) {
04615 char *ptr;
04616 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04617 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04618
04619 if (check_mime(ast_str_buffer(str1))) {
04620 int first_line = 1;
04621 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04622 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04623 *ptr = '\0';
04624 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04625 first_line = 0;
04626
04627 ast_str_set(&str2, 0, "%s", ptr + 1);
04628 }
04629 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04630 } else {
04631 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04632 }
04633 ast = ast_channel_unref(ast);
04634 } else {
04635 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04636 }
04637 } else {
04638 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04639 }
04640
04641 if (check_mime(vmu->fullname)) {
04642 int first_line = 1;
04643 char *ptr;
04644 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04645 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04646 *ptr = '\0';
04647 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04648 first_line = 0;
04649
04650 ast_str_set(&str2, 0, "%s", ptr + 1);
04651 }
04652 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04653 } else {
04654 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04655 }
04656
04657 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04658 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04659 struct ast_channel *ast;
04660 if ((ast = ast_dummy_channel_alloc())) {
04661 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04662 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04663 if (check_mime(ast_str_buffer(str1))) {
04664 int first_line = 1;
04665 char *ptr;
04666 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04667 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04668 *ptr = '\0';
04669 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04670 first_line = 0;
04671
04672 ast_str_set(&str2, 0, "%s", ptr + 1);
04673 }
04674 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04675 } else {
04676 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04677 }
04678 ast = ast_channel_unref(ast);
04679 } else {
04680 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04681 }
04682 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04683 if (ast_strlen_zero(flag)) {
04684 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04685 } else {
04686 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04687 }
04688 } else {
04689 if (ast_strlen_zero(flag)) {
04690 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04691 } else {
04692 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04693 }
04694 }
04695
04696 fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
04697 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04698 if (imap) {
04699
04700 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04701
04702 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04703 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04704 #ifdef IMAP_STORAGE
04705 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04706 #else
04707 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04708 #endif
04709
04710 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04711 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04712 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04713 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04714 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04715 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04716 if (!ast_strlen_zero(category)) {
04717 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04718 } else {
04719 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04720 }
04721 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04722 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04723 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04724 }
04725 if (!ast_strlen_zero(cidnum)) {
04726 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04727 }
04728 if (!ast_strlen_zero(cidname)) {
04729 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04730 }
04731 fprintf(p, "MIME-Version: 1.0" ENDL);
04732 if (attach_user_voicemail) {
04733
04734 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
04735 (int) getpid(), (unsigned int) ast_random());
04736
04737 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04738 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04739 fprintf(p, "--%s" ENDL, bound);
04740 }
04741 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04742 if (emailbody || vmu->emailbody) {
04743 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04744 struct ast_channel *ast;
04745 if ((ast = ast_dummy_channel_alloc())) {
04746 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04747 ast_str_substitute_variables(&str1, 0, ast, e_body);
04748 #ifdef IMAP_STORAGE
04749 {
04750
04751 char *line = ast_str_buffer(str1), *next;
04752 do {
04753
04754 if ((next = strchr(line, '\n'))) {
04755 *next++ = '\0';
04756 }
04757 fprintf(p, "%s" ENDL, line);
04758 line = next;
04759 } while (!ast_strlen_zero(line));
04760 }
04761 #else
04762 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04763 #endif
04764 ast = ast_channel_unref(ast);
04765 } else {
04766 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04767 }
04768 } else if (msgnum > -1) {
04769 if (strcmp(vmu->mailbox, mailbox)) {
04770
04771 struct ast_config *msg_cfg;
04772 const char *v;
04773 int inttime;
04774 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04775 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04776
04777 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04778 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04779 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04780 strcat(fromfile, ".txt");
04781 }
04782 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
04783 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04784 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04785 }
04786
04787
04788
04789 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04790 struct timeval tv = { inttime, };
04791 struct ast_tm tm;
04792 ast_localtime(&tv, &tm, NULL);
04793 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04794 }
04795 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04796 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04797 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04798 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04799 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04800 date, origcallerid, origdate);
04801 ast_config_destroy(msg_cfg);
04802 } else {
04803 goto plain_message;
04804 }
04805 } else {
04806 plain_message:
04807 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04808 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04809 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04810 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04811 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04812 }
04813 } else {
04814 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04815 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04816 }
04817
04818 if (imap || attach_user_voicemail) {
04819 if (!ast_strlen_zero(attach2)) {
04820 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04821 ast_debug(5, "creating second attachment filename %s\n", filename);
04822 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04823 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04824 ast_debug(5, "creating attachment filename %s\n", filename);
04825 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04826 } else {
04827 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04828 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04829 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04830 }
04831 }
04832 ast_free(str1);
04833 ast_free(str2);
04834 }
04835
04836 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)
04837 {
04838 char tmpdir[256], newtmp[256];
04839 char fname[256];
04840 char tmpcmd[256];
04841 int tmpfd = -1;
04842 int soxstatus = 0;
04843
04844
04845 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04846
04847 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04848 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04849 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04850 tmpfd = mkstemp(newtmp);
04851 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04852 ast_debug(3, "newtmp: %s\n", newtmp);
04853 if (tmpfd > -1) {
04854 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04855 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04856 attach = newtmp;
04857 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04858 } else {
04859 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04860 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04861 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04862 }
04863 }
04864 }
04865 fprintf(p, "--%s" ENDL, bound);
04866 if (msgnum > -1)
04867 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04868 else
04869 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04870 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04871 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04872 if (msgnum > -1)
04873 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04874 else
04875 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04876 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04877 base_encode(fname, p);
04878 if (last)
04879 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04880 if (tmpfd > -1) {
04881 if (soxstatus == 0) {
04882 unlink(fname);
04883 }
04884 close(tmpfd);
04885 unlink(newtmp);
04886 }
04887 return 0;
04888 }
04889
04890 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)
04891 {
04892 FILE *p = NULL;
04893 char tmp[80] = "/tmp/astmail-XXXXXX";
04894 char tmp2[256];
04895 char *stringp;
04896
04897 if (vmu && ast_strlen_zero(vmu->email)) {
04898 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04899 return(0);
04900 }
04901
04902
04903 format = ast_strdupa(format);
04904 stringp = format;
04905 strsep(&stringp, "|");
04906
04907 if (!strcmp(format, "wav49"))
04908 format = "WAV";
04909 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));
04910
04911
04912 if ((p = vm_mkftemp(tmp)) == NULL) {
04913 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04914 return -1;
04915 } else {
04916 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04917 fclose(p);
04918 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04919 ast_safe_system(tmp2);
04920 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04921 }
04922 return 0;
04923 }
04924
04925 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)
04926 {
04927 char enc_cidnum[256], enc_cidname[256];
04928 char date[256];
04929 char host[MAXHOSTNAMELEN] = "";
04930 char who[256];
04931 char dur[PATH_MAX];
04932 char tmp[80] = "/tmp/astmail-XXXXXX";
04933 char tmp2[PATH_MAX];
04934 struct ast_tm tm;
04935 FILE *p;
04936 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04937
04938 if (!str1 || !str2) {
04939 ast_free(str1);
04940 ast_free(str2);
04941 return -1;
04942 }
04943
04944 if (cidnum) {
04945 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04946 }
04947 if (cidname) {
04948 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04949 }
04950
04951 if ((p = vm_mkftemp(tmp)) == NULL) {
04952 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04953 ast_free(str1);
04954 ast_free(str2);
04955 return -1;
04956 }
04957 gethostname(host, sizeof(host)-1);
04958 if (strchr(srcemail, '@')) {
04959 ast_copy_string(who, srcemail, sizeof(who));
04960 } else {
04961 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04962 }
04963 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04964 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04965 fprintf(p, "Date: %s\n", date);
04966
04967
04968 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04969
04970 if (!ast_strlen_zero(pagerfromstring)) {
04971 struct ast_channel *ast;
04972 if ((ast = ast_dummy_channel_alloc())) {
04973 char *ptr;
04974 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04975 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04976
04977 if (check_mime(ast_str_buffer(str1))) {
04978 int first_line = 1;
04979 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04980 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04981 *ptr = '\0';
04982 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04983 first_line = 0;
04984
04985 ast_str_set(&str2, 0, "%s", ptr + 1);
04986 }
04987 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04988 } else {
04989 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04990 }
04991 ast = ast_channel_unref(ast);
04992 } else {
04993 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04994 }
04995 } else {
04996 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04997 }
04998
04999 if (check_mime(vmu->fullname)) {
05000 int first_line = 1;
05001 char *ptr;
05002 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
05003 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05004 *ptr = '\0';
05005 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
05006 first_line = 0;
05007
05008 ast_str_set(&str2, 0, "%s", ptr + 1);
05009 }
05010 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
05011 } else {
05012 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05013 }
05014
05015 if (!ast_strlen_zero(pagersubject)) {
05016 struct ast_channel *ast;
05017 if ((ast = ast_dummy_channel_alloc())) {
05018 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05019 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05020 if (check_mime(ast_str_buffer(str1))) {
05021 int first_line = 1;
05022 char *ptr;
05023 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05024 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05025 *ptr = '\0';
05026 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05027 first_line = 0;
05028
05029 ast_str_set(&str2, 0, "%s", ptr + 1);
05030 }
05031 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05032 } else {
05033 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05034 }
05035 ast = ast_channel_unref(ast);
05036 } else {
05037 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05038 }
05039 } else {
05040 if (ast_strlen_zero(flag)) {
05041 fprintf(p, "Subject: New VM\n\n");
05042 } else {
05043 fprintf(p, "Subject: New %s VM\n\n", flag);
05044 }
05045 }
05046
05047 if (pagerbody) {
05048 struct ast_channel *ast;
05049 if ((ast = ast_dummy_channel_alloc())) {
05050 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05051 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05052 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05053 ast = ast_channel_unref(ast);
05054 } else {
05055 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05056 }
05057 } else {
05058 fprintf(p, "New %s long %s msg in box %s\n"
05059 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05060 }
05061
05062 fclose(p);
05063 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05064 ast_safe_system(tmp2);
05065 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05066 ast_free(str1);
05067 ast_free(str2);
05068 return 0;
05069 }
05070
05071
05072
05073
05074
05075
05076
05077
05078
05079
05080 static int get_date(char *s, int len)
05081 {
05082 struct ast_tm tm;
05083 struct timeval t = ast_tvnow();
05084
05085 ast_localtime(&t, &tm, "UTC");
05086
05087 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05088 }
05089
05090 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05091 {
05092 int res;
05093 char fn[PATH_MAX];
05094 char dest[PATH_MAX];
05095
05096 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05097
05098 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05099 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05100 return -1;
05101 }
05102
05103 RETRIEVE(fn, -1, ext, context);
05104 if (ast_fileexists(fn, NULL, NULL) > 0) {
05105 res = ast_stream_and_wait(chan, fn, ecodes);
05106 if (res) {
05107 DISPOSE(fn, -1);
05108 return res;
05109 }
05110 } else {
05111
05112 DISPOSE(fn, -1);
05113 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05114 if (res)
05115 return res;
05116 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05117 if (res)
05118 return res;
05119 }
05120 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05121 return res;
05122 }
05123
05124 static void free_zone(struct vm_zone *z)
05125 {
05126 ast_free(z);
05127 }
05128
05129 #ifdef ODBC_STORAGE
05130 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05131 {
05132 int x = -1;
05133 int res;
05134 SQLHSTMT stmt = NULL;
05135 char sql[PATH_MAX];
05136 char rowdata[20];
05137 char tmp[PATH_MAX] = "";
05138 struct odbc_obj *obj = NULL;
05139 char *context;
05140 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05141
05142 if (newmsgs)
05143 *newmsgs = 0;
05144 if (oldmsgs)
05145 *oldmsgs = 0;
05146 if (urgentmsgs)
05147 *urgentmsgs = 0;
05148
05149
05150 if (ast_strlen_zero(mailbox))
05151 return 0;
05152
05153 ast_copy_string(tmp, mailbox, sizeof(tmp));
05154
05155 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05156 int u, n, o;
05157 char *next, *remaining = tmp;
05158 while ((next = strsep(&remaining, " ,"))) {
05159 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05160 return -1;
05161 }
05162 if (urgentmsgs) {
05163 *urgentmsgs += u;
05164 }
05165 if (newmsgs) {
05166 *newmsgs += n;
05167 }
05168 if (oldmsgs) {
05169 *oldmsgs += o;
05170 }
05171 }
05172 return 0;
05173 }
05174
05175 context = strchr(tmp, '@');
05176 if (context) {
05177 *context = '\0';
05178 context++;
05179 } else
05180 context = "default";
05181
05182 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05183 do {
05184 if (newmsgs) {
05185 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05186 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05187 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05188 break;
05189 }
05190 res = SQLFetch(stmt);
05191 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05192 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05193 break;
05194 }
05195 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05196 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05197 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05198 break;
05199 }
05200 *newmsgs = atoi(rowdata);
05201 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05202 }
05203
05204 if (oldmsgs) {
05205 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05206 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05207 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05208 break;
05209 }
05210 res = SQLFetch(stmt);
05211 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05212 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05213 break;
05214 }
05215 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05216 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05217 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05218 break;
05219 }
05220 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05221 *oldmsgs = atoi(rowdata);
05222 }
05223
05224 if (urgentmsgs) {
05225 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05226 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05227 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05228 break;
05229 }
05230 res = SQLFetch(stmt);
05231 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05232 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05233 break;
05234 }
05235 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05236 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05237 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05238 break;
05239 }
05240 *urgentmsgs = atoi(rowdata);
05241 }
05242
05243 x = 0;
05244 } while (0);
05245 } else {
05246 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05247 }
05248
05249 if (stmt) {
05250 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05251 }
05252 if (obj) {
05253 ast_odbc_release_obj(obj);
05254 }
05255 return x;
05256 }
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266
05267 static int messagecount(const char *context, const char *mailbox, const char *folder)
05268 {
05269 struct odbc_obj *obj = NULL;
05270 int nummsgs = 0;
05271 int res;
05272 SQLHSTMT stmt = NULL;
05273 char sql[PATH_MAX];
05274 char rowdata[20];
05275 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05276 if (!folder)
05277 folder = "INBOX";
05278
05279 if (ast_strlen_zero(mailbox))
05280 return 0;
05281
05282 obj = ast_odbc_request_obj(odbc_database, 0);
05283 if (obj) {
05284 if (!strcmp(folder, "INBOX")) {
05285 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);
05286 } else {
05287 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05288 }
05289 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05290 if (!stmt) {
05291 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05292 goto yuck;
05293 }
05294 res = SQLFetch(stmt);
05295 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05296 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05297 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05298 goto yuck;
05299 }
05300 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05301 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05302 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05303 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05304 goto yuck;
05305 }
05306 nummsgs = atoi(rowdata);
05307 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05308 } else
05309 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05310
05311 yuck:
05312 if (obj)
05313 ast_odbc_release_obj(obj);
05314 return nummsgs;
05315 }
05316
05317
05318
05319
05320
05321
05322
05323
05324
05325 static int has_voicemail(const char *mailbox, const char *folder)
05326 {
05327 char tmp[256], *tmp2 = tmp, *box, *context;
05328 ast_copy_string(tmp, mailbox, sizeof(tmp));
05329 while ((context = box = strsep(&tmp2, ",&"))) {
05330 strsep(&context, "@");
05331 if (ast_strlen_zero(context))
05332 context = "default";
05333 if (messagecount(context, box, folder))
05334 return 1;
05335 }
05336 return 0;
05337 }
05338 #endif
05339 #ifndef IMAP_STORAGE
05340
05341
05342
05343
05344
05345
05346
05347
05348
05349
05350
05351
05352
05353
05354
05355
05356 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)
05357 {
05358 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05359 const char *frombox = mbox(vmu, imbox);
05360 const char *userfolder;
05361 int recipmsgnum;
05362 int res = 0;
05363
05364 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05365
05366 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05367 userfolder = "Urgent";
05368 } else {
05369 userfolder = "INBOX";
05370 }
05371
05372 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05373
05374 if (!dir)
05375 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05376 else
05377 ast_copy_string(fromdir, dir, sizeof(fromdir));
05378
05379 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05380 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05381
05382 if (vm_lock_path(todir))
05383 return ERROR_LOCK_PATH;
05384
05385 recipmsgnum = last_message_index(recip, todir) + 1;
05386 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05387 make_file(topath, sizeof(topath), todir, recipmsgnum);
05388 #ifndef ODBC_STORAGE
05389 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05390 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05391 } else {
05392 #endif
05393
05394
05395
05396 copy_plain_file(frompath, topath);
05397 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05398 vm_delete(topath);
05399 #ifndef ODBC_STORAGE
05400 }
05401 #endif
05402 } else {
05403 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05404 res = -1;
05405 }
05406 ast_unlock_path(todir);
05407 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05408 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05409 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05410 flag);
05411
05412 return res;
05413 }
05414 #endif
05415 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05416
05417 static int messagecount(const char *context, const char *mailbox, const char *folder)
05418 {
05419 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05420 }
05421
05422 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05423 {
05424 DIR *dir;
05425 struct dirent *de;
05426 char fn[256];
05427 int ret = 0;
05428
05429
05430 if (ast_strlen_zero(mailbox))
05431 return 0;
05432
05433 if (ast_strlen_zero(folder))
05434 folder = "INBOX";
05435 if (ast_strlen_zero(context))
05436 context = "default";
05437
05438 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05439
05440 if (!(dir = opendir(fn)))
05441 return 0;
05442
05443 while ((de = readdir(dir))) {
05444 if (!strncasecmp(de->d_name, "msg", 3)) {
05445 if (shortcircuit) {
05446 ret = 1;
05447 break;
05448 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05449 ret++;
05450 }
05451 }
05452 }
05453
05454 closedir(dir);
05455
05456 return ret;
05457 }
05458
05459
05460
05461
05462
05463
05464
05465
05466
05467
05468 static int has_voicemail(const char *mailbox, const char *folder)
05469 {
05470 char tmp[256], *tmp2 = tmp, *box, *context;
05471 ast_copy_string(tmp, mailbox, sizeof(tmp));
05472 if (ast_strlen_zero(folder)) {
05473 folder = "INBOX";
05474 }
05475 while ((box = strsep(&tmp2, ",&"))) {
05476 if ((context = strchr(box, '@')))
05477 *context++ = '\0';
05478 else
05479 context = "default";
05480 if (__has_voicemail(context, box, folder, 1))
05481 return 1;
05482
05483 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05484 return 1;
05485 }
05486 }
05487 return 0;
05488 }
05489
05490
05491 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05492 {
05493 char tmp[256];
05494 char *context;
05495
05496
05497 if (ast_strlen_zero(mailbox))
05498 return 0;
05499
05500 if (newmsgs)
05501 *newmsgs = 0;
05502 if (oldmsgs)
05503 *oldmsgs = 0;
05504 if (urgentmsgs)
05505 *urgentmsgs = 0;
05506
05507 if (strchr(mailbox, ',')) {
05508 int tmpnew, tmpold, tmpurgent;
05509 char *mb, *cur;
05510
05511 ast_copy_string(tmp, mailbox, sizeof(tmp));
05512 mb = tmp;
05513 while ((cur = strsep(&mb, ", "))) {
05514 if (!ast_strlen_zero(cur)) {
05515 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05516 return -1;
05517 else {
05518 if (newmsgs)
05519 *newmsgs += tmpnew;
05520 if (oldmsgs)
05521 *oldmsgs += tmpold;
05522 if (urgentmsgs)
05523 *urgentmsgs += tmpurgent;
05524 }
05525 }
05526 }
05527 return 0;
05528 }
05529
05530 ast_copy_string(tmp, mailbox, sizeof(tmp));
05531
05532 if ((context = strchr(tmp, '@')))
05533 *context++ = '\0';
05534 else
05535 context = "default";
05536
05537 if (newmsgs)
05538 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05539 if (oldmsgs)
05540 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05541 if (urgentmsgs)
05542 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05543
05544 return 0;
05545 }
05546
05547 #endif
05548
05549
05550 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05551 {
05552 int urgentmsgs = 0;
05553 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05554 if (newmsgs) {
05555 *newmsgs += urgentmsgs;
05556 }
05557 return res;
05558 }
05559
05560 static void run_externnotify(char *context, char *extension, const char *flag)
05561 {
05562 char arguments[255];
05563 char ext_context[256] = "";
05564 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05565 struct ast_smdi_mwi_message *mwi_msg;
05566
05567 if (!ast_strlen_zero(context))
05568 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05569 else
05570 ast_copy_string(ext_context, extension, sizeof(ext_context));
05571
05572 if (smdi_iface) {
05573 if (ast_app_has_voicemail(ext_context, NULL))
05574 ast_smdi_mwi_set(smdi_iface, extension);
05575 else
05576 ast_smdi_mwi_unset(smdi_iface, extension);
05577
05578 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05579 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05580 if (!strncmp(mwi_msg->cause, "INV", 3))
05581 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05582 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05583 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05584 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05585 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05586 } else {
05587 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05588 }
05589 }
05590
05591 if (!ast_strlen_zero(externnotify)) {
05592 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05593 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05594 } else {
05595 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05596 externnotify, S_OR(context, "\"\""),
05597 extension, newvoicemails,
05598 oldvoicemails, urgentvoicemails);
05599 ast_debug(1, "Executing %s\n", arguments);
05600 ast_safe_system(arguments);
05601 }
05602 }
05603 }
05604
05605
05606
05607
05608
05609
05610 struct leave_vm_options {
05611 unsigned int flags;
05612 signed char record_gain;
05613 char *exitcontext;
05614 };
05615
05616
05617
05618
05619
05620
05621
05622
05623
05624
05625
05626 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05627 {
05628 #ifdef IMAP_STORAGE
05629 int newmsgs, oldmsgs;
05630 #else
05631 char urgdir[PATH_MAX];
05632 #endif
05633 char txtfile[PATH_MAX];
05634 char tmptxtfile[PATH_MAX];
05635 struct vm_state *vms = NULL;
05636 char callerid[256];
05637 FILE *txt;
05638 char date[256];
05639 int txtdes;
05640 int res = 0;
05641 int msgnum;
05642 int duration = 0;
05643 int sound_duration = 0;
05644 int ausemacro = 0;
05645 int ousemacro = 0;
05646 int ouseexten = 0;
05647 char tmpdur[16];
05648 char priority[16];
05649 char origtime[16];
05650 char dir[PATH_MAX];
05651 char tmpdir[PATH_MAX];
05652 char fn[PATH_MAX];
05653 char prefile[PATH_MAX] = "";
05654 char tempfile[PATH_MAX] = "";
05655 char ext_context[256] = "";
05656 char fmt[80];
05657 char *context;
05658 char ecodes[17] = "#";
05659 struct ast_str *tmp = ast_str_create(16);
05660 char *tmpptr;
05661 struct ast_vm_user *vmu;
05662 struct ast_vm_user svm;
05663 const char *category = NULL;
05664 const char *code;
05665 const char *alldtmf = "0123456789ABCD*#";
05666 char flag[80];
05667
05668 if (!tmp) {
05669 return -1;
05670 }
05671
05672 ast_str_set(&tmp, 0, "%s", ext);
05673 ext = ast_str_buffer(tmp);
05674 if ((context = strchr(ext, '@'))) {
05675 *context++ = '\0';
05676 tmpptr = strchr(context, '&');
05677 } else {
05678 tmpptr = strchr(ext, '&');
05679 }
05680
05681 if (tmpptr)
05682 *tmpptr++ = '\0';
05683
05684 ast_channel_lock(chan);
05685 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05686 category = ast_strdupa(category);
05687 }
05688 ast_channel_unlock(chan);
05689
05690 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05691 ast_copy_string(flag, "Urgent", sizeof(flag));
05692 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05693 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05694 } else {
05695 flag[0] = '\0';
05696 }
05697
05698 ast_debug(3, "Before find_user\n");
05699 if (!(vmu = find_user(&svm, context, ext))) {
05700 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05701 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05702 ast_free(tmp);
05703 return res;
05704 }
05705
05706 if (strcmp(vmu->context, "default"))
05707 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05708 else
05709 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05710
05711
05712
05713
05714
05715
05716 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05717 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05718 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05719 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05720 }
05721
05722
05723
05724
05725 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05726 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05727 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05728 ast_free(tmp);
05729 return -1;
05730 }
05731 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05732 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05733 ast_copy_string(prefile, tempfile, sizeof(prefile));
05734
05735 DISPOSE(tempfile, -1);
05736
05737 #ifndef IMAP_STORAGE
05738 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05739 #else
05740 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05741 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05742 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05743 }
05744 #endif
05745
05746
05747 if (ast_test_flag(vmu, VM_OPERATOR)) {
05748 if (!ast_strlen_zero(vmu->exit)) {
05749 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05750 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05751 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05752 ouseexten = 1;
05753 }
05754 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05755 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05756 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05757 ouseexten = 1;
05758 } else if (!ast_strlen_zero(chan->macrocontext)
05759 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05760 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05761 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05762 ousemacro = 1;
05763 }
05764 }
05765
05766 if (!ast_strlen_zero(vmu->exit)) {
05767 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05768 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05769 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05770 }
05771 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05772 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05773 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05774 } else if (!ast_strlen_zero(chan->macrocontext)
05775 && ast_exists_extension(chan, chan->macrocontext, "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 ausemacro = 1;
05779 }
05780
05781 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05782 for (code = alldtmf; *code; code++) {
05783 char e[2] = "";
05784 e[0] = *code;
05785 if (strchr(ecodes, e[0]) == NULL
05786 && ast_canmatch_extension(chan,
05787 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05788 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05789 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05790 }
05791 }
05792 }
05793
05794
05795 if (!ast_strlen_zero(prefile)) {
05796 #ifdef ODBC_STORAGE
05797 int success =
05798 #endif
05799 RETRIEVE(prefile, -1, ext, context);
05800 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05801 if (ast_streamfile(chan, prefile, chan->language) > -1)
05802 res = ast_waitstream(chan, ecodes);
05803 #ifdef ODBC_STORAGE
05804 if (success == -1) {
05805
05806 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05807 store_file(prefile, vmu->mailbox, vmu->context, -1);
05808 }
05809 #endif
05810 } else {
05811 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05812 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05813 }
05814 DISPOSE(prefile, -1);
05815 if (res < 0) {
05816 ast_debug(1, "Hang up during prefile playback\n");
05817 free_user(vmu);
05818 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05819 ast_free(tmp);
05820 return -1;
05821 }
05822 }
05823 if (res == '#') {
05824
05825 ast_set_flag(options, OPT_SILENT);
05826 res = 0;
05827 }
05828
05829 if (vmu->maxmsg == 0) {
05830 if (option_debug > 2)
05831 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05832 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05833 goto leave_vm_out;
05834 }
05835 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05836 res = ast_stream_and_wait(chan, INTRO, ecodes);
05837 if (res == '#') {
05838 ast_set_flag(options, OPT_SILENT);
05839 res = 0;
05840 }
05841 }
05842 if (res > 0)
05843 ast_stopstream(chan);
05844
05845
05846 if (res == '*') {
05847 chan->exten[0] = 'a';
05848 chan->exten[1] = '\0';
05849 if (!ast_strlen_zero(vmu->exit)) {
05850 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05851 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05852 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05853 }
05854 chan->priority = 0;
05855 free_user(vmu);
05856 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05857 ast_free(tmp);
05858 return 0;
05859 }
05860
05861
05862 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05863 transfer:
05864 if (ouseexten || ousemacro) {
05865 chan->exten[0] = 'o';
05866 chan->exten[1] = '\0';
05867 if (!ast_strlen_zero(vmu->exit)) {
05868 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05869 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05870 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05871 }
05872 ast_play_and_wait(chan, "transfer");
05873 chan->priority = 0;
05874 free_user(vmu);
05875 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05876 }
05877 ast_free(tmp);
05878 return OPERATOR_EXIT;
05879 }
05880
05881
05882 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05883 if (!ast_strlen_zero(options->exitcontext)) {
05884 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05885 }
05886 free_user(vmu);
05887 ast_free(tmp);
05888 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05889 return res;
05890 }
05891
05892 if (res < 0) {
05893 free_user(vmu);
05894 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05895 ast_free(tmp);
05896 return -1;
05897 }
05898
05899 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05900 if (!ast_strlen_zero(fmt)) {
05901 msgnum = 0;
05902
05903 #ifdef IMAP_STORAGE
05904
05905
05906 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05907 if (res < 0) {
05908 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05909 ast_free(tmp);
05910 return -1;
05911 }
05912 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05913
05914
05915
05916
05917 if (!(vms = create_vm_state_from_user(vmu))) {
05918 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05919 ast_free(tmp);
05920 return -1;
05921 }
05922 }
05923 vms->newmessages++;
05924
05925
05926 msgnum = newmsgs + oldmsgs;
05927 ast_debug(3, "Messagecount set to %d\n", msgnum);
05928 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05929
05930 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05931
05932 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05933 goto leave_vm_out;
05934 }
05935 #else
05936 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05937 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05938 if (!res)
05939 res = ast_waitstream(chan, "");
05940 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05941 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05942 inprocess_count(vmu->mailbox, vmu->context, -1);
05943 goto leave_vm_out;
05944 }
05945
05946 #endif
05947 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05948 txtdes = mkstemp(tmptxtfile);
05949 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05950 if (txtdes < 0) {
05951 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05952 if (!res)
05953 res = ast_waitstream(chan, "");
05954 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05955 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05956 inprocess_count(vmu->mailbox, vmu->context, -1);
05957 goto leave_vm_out;
05958 }
05959
05960
05961 if (res >= 0) {
05962
05963 res = ast_stream_and_wait(chan, "beep", "");
05964 }
05965
05966
05967 if (ast_check_realtime("voicemail_data")) {
05968 snprintf(priority, sizeof(priority), "%d", chan->priority);
05969 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05970 get_date(date, sizeof(date));
05971 ast_callerid_merge(callerid, sizeof(callerid),
05972 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05973 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05974 "Unknown");
05975 ast_store_realtime("voicemail_data",
05976 "origmailbox", ext,
05977 "context", chan->context,
05978 "macrocontext", chan->macrocontext,
05979 "exten", chan->exten,
05980 "priority", priority,
05981 "callerchan", chan->name,
05982 "callerid", callerid,
05983 "origdate", date,
05984 "origtime", origtime,
05985 "category", S_OR(category, ""),
05986 "filename", tmptxtfile,
05987 SENTINEL);
05988 }
05989
05990
05991 txt = fdopen(txtdes, "w+");
05992 if (txt) {
05993 get_date(date, sizeof(date));
05994 ast_callerid_merge(callerid, sizeof(callerid),
05995 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05996 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05997 "Unknown");
05998 fprintf(txt,
05999 ";\n"
06000 "; Message Information file\n"
06001 ";\n"
06002 "[message]\n"
06003 "origmailbox=%s\n"
06004 "context=%s\n"
06005 "macrocontext=%s\n"
06006 "exten=%s\n"
06007 "rdnis=%s\n"
06008 "priority=%d\n"
06009 "callerchan=%s\n"
06010 "callerid=%s\n"
06011 "origdate=%s\n"
06012 "origtime=%ld\n"
06013 "category=%s\n",
06014 ext,
06015 chan->context,
06016 chan->macrocontext,
06017 chan->exten,
06018 S_COR(chan->redirecting.from.number.valid,
06019 chan->redirecting.from.number.str, "unknown"),
06020 chan->priority,
06021 chan->name,
06022 callerid,
06023 date, (long) time(NULL),
06024 category ? category : "");
06025 } else {
06026 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06027 inprocess_count(vmu->mailbox, vmu->context, -1);
06028 if (ast_check_realtime("voicemail_data")) {
06029 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06030 }
06031 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06032 goto leave_vm_out;
06033 }
06034 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06035
06036 if (txt) {
06037 fprintf(txt, "flag=%s\n", flag);
06038 if (sound_duration < vmu->minsecs) {
06039 fclose(txt);
06040 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06041 ast_filedelete(tmptxtfile, NULL);
06042 unlink(tmptxtfile);
06043 if (ast_check_realtime("voicemail_data")) {
06044 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06045 }
06046 inprocess_count(vmu->mailbox, vmu->context, -1);
06047 } else {
06048 fprintf(txt, "duration=%d\n", duration);
06049 fclose(txt);
06050 if (vm_lock_path(dir)) {
06051 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06052
06053 ast_filedelete(tmptxtfile, NULL);
06054 unlink(tmptxtfile);
06055 inprocess_count(vmu->mailbox, vmu->context, -1);
06056 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06057 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06058 unlink(tmptxtfile);
06059 ast_unlock_path(dir);
06060 inprocess_count(vmu->mailbox, vmu->context, -1);
06061 if (ast_check_realtime("voicemail_data")) {
06062 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06063 }
06064 } else {
06065 #ifndef IMAP_STORAGE
06066 msgnum = last_message_index(vmu, dir) + 1;
06067 #endif
06068 make_file(fn, sizeof(fn), dir, msgnum);
06069
06070
06071 #ifndef IMAP_STORAGE
06072 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06073 #else
06074 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06075 #endif
06076
06077 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06078 ast_filerename(tmptxtfile, fn, NULL);
06079 rename(tmptxtfile, txtfile);
06080 inprocess_count(vmu->mailbox, vmu->context, -1);
06081
06082
06083
06084 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06085 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06086
06087 ast_unlock_path(dir);
06088 if (ast_check_realtime("voicemail_data")) {
06089 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06090 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06091 }
06092
06093
06094
06095 if (ast_fileexists(fn, NULL, NULL) > 0) {
06096 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06097 }
06098
06099
06100 while (tmpptr) {
06101 struct ast_vm_user recipu, *recip;
06102 char *exten, *cntx;
06103
06104 exten = strsep(&tmpptr, "&");
06105 cntx = strchr(exten, '@');
06106 if (cntx) {
06107 *cntx = '\0';
06108 cntx++;
06109 }
06110 if ((recip = find_user(&recipu, cntx, exten))) {
06111 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06112 free_user(recip);
06113 }
06114 }
06115 #ifndef IMAP_STORAGE
06116 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06117
06118 char sfn[PATH_MAX];
06119 char dfn[PATH_MAX];
06120 int x;
06121
06122 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06123 x = last_message_index(vmu, urgdir) + 1;
06124 make_file(sfn, sizeof(sfn), dir, msgnum);
06125 make_file(dfn, sizeof(dfn), urgdir, x);
06126 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06127 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06128
06129 ast_copy_string(fn, dfn, sizeof(fn));
06130 msgnum = x;
06131 }
06132 #endif
06133
06134 if (ast_fileexists(fn, NULL, NULL)) {
06135 #ifdef IMAP_STORAGE
06136 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06137 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06138 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06139 flag);
06140 #else
06141 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06142 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06143 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06144 flag);
06145 #endif
06146 }
06147
06148
06149 if (ast_fileexists(fn, NULL, NULL)) {
06150 DISPOSE(dir, msgnum);
06151 }
06152 }
06153 }
06154 } else {
06155 inprocess_count(vmu->mailbox, vmu->context, -1);
06156 }
06157 if (res == '0') {
06158 goto transfer;
06159 } else if (res > 0 && res != 't')
06160 res = 0;
06161
06162 if (sound_duration < vmu->minsecs)
06163
06164 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06165 else
06166 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06167 } else
06168 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06169 leave_vm_out:
06170 free_user(vmu);
06171
06172 #ifdef IMAP_STORAGE
06173
06174 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06175 if (expungeonhangup == 1) {
06176 ast_mutex_lock(&vms->lock);
06177 #ifdef HAVE_IMAP_TK2006
06178 if (LEVELUIDPLUS (vms->mailstream)) {
06179 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06180 } else
06181 #endif
06182 mail_expunge(vms->mailstream);
06183 ast_mutex_unlock(&vms->lock);
06184 }
06185 #endif
06186
06187 ast_free(tmp);
06188 return res;
06189 }
06190
06191 #if !defined(IMAP_STORAGE)
06192 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06193 {
06194
06195
06196 int x, dest;
06197 char sfn[PATH_MAX];
06198 char dfn[PATH_MAX];
06199
06200 if (vm_lock_path(dir)) {
06201 return ERROR_LOCK_PATH;
06202 }
06203
06204 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06205 make_file(sfn, sizeof(sfn), dir, x);
06206 if (EXISTS(dir, x, sfn, NULL)) {
06207
06208 if (x != dest) {
06209 make_file(dfn, sizeof(dfn), dir, dest);
06210 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06211 }
06212
06213 dest++;
06214 }
06215 }
06216 ast_unlock_path(dir);
06217
06218 return dest;
06219 }
06220 #endif
06221
06222 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06223 {
06224 int d;
06225 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06226 return d;
06227 }
06228
06229 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06230 {
06231 #ifdef IMAP_STORAGE
06232
06233
06234 char sequence[10];
06235 char mailbox[256];
06236 int res;
06237
06238
06239 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06240
06241 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06242 ast_mutex_lock(&vms->lock);
06243
06244 if (box == OLD_FOLDER) {
06245 mail_setflag(vms->mailstream, sequence, "\\Seen");
06246 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06247 } else if (box == NEW_FOLDER) {
06248 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06249 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06250 }
06251 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06252 ast_mutex_unlock(&vms->lock);
06253 return 0;
06254 }
06255
06256 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06257 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06258 if (mail_create(vms->mailstream, mailbox) == NIL)
06259 ast_debug(5, "Folder exists.\n");
06260 else
06261 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06262 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06263 ast_mutex_unlock(&vms->lock);
06264 return res;
06265 #else
06266 char *dir = vms->curdir;
06267 char *username = vms->username;
06268 char *context = vmu->context;
06269 char sfn[PATH_MAX];
06270 char dfn[PATH_MAX];
06271 char ddir[PATH_MAX];
06272 const char *dbox = mbox(vmu, box);
06273 int x, i;
06274 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06275
06276 if (vm_lock_path(ddir))
06277 return ERROR_LOCK_PATH;
06278
06279 x = last_message_index(vmu, ddir) + 1;
06280
06281 if (box == 10 && x >= vmu->maxdeletedmsg) {
06282 x--;
06283 for (i = 1; i <= x; i++) {
06284
06285 make_file(sfn, sizeof(sfn), ddir, i);
06286 make_file(dfn, sizeof(dfn), ddir, i - 1);
06287 if (EXISTS(ddir, i, sfn, NULL)) {
06288 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06289 } else
06290 break;
06291 }
06292 } else {
06293 if (x >= vmu->maxmsg) {
06294 ast_unlock_path(ddir);
06295 return -1;
06296 }
06297 }
06298 make_file(sfn, sizeof(sfn), dir, msg);
06299 make_file(dfn, sizeof(dfn), ddir, x);
06300 if (strcmp(sfn, dfn)) {
06301 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06302 }
06303 ast_unlock_path(ddir);
06304 #endif
06305 return 0;
06306 }
06307
06308 static int adsi_logo(unsigned char *buf)
06309 {
06310 int bytes = 0;
06311 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06312 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06313 return bytes;
06314 }
06315
06316 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06317 {
06318 unsigned char buf[256];
06319 int bytes = 0;
06320 int x;
06321 char num[5];
06322
06323 *useadsi = 0;
06324 bytes += ast_adsi_data_mode(buf + bytes);
06325 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06326
06327 bytes = 0;
06328 bytes += adsi_logo(buf);
06329 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06330 #ifdef DISPLAY
06331 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06332 #endif
06333 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06334 bytes += ast_adsi_data_mode(buf + bytes);
06335 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06336
06337 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06338 bytes = 0;
06339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06340 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06341 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06342 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06344 return 0;
06345 }
06346
06347 #ifdef DISPLAY
06348
06349 bytes = 0;
06350 bytes += ast_adsi_logo(buf);
06351 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06352 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06353 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06354 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06355 #endif
06356 bytes = 0;
06357 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06358 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06359 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06360 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06361 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06362 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06363 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06364
06365 #ifdef DISPLAY
06366
06367 bytes = 0;
06368 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06369 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06370
06371 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06372 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06373 #endif
06374
06375 bytes = 0;
06376
06377 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06378 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06379 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06380 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06381 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06382 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06383 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06384
06385 #ifdef DISPLAY
06386
06387 bytes = 0;
06388 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06389 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06390 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06391 #endif
06392
06393 bytes = 0;
06394 for (x = 0; x < 5; x++) {
06395 snprintf(num, sizeof(num), "%d", x);
06396 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06397 }
06398 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06399 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06400
06401 #ifdef DISPLAY
06402
06403 bytes = 0;
06404 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06405 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06406 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06407 #endif
06408
06409 if (ast_adsi_end_download(chan)) {
06410 bytes = 0;
06411 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06412 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06413 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06414 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06415 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06416 return 0;
06417 }
06418 bytes = 0;
06419 bytes += ast_adsi_download_disconnect(buf + bytes);
06420 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06421 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06422
06423 ast_debug(1, "Done downloading scripts...\n");
06424
06425 #ifdef DISPLAY
06426
06427 bytes = 0;
06428 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06429 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06430 #endif
06431 ast_debug(1, "Restarting session...\n");
06432
06433 bytes = 0;
06434
06435 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06436 *useadsi = 1;
06437 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06438 } else
06439 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06440
06441 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06442 return 0;
06443 }
06444
06445 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06446 {
06447 int x;
06448 if (!ast_adsi_available(chan))
06449 return;
06450 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06451 if (x < 0)
06452 return;
06453 if (!x) {
06454 if (adsi_load_vmail(chan, useadsi)) {
06455 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06456 return;
06457 }
06458 } else
06459 *useadsi = 1;
06460 }
06461
06462 static void adsi_login(struct ast_channel *chan)
06463 {
06464 unsigned char buf[256];
06465 int bytes = 0;
06466 unsigned char keys[8];
06467 int x;
06468 if (!ast_adsi_available(chan))
06469 return;
06470
06471 for (x = 0; x < 8; x++)
06472 keys[x] = 0;
06473
06474 keys[3] = ADSI_KEY_APPS + 3;
06475
06476 bytes += adsi_logo(buf + bytes);
06477 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06478 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06479 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06480 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06481 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06482 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06483 bytes += ast_adsi_set_keys(buf + bytes, keys);
06484 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06485 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06486 }
06487
06488 static void adsi_password(struct ast_channel *chan)
06489 {
06490 unsigned char buf[256];
06491 int bytes = 0;
06492 unsigned char keys[8];
06493 int x;
06494 if (!ast_adsi_available(chan))
06495 return;
06496
06497 for (x = 0; x < 8; x++)
06498 keys[x] = 0;
06499
06500 keys[3] = ADSI_KEY_APPS + 3;
06501
06502 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06503 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06504 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06505 bytes += ast_adsi_set_keys(buf + bytes, keys);
06506 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06507 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06508 }
06509
06510 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06511 {
06512 unsigned char buf[256];
06513 int bytes = 0;
06514 unsigned char keys[8];
06515 int x, y;
06516
06517 if (!ast_adsi_available(chan))
06518 return;
06519
06520 for (x = 0; x < 5; x++) {
06521 y = ADSI_KEY_APPS + 12 + start + x;
06522 if (y > ADSI_KEY_APPS + 12 + 4)
06523 y = 0;
06524 keys[x] = ADSI_KEY_SKT | y;
06525 }
06526 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06527 keys[6] = 0;
06528 keys[7] = 0;
06529
06530 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06531 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06532 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06533 bytes += ast_adsi_set_keys(buf + bytes, keys);
06534 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06535
06536 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06537 }
06538
06539 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06540 {
06541 int bytes = 0;
06542 unsigned char buf[256];
06543 char buf1[256], buf2[256];
06544 char fn2[PATH_MAX];
06545
06546 char cid[256] = "";
06547 char *val;
06548 char *name, *num;
06549 char datetime[21] = "";
06550 FILE *f;
06551
06552 unsigned char keys[8];
06553
06554 int x;
06555
06556 if (!ast_adsi_available(chan))
06557 return;
06558
06559
06560 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06561 f = fopen(fn2, "r");
06562 if (f) {
06563 while (!feof(f)) {
06564 if (!fgets((char *) buf, sizeof(buf), f)) {
06565 continue;
06566 }
06567 if (!feof(f)) {
06568 char *stringp = NULL;
06569 stringp = (char *) buf;
06570 strsep(&stringp, "=");
06571 val = strsep(&stringp, "=");
06572 if (!ast_strlen_zero(val)) {
06573 if (!strcmp((char *) buf, "callerid"))
06574 ast_copy_string(cid, val, sizeof(cid));
06575 if (!strcmp((char *) buf, "origdate"))
06576 ast_copy_string(datetime, val, sizeof(datetime));
06577 }
06578 }
06579 }
06580 fclose(f);
06581 }
06582
06583 for (x = 0; x < 5; x++)
06584 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06585 keys[6] = 0x0;
06586 keys[7] = 0x0;
06587
06588 if (!vms->curmsg) {
06589
06590 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06591 }
06592 if (vms->curmsg >= vms->lastmsg) {
06593
06594 if (vms->curmsg) {
06595
06596 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06597 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06598
06599 } else {
06600
06601 keys[3] = 1;
06602 }
06603 }
06604
06605 if (!ast_strlen_zero(cid)) {
06606 ast_callerid_parse(cid, &name, &num);
06607 if (!name)
06608 name = num;
06609 } else
06610 name = "Unknown Caller";
06611
06612
06613 #ifdef IMAP_STORAGE
06614 ast_mutex_lock(&vms->lock);
06615 #endif
06616 if (vms->deleted[vms->curmsg]) {
06617 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06618 }
06619 #ifdef IMAP_STORAGE
06620 ast_mutex_unlock(&vms->lock);
06621 #endif
06622
06623
06624 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06625 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06626 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06627 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06628
06629 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06630 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06631 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06632 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06633 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06634 bytes += ast_adsi_set_keys(buf + bytes, keys);
06635 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06636
06637 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06638 }
06639
06640 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06641 {
06642 int bytes = 0;
06643 unsigned char buf[256];
06644 unsigned char keys[8];
06645
06646 int x;
06647
06648 if (!ast_adsi_available(chan))
06649 return;
06650
06651
06652 for (x = 0; x < 5; x++)
06653 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06654
06655 keys[6] = 0x0;
06656 keys[7] = 0x0;
06657
06658 if (!vms->curmsg) {
06659
06660 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06661 }
06662 if (vms->curmsg >= vms->lastmsg) {
06663
06664 if (vms->curmsg) {
06665
06666 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06667 } else {
06668
06669 keys[3] = 1;
06670 }
06671 }
06672
06673
06674 #ifdef IMAP_STORAGE
06675 ast_mutex_lock(&vms->lock);
06676 #endif
06677 if (vms->deleted[vms->curmsg]) {
06678 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06679 }
06680 #ifdef IMAP_STORAGE
06681 ast_mutex_unlock(&vms->lock);
06682 #endif
06683
06684
06685 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06686 bytes += ast_adsi_set_keys(buf + bytes, keys);
06687 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06688
06689 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06690 }
06691
06692 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06693 {
06694 unsigned char buf[256] = "";
06695 char buf1[256] = "", buf2[256] = "";
06696 int bytes = 0;
06697 unsigned char keys[8];
06698 int x;
06699
06700 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06701 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06702 if (!ast_adsi_available(chan))
06703 return;
06704 if (vms->newmessages) {
06705 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06706 if (vms->oldmessages) {
06707 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06708 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06709 } else {
06710 snprintf(buf2, sizeof(buf2), "%s.", newm);
06711 }
06712 } else if (vms->oldmessages) {
06713 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06714 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06715 } else {
06716 strcpy(buf1, "You have no messages.");
06717 buf2[0] = ' ';
06718 buf2[1] = '\0';
06719 }
06720 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06721 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06722 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06723
06724 for (x = 0; x < 6; x++)
06725 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06726 keys[6] = 0;
06727 keys[7] = 0;
06728
06729
06730 if (vms->lastmsg < 0)
06731 keys[0] = 1;
06732 bytes += ast_adsi_set_keys(buf + bytes, keys);
06733
06734 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06735
06736 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06737 }
06738
06739 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06740 {
06741 unsigned char buf[256] = "";
06742 char buf1[256] = "", buf2[256] = "";
06743 int bytes = 0;
06744 unsigned char keys[8];
06745 int x;
06746
06747 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06748
06749 if (!ast_adsi_available(chan))
06750 return;
06751
06752
06753 for (x = 0; x < 6; x++)
06754 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06755
06756 keys[6] = 0;
06757 keys[7] = 0;
06758
06759 if ((vms->lastmsg + 1) < 1)
06760 keys[0] = 0;
06761
06762 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06763 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06764
06765 if (vms->lastmsg + 1)
06766 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06767 else
06768 strcpy(buf2, "no messages.");
06769 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06770 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06771 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06772 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06773 bytes += ast_adsi_set_keys(buf + bytes, keys);
06774
06775 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06776
06777 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06778
06779 }
06780
06781
06782
06783
06784
06785
06786
06787
06788
06789
06790
06791
06792
06793
06794
06795 static void adsi_goodbye(struct ast_channel *chan)
06796 {
06797 unsigned char buf[256];
06798 int bytes = 0;
06799
06800 if (!ast_adsi_available(chan))
06801 return;
06802 bytes += adsi_logo(buf + bytes);
06803 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06804 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06805 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06806 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06807
06808 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06809 }
06810
06811
06812
06813
06814
06815 static int get_folder(struct ast_channel *chan, int start)
06816 {
06817 int x;
06818 int d;
06819 char fn[PATH_MAX];
06820 d = ast_play_and_wait(chan, "vm-press");
06821 if (d)
06822 return d;
06823 for (x = start; x < 5; x++) {
06824 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06825 return d;
06826 d = ast_play_and_wait(chan, "vm-for");
06827 if (d)
06828 return d;
06829 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06830
06831
06832
06833
06834 if (x == 0) {
06835 if (ast_fileexists(fn, NULL, NULL)) {
06836 d = vm_play_folder_name(chan, fn);
06837 } else {
06838 ast_verb(1, "failed to find %s\n", fn);
06839 d = vm_play_folder_name(chan, "vm-INBOX");
06840 }
06841 } else {
06842 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06843 d = vm_play_folder_name(chan, fn);
06844 }
06845
06846 if (d)
06847 return d;
06848 d = ast_waitfordigit(chan, 500);
06849 if (d)
06850 return d;
06851 }
06852
06853 d = ast_play_and_wait(chan, "vm-tocancel");
06854 if (d)
06855 return d;
06856 d = ast_waitfordigit(chan, 4000);
06857 return d;
06858 }
06859
06860
06861
06862
06863
06864
06865
06866
06867
06868
06869
06870
06871
06872 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06873 {
06874 int res = 0;
06875 int loops = 0;
06876
06877 res = ast_play_and_wait(chan, fn);
06878 while (((res < '0') || (res > '9')) &&
06879 (res != '#') && (res >= 0) &&
06880 loops < 4) {
06881 res = get_folder(chan, 0);
06882 loops++;
06883 }
06884 if (loops == 4) {
06885 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06886 return '#';
06887 }
06888 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06889 return res;
06890 }
06891
06892
06893
06894
06895
06896
06897
06898
06899
06900
06901
06902
06903
06904
06905
06906
06907
06908
06909
06910 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06911 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06912 {
06913 int cmd = 0;
06914 int retries = 0, prepend_duration = 0, already_recorded = 0;
06915 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06916 char textfile[PATH_MAX];
06917 struct ast_config *msg_cfg;
06918 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06919 #ifndef IMAP_STORAGE
06920 signed char zero_gain = 0;
06921 #endif
06922 const char *duration_str;
06923
06924
06925 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06926 strcpy(textfile, msgfile);
06927 strcpy(backup, msgfile);
06928 strcpy(backup_textfile, msgfile);
06929 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06930 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06931 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06932
06933 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06934 *duration = atoi(duration_str);
06935 } else {
06936 *duration = 0;
06937 }
06938
06939 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06940 if (cmd)
06941 retries = 0;
06942 switch (cmd) {
06943 case '1':
06944
06945 #ifdef IMAP_STORAGE
06946
06947 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06948 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06949 ast_play_and_wait(chan, INTRO);
06950 ast_play_and_wait(chan, "beep");
06951 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06952 if (cmd == -1) {
06953 break;
06954 }
06955 cmd = 't';
06956 #else
06957
06958
06959
06960 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06961 strcpy(textfile, msgfile);
06962 strncat(textfile, ".txt", sizeof(textfile) - 1);
06963 *duration = 0;
06964
06965
06966 if (!valid_config(msg_cfg)) {
06967 cmd = 0;
06968 break;
06969 }
06970
06971
06972 #ifndef IMAP_STORAGE
06973 if (already_recorded) {
06974 ast_filecopy(backup, msgfile, NULL);
06975 copy(backup_textfile, textfile);
06976 }
06977 else {
06978 ast_filecopy(msgfile, backup, NULL);
06979 copy(textfile, backup_textfile);
06980 }
06981 #endif
06982 already_recorded = 1;
06983
06984 if (record_gain)
06985 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06986
06987 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06988
06989 if (cmd == 'S') {
06990 ast_stream_and_wait(chan, vm_pls_try_again, "");
06991 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06992 ast_filerename(backup, msgfile, NULL);
06993 }
06994
06995 if (record_gain)
06996 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06997
06998
06999 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
07000 *duration = atoi(duration_str);
07001
07002 if (prepend_duration) {
07003 struct ast_category *msg_cat;
07004
07005 char duration_buf[12];
07006
07007 *duration += prepend_duration;
07008 msg_cat = ast_category_get(msg_cfg, "message");
07009 snprintf(duration_buf, 11, "%ld", *duration);
07010 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
07011 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
07012 }
07013 }
07014
07015 #endif
07016 break;
07017 case '2':
07018
07019 #ifdef IMAP_STORAGE
07020 *vms->introfn = '\0';
07021 #endif
07022 cmd = 't';
07023 break;
07024 case '*':
07025 cmd = '*';
07026 break;
07027 default:
07028
07029 already_recorded = 0;
07030
07031 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07032
07033 if (!cmd) {
07034 cmd = ast_play_and_wait(chan, "vm-starmain");
07035
07036 }
07037 if (!cmd) {
07038 cmd = ast_waitfordigit(chan, 6000);
07039 }
07040 if (!cmd) {
07041 retries++;
07042 }
07043 if (retries > 3) {
07044 cmd = '*';
07045 }
07046 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07047 }
07048 }
07049
07050 if (valid_config(msg_cfg))
07051 ast_config_destroy(msg_cfg);
07052 if (prepend_duration)
07053 *duration = prepend_duration;
07054
07055 if (already_recorded && cmd == -1) {
07056
07057 ast_filerename(backup, msgfile, NULL);
07058 rename(backup_textfile, textfile);
07059 }
07060
07061 if (cmd == 't' || cmd == 'S')
07062 cmd = 0;
07063 return cmd;
07064 }
07065
07066 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07067 {
07068 struct ast_event *event;
07069 char *mailbox, *context;
07070
07071
07072 context = mailbox = ast_strdupa(box);
07073 strsep(&context, "@");
07074 if (ast_strlen_zero(context))
07075 context = "default";
07076
07077 if (!(event = ast_event_new(AST_EVENT_MWI,
07078 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07079 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07080 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07081 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07082 AST_EVENT_IE_END))) {
07083 return;
07084 }
07085
07086 ast_event_queue_and_cache(event);
07087 }
07088
07089
07090
07091
07092
07093
07094
07095
07096
07097
07098
07099
07100
07101
07102
07103 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)
07104 {
07105 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07106 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07107 const char *category;
07108 char *myserveremail = serveremail;
07109
07110 ast_channel_lock(chan);
07111 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07112 category = ast_strdupa(category);
07113 }
07114 ast_channel_unlock(chan);
07115
07116 #ifndef IMAP_STORAGE
07117 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07118 #else
07119 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07120 #endif
07121 make_file(fn, sizeof(fn), todir, msgnum);
07122 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07123
07124 if (!ast_strlen_zero(vmu->attachfmt)) {
07125 if (strstr(fmt, vmu->attachfmt))
07126 fmt = vmu->attachfmt;
07127 else
07128 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);
07129 }
07130
07131
07132 fmt = ast_strdupa(fmt);
07133 stringp = fmt;
07134 strsep(&stringp, "|");
07135
07136 if (!ast_strlen_zero(vmu->serveremail))
07137 myserveremail = vmu->serveremail;
07138
07139 if (!ast_strlen_zero(vmu->email)) {
07140 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07141
07142 if (attach_user_voicemail)
07143 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07144
07145
07146 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07147
07148 if (attach_user_voicemail)
07149 DISPOSE(todir, msgnum);
07150 }
07151
07152 if (!ast_strlen_zero(vmu->pager)) {
07153 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07154 }
07155
07156 if (ast_test_flag(vmu, VM_DELETE))
07157 DELETE(todir, msgnum, fn, vmu);
07158
07159
07160 if (ast_app_has_voicemail(ext_context, NULL))
07161 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07162
07163 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07164
07165 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);
07166 run_externnotify(vmu->context, vmu->mailbox, flag);
07167
07168 #ifdef IMAP_STORAGE
07169 vm_delete(fn);
07170 if (ast_test_flag(vmu, VM_DELETE)) {
07171 vm_imap_delete(NULL, vms->curmsg, vmu);
07172 vms->newmessages--;
07173 }
07174 #endif
07175
07176 return 0;
07177 }
07178
07179
07180
07181
07182
07183
07184
07185
07186
07187
07188
07189
07190
07191
07192
07193
07194
07195
07196
07197
07198
07199
07200
07201
07202
07203
07204
07205
07206 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)
07207 {
07208 #ifdef IMAP_STORAGE
07209 int todircount = 0;
07210 struct vm_state *dstvms;
07211 #endif
07212 char username[70]="";
07213 char fn[PATH_MAX];
07214 char ecodes[16] = "#";
07215 int res = 0, cmd = 0;
07216 struct ast_vm_user *receiver = NULL, *vmtmp;
07217 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07218 char *stringp;
07219 const char *s;
07220 int saved_messages = 0;
07221 int valid_extensions = 0;
07222 char *dir;
07223 int curmsg;
07224 char urgent_str[7] = "";
07225 int prompt_played = 0;
07226 #ifndef IMAP_STORAGE
07227 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07228 #endif
07229 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07230 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07231 }
07232
07233 if (vms == NULL) return -1;
07234 dir = vms->curdir;
07235 curmsg = vms->curmsg;
07236
07237 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07238 while (!res && !valid_extensions) {
07239 int use_directory = 0;
07240 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07241 int done = 0;
07242 int retries = 0;
07243 cmd = 0;
07244 while ((cmd >= 0) && !done ){
07245 if (cmd)
07246 retries = 0;
07247 switch (cmd) {
07248 case '1':
07249 use_directory = 0;
07250 done = 1;
07251 break;
07252 case '2':
07253 use_directory = 1;
07254 done = 1;
07255 break;
07256 case '*':
07257 cmd = 't';
07258 done = 1;
07259 break;
07260 default:
07261
07262 cmd = ast_play_and_wait(chan, "vm-forward");
07263 if (!cmd) {
07264 cmd = ast_waitfordigit(chan, 3000);
07265 }
07266 if (!cmd) {
07267 retries++;
07268 }
07269 if (retries > 3) {
07270 cmd = 't';
07271 done = 1;
07272 }
07273 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07274 }
07275 }
07276 if (cmd < 0 || cmd == 't')
07277 break;
07278 }
07279
07280 if (use_directory) {
07281
07282
07283 char old_context[sizeof(chan->context)];
07284 char old_exten[sizeof(chan->exten)];
07285 int old_priority;
07286 struct ast_app* directory_app;
07287
07288 directory_app = pbx_findapp("Directory");
07289 if (directory_app) {
07290 char vmcontext[256];
07291
07292 memcpy(old_context, chan->context, sizeof(chan->context));
07293 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07294 old_priority = chan->priority;
07295
07296
07297 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07298 res = pbx_exec(chan, directory_app, vmcontext);
07299
07300 ast_copy_string(username, chan->exten, sizeof(username));
07301
07302
07303 memcpy(chan->context, old_context, sizeof(chan->context));
07304 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07305 chan->priority = old_priority;
07306 } else {
07307 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07308 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07309 }
07310 } else {
07311
07312 res = ast_streamfile(chan, "vm-extension", chan->language);
07313 prompt_played++;
07314 if (res || prompt_played > 4)
07315 break;
07316 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07317 break;
07318 }
07319
07320
07321 if (ast_strlen_zero(username))
07322 continue;
07323 stringp = username;
07324 s = strsep(&stringp, "*");
07325
07326 valid_extensions = 1;
07327 while (s) {
07328 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07329 int oldmsgs;
07330 int newmsgs;
07331 int capacity;
07332 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07333 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07334
07335 res = ast_play_and_wait(chan, "pbx-invalid");
07336 valid_extensions = 0;
07337 break;
07338 }
07339 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07340 if ((newmsgs + oldmsgs) >= capacity) {
07341 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07342 res = ast_play_and_wait(chan, "vm-mailboxfull");
07343 valid_extensions = 0;
07344 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07345 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07346 free_user(vmtmp);
07347 }
07348 inprocess_count(receiver->mailbox, receiver->context, -1);
07349 break;
07350 }
07351 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07352 } else {
07353
07354
07355
07356
07357
07358 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07359 free_user(receiver);
07360 }
07361 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07362
07363 res = ast_play_and_wait(chan, "pbx-invalid");
07364 valid_extensions = 0;
07365 break;
07366 }
07367
07368
07369 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07370 RETRIEVE(fn, -1, s, receiver->context);
07371 if (ast_fileexists(fn, NULL, NULL) > 0) {
07372 res = ast_stream_and_wait(chan, fn, ecodes);
07373 if (res) {
07374 DISPOSE(fn, -1);
07375 return res;
07376 }
07377 } else {
07378 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07379 }
07380 DISPOSE(fn, -1);
07381
07382 s = strsep(&stringp, "*");
07383 }
07384
07385 if (valid_extensions)
07386 break;
07387 }
07388
07389 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07390 return res;
07391 if (is_new_message == 1) {
07392 struct leave_vm_options leave_options;
07393 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07394 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07395
07396
07397 memset(&leave_options, 0, sizeof(leave_options));
07398 leave_options.record_gain = record_gain;
07399 cmd = leave_voicemail(chan, mailbox, &leave_options);
07400 } else {
07401
07402 long duration = 0;
07403 struct vm_state vmstmp;
07404 int copy_msg_result = 0;
07405 memcpy(&vmstmp, vms, sizeof(vmstmp));
07406
07407 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07408
07409 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07410 if (!cmd) {
07411 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07412 #ifdef IMAP_STORAGE
07413 int attach_user_voicemail;
07414 char *myserveremail = serveremail;
07415
07416
07417 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07418 if (!dstvms) {
07419 dstvms = create_vm_state_from_user(vmtmp);
07420 }
07421 if (dstvms) {
07422 init_mailstream(dstvms, 0);
07423 if (!dstvms->mailstream) {
07424 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07425 } else {
07426 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07427 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07428 }
07429 } else {
07430 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07431 }
07432 if (!ast_strlen_zero(vmtmp->serveremail))
07433 myserveremail = vmtmp->serveremail;
07434 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07435
07436 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07437 dstvms->curbox,
07438 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07439 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07440 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07441 NULL, urgent_str);
07442 #else
07443 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07444 #endif
07445 saved_messages++;
07446 AST_LIST_REMOVE_CURRENT(list);
07447 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07448 free_user(vmtmp);
07449 if (res)
07450 break;
07451 }
07452 AST_LIST_TRAVERSE_SAFE_END;
07453 if (saved_messages > 0 && !copy_msg_result) {
07454
07455
07456
07457
07458
07459
07460
07461
07462 #ifdef IMAP_STORAGE
07463
07464 if (ast_strlen_zero(vmstmp.introfn))
07465 #endif
07466 res = ast_play_and_wait(chan, "vm-msgsaved");
07467 }
07468 #ifndef IMAP_STORAGE
07469 else {
07470
07471 res = ast_play_and_wait(chan, "vm-mailboxfull");
07472 }
07473
07474 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07475 strcpy(textfile, msgfile);
07476 strcpy(backup, msgfile);
07477 strcpy(backup_textfile, msgfile);
07478 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07479 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07480 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07481 if (ast_fileexists(backup, NULL, NULL) > 0) {
07482 ast_filerename(backup, msgfile, NULL);
07483 rename(backup_textfile, textfile);
07484 }
07485 #endif
07486 }
07487 DISPOSE(dir, curmsg);
07488 #ifndef IMAP_STORAGE
07489 if (cmd) {
07490 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07491 strcpy(textfile, msgfile);
07492 strcpy(backup_textfile, msgfile);
07493 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07494 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07495 rename(backup_textfile, textfile);
07496 }
07497 #endif
07498 }
07499
07500
07501 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07502 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07503 free_user(vmtmp);
07504 }
07505 return res ? res : cmd;
07506 }
07507
07508 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07509 {
07510 int res;
07511 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07512 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07513 return res;
07514 }
07515
07516 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07517 {
07518 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07519 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);
07520 }
07521
07522 static int play_message_category(struct ast_channel *chan, const char *category)
07523 {
07524 int res = 0;
07525
07526 if (!ast_strlen_zero(category))
07527 res = ast_play_and_wait(chan, category);
07528
07529 if (res) {
07530 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07531 res = 0;
07532 }
07533
07534 return res;
07535 }
07536
07537 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07538 {
07539 int res = 0;
07540 struct vm_zone *the_zone = NULL;
07541 time_t t;
07542
07543 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07544 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07545 return 0;
07546 }
07547
07548
07549 if (!ast_strlen_zero(vmu->zonetag)) {
07550
07551 struct vm_zone *z;
07552 AST_LIST_LOCK(&zones);
07553 AST_LIST_TRAVERSE(&zones, z, list) {
07554 if (!strcmp(z->name, vmu->zonetag)) {
07555 the_zone = z;
07556 break;
07557 }
07558 }
07559 AST_LIST_UNLOCK(&zones);
07560 }
07561
07562
07563 #if 0
07564
07565 ast_localtime(&t, &time_now, NULL);
07566 tv_now = ast_tvnow();
07567 ast_localtime(&tv_now, &time_then, NULL);
07568
07569
07570 if (time_now.tm_year == time_then.tm_year)
07571 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07572 else
07573 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07574 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07575
07576
07577 #endif
07578 if (the_zone) {
07579 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07580 } else if (!strncasecmp(chan->language, "de", 2)) {
07581 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07582 } else if (!strncasecmp(chan->language, "gr", 2)) {
07583 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07584 } else if (!strncasecmp(chan->language, "it", 2)) {
07585 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);
07586 } else if (!strncasecmp(chan->language, "nl", 2)) {
07587 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07588 } else if (!strncasecmp(chan->language, "no", 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, "pl", 2)) {
07591 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07592 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07593 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);
07594 } else if (!strncasecmp(chan->language, "se", 2)) {
07595 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07596 } else if (!strncasecmp(chan->language, "zh", 2)) {
07597 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07598 } else if (!strncasecmp(chan->language, "vi", 2)) {
07599 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);
07600 } else {
07601 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07602 }
07603 #if 0
07604 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07605 #endif
07606 return res;
07607 }
07608
07609
07610
07611 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07612 {
07613 int res = 0;
07614 int i;
07615 char *callerid, *name;
07616 char prefile[PATH_MAX] = "";
07617
07618
07619
07620
07621
07622
07623
07624
07625
07626 if ((cid == NULL)||(context == NULL))
07627 return res;
07628
07629
07630 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07631 ast_callerid_parse(cid, &name, &callerid);
07632 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07633
07634
07635 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07636 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07637 if ((strcmp(cidinternalcontexts[i], context) == 0))
07638 break;
07639 }
07640 if (i != MAX_NUM_CID_CONTEXTS){
07641 if (!res) {
07642 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07643 if (!ast_strlen_zero(prefile)) {
07644
07645 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07646 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07647 if (!callback)
07648 res = wait_file2(chan, vms, "vm-from");
07649 res = ast_stream_and_wait(chan, prefile, "");
07650 } else {
07651 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07652
07653 if (!callback)
07654 res = wait_file2(chan, vms, "vm-from-extension");
07655 res = ast_say_digit_str(chan, callerid, "", chan->language);
07656 }
07657 }
07658 }
07659 } else if (!res) {
07660 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07661
07662 if (!callback)
07663 res = wait_file2(chan, vms, "vm-from-phonenumber");
07664 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07665 }
07666 } else {
07667
07668 ast_debug(1, "VM-CID: From an unknown number\n");
07669
07670 res = wait_file2(chan, vms, "vm-unknown-caller");
07671 }
07672 return res;
07673 }
07674
07675 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07676 {
07677 int res = 0;
07678 int durationm;
07679 int durations;
07680
07681 if (duration == NULL)
07682 return res;
07683
07684
07685 durations = atoi(duration);
07686 durationm = (durations / 60);
07687
07688 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07689
07690 if ((!res) && (durationm >= minduration)) {
07691 res = wait_file2(chan, vms, "vm-duration");
07692
07693
07694 if (!strncasecmp(chan->language, "pl", 2)) {
07695 div_t num = div(durationm, 10);
07696
07697 if (durationm == 1) {
07698 res = ast_play_and_wait(chan, "digits/1z");
07699 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07700 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07701 if (num.rem == 2) {
07702 if (!num.quot) {
07703 res = ast_play_and_wait(chan, "digits/2-ie");
07704 } else {
07705 res = say_and_wait(chan, durationm - 2 , chan->language);
07706 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07707 }
07708 } else {
07709 res = say_and_wait(chan, durationm, chan->language);
07710 }
07711 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07712 } else {
07713 res = say_and_wait(chan, durationm, chan->language);
07714 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07715 }
07716
07717 } else {
07718 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07719 res = wait_file2(chan, vms, "vm-minutes");
07720 }
07721 }
07722 return res;
07723 }
07724
07725 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07726 {
07727 int res = 0;
07728 char filename[256], *cid;
07729 const char *origtime, *context, *category, *duration, *flag;
07730 struct ast_config *msg_cfg;
07731 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07732
07733 vms->starting = 0;
07734 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07735 adsi_message(chan, vms);
07736 if (!vms->curmsg) {
07737 res = wait_file2(chan, vms, "vm-first");
07738 } else if (vms->curmsg == vms->lastmsg) {
07739 res = wait_file2(chan, vms, "vm-last");
07740 }
07741
07742 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07743 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07744 msg_cfg = ast_config_load(filename, config_flags);
07745 if (!valid_config(msg_cfg)) {
07746 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07747 return 0;
07748 }
07749 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07750
07751
07752 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07753 res = wait_file2(chan, vms, "vm-Urgent");
07754 }
07755
07756 if (!res) {
07757
07758
07759 if (!strncasecmp(chan->language, "pl", 2)) {
07760 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07761 int ten, one;
07762 char nextmsg[256];
07763 ten = (vms->curmsg + 1) / 10;
07764 one = (vms->curmsg + 1) % 10;
07765
07766 if (vms->curmsg < 20) {
07767 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07768 res = wait_file2(chan, vms, nextmsg);
07769 } else {
07770 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07771 res = wait_file2(chan, vms, nextmsg);
07772 if (one > 0) {
07773 if (!res) {
07774 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07775 res = wait_file2(chan, vms, nextmsg);
07776 }
07777 }
07778 }
07779 }
07780 if (!res)
07781 res = wait_file2(chan, vms, "vm-message");
07782
07783 } else if (!strncasecmp(chan->language, "he", 2)) {
07784 if (!vms->curmsg) {
07785 res = wait_file2(chan, vms, "vm-message");
07786 res = wait_file2(chan, vms, "vm-first");
07787 } else if (vms->curmsg == vms->lastmsg) {
07788 res = wait_file2(chan, vms, "vm-message");
07789 res = wait_file2(chan, vms, "vm-last");
07790 } else {
07791 res = wait_file2(chan, vms, "vm-message");
07792 res = wait_file2(chan, vms, "vm-number");
07793 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07794 }
07795
07796 } else if (!strncasecmp(chan->language, "vi", 2)) {
07797 if (!vms->curmsg) {
07798 res = wait_file2(chan, vms, "vm-message");
07799 res = wait_file2(chan, vms, "vm-first");
07800 } else if (vms->curmsg == vms->lastmsg) {
07801 res = wait_file2(chan, vms, "vm-message");
07802 res = wait_file2(chan, vms, "vm-last");
07803 } else {
07804 res = wait_file2(chan, vms, "vm-message");
07805 res = wait_file2(chan, vms, "vm-number");
07806 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07807 }
07808 } else {
07809 if (!strncasecmp(chan->language, "se", 2)) {
07810 res = wait_file2(chan, vms, "vm-meddelandet");
07811 } else {
07812 res = wait_file2(chan, vms, "vm-message");
07813 }
07814 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07815 if (!res) {
07816 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07817 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07818 }
07819 }
07820 }
07821 }
07822
07823 if (!valid_config(msg_cfg)) {
07824 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07825 return 0;
07826 }
07827
07828 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07829 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07830 DISPOSE(vms->curdir, vms->curmsg);
07831 ast_config_destroy(msg_cfg);
07832 return 0;
07833 }
07834
07835 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07836 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07837 category = ast_variable_retrieve(msg_cfg, "message", "category");
07838
07839 context = ast_variable_retrieve(msg_cfg, "message", "context");
07840 if (!strncasecmp("macro", context, 5))
07841 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07842 if (!res) {
07843 res = play_message_category(chan, category);
07844 }
07845 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07846 res = play_message_datetime(chan, vmu, origtime, filename);
07847 }
07848 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07849 res = play_message_callerid(chan, vms, cid, context, 0);
07850 }
07851 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07852 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07853 }
07854
07855 if (res == '1') {
07856 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07857 res = 0;
07858 }
07859 ast_config_destroy(msg_cfg);
07860
07861 if (!res) {
07862 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07863 #ifdef IMAP_STORAGE
07864 ast_mutex_lock(&vms->lock);
07865 #endif
07866 vms->heard[vms->curmsg] = 1;
07867 #ifdef IMAP_STORAGE
07868 ast_mutex_unlock(&vms->lock);
07869
07870
07871
07872 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07873 wait_file(chan, vms, vms->introfn);
07874 }
07875 #endif
07876 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07877 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07878 res = 0;
07879 }
07880 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07881 }
07882 DISPOSE(vms->curdir, vms->curmsg);
07883 return res;
07884 }
07885
07886 #ifdef IMAP_STORAGE
07887 static int imap_remove_file(char *dir, int msgnum)
07888 {
07889 char fn[PATH_MAX];
07890 char full_fn[PATH_MAX];
07891 char intro[PATH_MAX] = {0,};
07892
07893 if (msgnum > -1) {
07894 make_file(fn, sizeof(fn), dir, msgnum);
07895 snprintf(intro, sizeof(intro), "%sintro", fn);
07896 } else
07897 ast_copy_string(fn, dir, sizeof(fn));
07898
07899 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07900 ast_filedelete(fn, NULL);
07901 if (!ast_strlen_zero(intro)) {
07902 ast_filedelete(intro, NULL);
07903 }
07904 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07905 unlink(full_fn);
07906 }
07907 return 0;
07908 }
07909
07910
07911
07912 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07913 {
07914 char *file, *filename;
07915 char *attachment;
07916 char arg[10];
07917 int i;
07918 BODY* body;
07919
07920 file = strrchr(ast_strdupa(dir), '/');
07921 if (file) {
07922 *file++ = '\0';
07923 } else {
07924 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07925 return -1;
07926 }
07927
07928 ast_mutex_lock(&vms->lock);
07929 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07930 mail_fetchstructure(vms->mailstream, i + 1, &body);
07931
07932 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07933 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07934 } else {
07935 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07936 ast_mutex_unlock(&vms->lock);
07937 return -1;
07938 }
07939 filename = strsep(&attachment, ".");
07940 if (!strcmp(filename, file)) {
07941 sprintf(arg, "%d", i + 1);
07942 mail_setflag(vms->mailstream, arg, "\\DELETED");
07943 }
07944 }
07945 mail_expunge(vms->mailstream);
07946 ast_mutex_unlock(&vms->lock);
07947 return 0;
07948 }
07949
07950 #elif !defined(IMAP_STORAGE)
07951 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07952 {
07953 int count_msg, last_msg;
07954
07955 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07956
07957
07958
07959
07960 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07961
07962
07963 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07964
07965
07966 count_msg = count_messages(vmu, vms->curdir);
07967 if (count_msg < 0) {
07968 return count_msg;
07969 } else {
07970 vms->lastmsg = count_msg - 1;
07971 }
07972
07973 if (vm_allocate_dh(vms, vmu, count_msg)) {
07974 return -1;
07975 }
07976
07977
07978
07979
07980
07981
07982
07983
07984 if (vm_lock_path(vms->curdir)) {
07985 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07986 return ERROR_LOCK_PATH;
07987 }
07988
07989
07990 last_msg = last_message_index(vmu, vms->curdir);
07991 ast_unlock_path(vms->curdir);
07992
07993 if (last_msg < -1) {
07994 return last_msg;
07995 } else if (vms->lastmsg != last_msg) {
07996 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);
07997 resequence_mailbox(vmu, vms->curdir, count_msg);
07998 }
07999
08000 return 0;
08001 }
08002 #endif
08003
08004 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
08005 {
08006 int x = 0;
08007 int last_msg_idx = 0;
08008
08009 #ifndef IMAP_STORAGE
08010 int res = 0, nummsg;
08011 char fn2[PATH_MAX];
08012 #endif
08013
08014 if (vms->lastmsg <= -1) {
08015 goto done;
08016 }
08017
08018 vms->curmsg = -1;
08019 #ifndef IMAP_STORAGE
08020
08021 if (vm_lock_path(vms->curdir)) {
08022 return ERROR_LOCK_PATH;
08023 }
08024
08025
08026 last_msg_idx = last_message_index(vmu, vms->curdir);
08027 if (last_msg_idx != vms->lastmsg) {
08028 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08029 }
08030
08031
08032 for (x = 0; x < last_msg_idx + 1; x++) {
08033 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08034
08035 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08036 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08037 break;
08038 }
08039 vms->curmsg++;
08040 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08041 if (strcmp(vms->fn, fn2)) {
08042 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08043 }
08044 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08045
08046 res = save_to_folder(vmu, vms, x, 1);
08047 if (res == ERROR_LOCK_PATH) {
08048
08049 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08050 vms->deleted[x] = 0;
08051 vms->heard[x] = 0;
08052 --x;
08053 }
08054 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08055
08056 res = save_to_folder(vmu, vms, x, 10);
08057 if (res == ERROR_LOCK_PATH) {
08058
08059 vms->deleted[x] = 0;
08060 vms->heard[x] = 0;
08061 --x;
08062 }
08063 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08064
08065
08066 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08067 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08068 DELETE(vms->curdir, x, vms->fn, vmu);
08069 }
08070 }
08071 }
08072
08073
08074 nummsg = x - 1;
08075 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08076 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08077 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08078 DELETE(vms->curdir, x, vms->fn, vmu);
08079 }
08080 }
08081 ast_unlock_path(vms->curdir);
08082 #else
08083 ast_mutex_lock(&vms->lock);
08084 if (vms->deleted) {
08085
08086
08087 last_msg_idx = vms->dh_arraysize;
08088 for (x = last_msg_idx - 1; x >= 0; x--) {
08089 if (vms->deleted[x]) {
08090 ast_debug(3, "IMAP delete of %d\n", x);
08091 DELETE(vms->curdir, x, vms->fn, vmu);
08092 }
08093 }
08094 }
08095 #endif
08096
08097 done:
08098 if (vms->deleted) {
08099 ast_free(vms->deleted);
08100 vms->deleted = NULL;
08101 }
08102 if (vms->heard) {
08103 ast_free(vms->heard);
08104 vms->heard = NULL;
08105 }
08106 vms->dh_arraysize = 0;
08107 #ifdef IMAP_STORAGE
08108 ast_mutex_unlock(&vms->lock);
08109 #endif
08110
08111 return 0;
08112 }
08113
08114
08115
08116
08117
08118
08119
08120 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08121 {
08122 int cmd;
08123 char *buf;
08124
08125 buf = ast_alloca(strlen(box) + 2);
08126 strcpy(buf, box);
08127 strcat(buf, "s");
08128
08129 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08130 cmd = ast_play_and_wait(chan, buf);
08131 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08132 } else {
08133 cmd = ast_play_and_wait(chan, "vm-messages");
08134 return cmd ? cmd : ast_play_and_wait(chan, box);
08135 }
08136 }
08137
08138 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08139 {
08140 int cmd;
08141
08142 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08143 if (!strcasecmp(box, "vm-INBOX"))
08144 cmd = ast_play_and_wait(chan, "vm-new-e");
08145 else
08146 cmd = ast_play_and_wait(chan, "vm-old-e");
08147 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08148 } else {
08149 cmd = ast_play_and_wait(chan, "vm-messages");
08150 return cmd ? cmd : ast_play_and_wait(chan, box);
08151 }
08152 }
08153
08154 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08155 {
08156 int cmd;
08157
08158 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08159 cmd = ast_play_and_wait(chan, "vm-messages");
08160 return cmd ? cmd : ast_play_and_wait(chan, box);
08161 } else {
08162 cmd = ast_play_and_wait(chan, box);
08163 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08164 }
08165 }
08166
08167 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08168 {
08169 int cmd;
08170
08171 if ( !strncasecmp(chan->language, "it", 2) ||
08172 !strncasecmp(chan->language, "es", 2) ||
08173 !strncasecmp(chan->language, "pt", 2)) {
08174 cmd = ast_play_and_wait(chan, "vm-messages");
08175 return cmd ? cmd : ast_play_and_wait(chan, box);
08176 } else if (!strncasecmp(chan->language, "gr", 2)) {
08177 return vm_play_folder_name_gr(chan, box);
08178 } else if (!strncasecmp(chan->language, "he", 2)) {
08179 return ast_play_and_wait(chan, box);
08180 } else if (!strncasecmp(chan->language, "pl", 2)) {
08181 return vm_play_folder_name_pl(chan, box);
08182 } else if (!strncasecmp(chan->language, "ua", 2)) {
08183 return vm_play_folder_name_ua(chan, box);
08184 } else if (!strncasecmp(chan->language, "vi", 2)) {
08185 return ast_play_and_wait(chan, box);
08186 } else {
08187 cmd = ast_play_and_wait(chan, box);
08188 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08189 }
08190 }
08191
08192
08193
08194
08195
08196
08197
08198
08199
08200
08201
08202
08203
08204 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08205 {
08206 int res = 0;
08207
08208 if (vms->newmessages) {
08209 res = ast_play_and_wait(chan, "vm-youhave");
08210 if (!res)
08211 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08212 if (!res) {
08213 if ((vms->newmessages == 1)) {
08214 res = ast_play_and_wait(chan, "vm-INBOX");
08215 if (!res)
08216 res = ast_play_and_wait(chan, "vm-message");
08217 } else {
08218 res = ast_play_and_wait(chan, "vm-INBOXs");
08219 if (!res)
08220 res = ast_play_and_wait(chan, "vm-messages");
08221 }
08222 }
08223 } else if (vms->oldmessages){
08224 res = ast_play_and_wait(chan, "vm-youhave");
08225 if (!res)
08226 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08227 if ((vms->oldmessages == 1)){
08228 res = ast_play_and_wait(chan, "vm-Old");
08229 if (!res)
08230 res = ast_play_and_wait(chan, "vm-message");
08231 } else {
08232 res = ast_play_and_wait(chan, "vm-Olds");
08233 if (!res)
08234 res = ast_play_and_wait(chan, "vm-messages");
08235 }
08236 } else if (!vms->oldmessages && !vms->newmessages)
08237 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08238 return res;
08239 }
08240
08241
08242
08243
08244
08245
08246
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 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08299 {
08300 int res;
08301 int lastnum = 0;
08302
08303 res = ast_play_and_wait(chan, "vm-youhave");
08304
08305 if (!res && vms->newmessages) {
08306 lastnum = vms->newmessages;
08307
08308 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08309 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08310 }
08311
08312 if (!res && vms->oldmessages) {
08313 res = ast_play_and_wait(chan, "vm-and");
08314 }
08315 }
08316
08317 if (!res && vms->oldmessages) {
08318 lastnum = vms->oldmessages;
08319
08320 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08321 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08322 }
08323 }
08324
08325 if (!res) {
08326 if (lastnum == 0) {
08327 res = ast_play_and_wait(chan, "vm-no");
08328 }
08329 if (!res) {
08330 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08331 }
08332 }
08333
08334 return res;
08335 }
08336
08337
08338 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08339 {
08340 int res = 0;
08341
08342
08343 if (!res) {
08344 if ((vms->newmessages) || (vms->oldmessages)) {
08345 res = ast_play_and_wait(chan, "vm-youhave");
08346 }
08347
08348
08349
08350
08351
08352 if (vms->newmessages) {
08353 if (!res) {
08354 if (vms->newmessages == 1) {
08355 res = ast_play_and_wait(chan, "vm-INBOX1");
08356 } else {
08357 if (vms->newmessages == 2) {
08358 res = ast_play_and_wait(chan, "vm-shtei");
08359 } else {
08360 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08361 }
08362 res = ast_play_and_wait(chan, "vm-INBOX");
08363 }
08364 }
08365 if (vms->oldmessages && !res) {
08366 res = ast_play_and_wait(chan, "vm-and");
08367 if (vms->oldmessages == 1) {
08368 res = ast_play_and_wait(chan, "vm-Old1");
08369 } else {
08370 if (vms->oldmessages == 2) {
08371 res = ast_play_and_wait(chan, "vm-shtei");
08372 } else {
08373 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08374 }
08375 res = ast_play_and_wait(chan, "vm-Old");
08376 }
08377 }
08378 }
08379 if (!res && vms->oldmessages && !vms->newmessages) {
08380 if (!res) {
08381 if (vms->oldmessages == 1) {
08382 res = ast_play_and_wait(chan, "vm-Old1");
08383 } else {
08384 if (vms->oldmessages == 2) {
08385 res = ast_play_and_wait(chan, "vm-shtei");
08386 } else {
08387 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08388 }
08389 res = ast_play_and_wait(chan, "vm-Old");
08390 }
08391 }
08392 }
08393 if (!res) {
08394 if (!vms->oldmessages && !vms->newmessages) {
08395 if (!res) {
08396 res = ast_play_and_wait(chan, "vm-nomessages");
08397 }
08398 }
08399 }
08400 }
08401 return res;
08402 }
08403
08404
08405 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08406 {
08407 int res;
08408
08409
08410 res = ast_play_and_wait(chan, "vm-youhave");
08411 if (!res) {
08412 if (vms->urgentmessages) {
08413 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08414 if (!res)
08415 res = ast_play_and_wait(chan, "vm-Urgent");
08416 if ((vms->oldmessages || vms->newmessages) && !res) {
08417 res = ast_play_and_wait(chan, "vm-and");
08418 } else if (!res) {
08419 if ((vms->urgentmessages == 1))
08420 res = ast_play_and_wait(chan, "vm-message");
08421 else
08422 res = ast_play_and_wait(chan, "vm-messages");
08423 }
08424 }
08425 if (vms->newmessages) {
08426 res = say_and_wait(chan, vms->newmessages, chan->language);
08427 if (!res)
08428 res = ast_play_and_wait(chan, "vm-INBOX");
08429 if (vms->oldmessages && !res)
08430 res = ast_play_and_wait(chan, "vm-and");
08431 else if (!res) {
08432 if ((vms->newmessages == 1))
08433 res = ast_play_and_wait(chan, "vm-message");
08434 else
08435 res = ast_play_and_wait(chan, "vm-messages");
08436 }
08437
08438 }
08439 if (!res && vms->oldmessages) {
08440 res = say_and_wait(chan, vms->oldmessages, chan->language);
08441 if (!res)
08442 res = ast_play_and_wait(chan, "vm-Old");
08443 if (!res) {
08444 if (vms->oldmessages == 1)
08445 res = ast_play_and_wait(chan, "vm-message");
08446 else
08447 res = ast_play_and_wait(chan, "vm-messages");
08448 }
08449 }
08450 if (!res) {
08451 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08452 res = ast_play_and_wait(chan, "vm-no");
08453 if (!res)
08454 res = ast_play_and_wait(chan, "vm-messages");
08455 }
08456 }
08457 }
08458 return res;
08459 }
08460
08461
08462 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08463 {
08464
08465 int res;
08466 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08467 res = ast_play_and_wait(chan, "vm-no") ||
08468 ast_play_and_wait(chan, "vm-message");
08469 else
08470 res = ast_play_and_wait(chan, "vm-youhave");
08471 if (!res && vms->newmessages) {
08472 res = (vms->newmessages == 1) ?
08473 ast_play_and_wait(chan, "digits/un") ||
08474 ast_play_and_wait(chan, "vm-nuovo") ||
08475 ast_play_and_wait(chan, "vm-message") :
08476
08477 say_and_wait(chan, vms->newmessages, chan->language) ||
08478 ast_play_and_wait(chan, "vm-nuovi") ||
08479 ast_play_and_wait(chan, "vm-messages");
08480 if (!res && vms->oldmessages)
08481 res = ast_play_and_wait(chan, "vm-and");
08482 }
08483 if (!res && vms->oldmessages) {
08484 res = (vms->oldmessages == 1) ?
08485 ast_play_and_wait(chan, "digits/un") ||
08486 ast_play_and_wait(chan, "vm-vecchio") ||
08487 ast_play_and_wait(chan, "vm-message") :
08488
08489 say_and_wait(chan, vms->oldmessages, chan->language) ||
08490 ast_play_and_wait(chan, "vm-vecchi") ||
08491 ast_play_and_wait(chan, "vm-messages");
08492 }
08493 return res;
08494 }
08495
08496
08497 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08498 {
08499
08500 int res;
08501 div_t num;
08502
08503 if (!vms->oldmessages && !vms->newmessages) {
08504 res = ast_play_and_wait(chan, "vm-no");
08505 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08506 return res;
08507 } else {
08508 res = ast_play_and_wait(chan, "vm-youhave");
08509 }
08510
08511 if (vms->newmessages) {
08512 num = div(vms->newmessages, 10);
08513 if (vms->newmessages == 1) {
08514 res = ast_play_and_wait(chan, "digits/1-a");
08515 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08516 res = res ? res : ast_play_and_wait(chan, "vm-message");
08517 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08518 if (num.rem == 2) {
08519 if (!num.quot) {
08520 res = ast_play_and_wait(chan, "digits/2-ie");
08521 } else {
08522 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08523 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08524 }
08525 } else {
08526 res = say_and_wait(chan, vms->newmessages, chan->language);
08527 }
08528 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08529 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08530 } else {
08531 res = say_and_wait(chan, vms->newmessages, chan->language);
08532 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08533 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08534 }
08535 if (!res && vms->oldmessages)
08536 res = ast_play_and_wait(chan, "vm-and");
08537 }
08538 if (!res && vms->oldmessages) {
08539 num = div(vms->oldmessages, 10);
08540 if (vms->oldmessages == 1) {
08541 res = ast_play_and_wait(chan, "digits/1-a");
08542 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08543 res = res ? res : ast_play_and_wait(chan, "vm-message");
08544 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08545 if (num.rem == 2) {
08546 if (!num.quot) {
08547 res = ast_play_and_wait(chan, "digits/2-ie");
08548 } else {
08549 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08550 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08551 }
08552 } else {
08553 res = say_and_wait(chan, vms->oldmessages, chan->language);
08554 }
08555 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08556 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08557 } else {
08558 res = say_and_wait(chan, vms->oldmessages, chan->language);
08559 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08560 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08561 }
08562 }
08563
08564 return res;
08565 }
08566
08567
08568 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08569 {
08570
08571 int res;
08572
08573 res = ast_play_and_wait(chan, "vm-youhave");
08574 if (res)
08575 return res;
08576
08577 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08578 res = ast_play_and_wait(chan, "vm-no");
08579 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08580 return res;
08581 }
08582
08583 if (vms->newmessages) {
08584 if ((vms->newmessages == 1)) {
08585 res = ast_play_and_wait(chan, "digits/ett");
08586 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08587 res = res ? res : ast_play_and_wait(chan, "vm-message");
08588 } else {
08589 res = say_and_wait(chan, vms->newmessages, chan->language);
08590 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08591 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08592 }
08593 if (!res && vms->oldmessages)
08594 res = ast_play_and_wait(chan, "vm-and");
08595 }
08596 if (!res && vms->oldmessages) {
08597 if (vms->oldmessages == 1) {
08598 res = ast_play_and_wait(chan, "digits/ett");
08599 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08600 res = res ? res : ast_play_and_wait(chan, "vm-message");
08601 } else {
08602 res = say_and_wait(chan, vms->oldmessages, chan->language);
08603 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08604 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08605 }
08606 }
08607
08608 return res;
08609 }
08610
08611
08612 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08613 {
08614
08615 int res;
08616
08617 res = ast_play_and_wait(chan, "vm-youhave");
08618 if (res)
08619 return res;
08620
08621 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08622 res = ast_play_and_wait(chan, "vm-no");
08623 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08624 return res;
08625 }
08626
08627 if (vms->newmessages) {
08628 if ((vms->newmessages == 1)) {
08629 res = ast_play_and_wait(chan, "digits/1");
08630 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08631 res = res ? res : ast_play_and_wait(chan, "vm-message");
08632 } else {
08633 res = say_and_wait(chan, vms->newmessages, chan->language);
08634 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08635 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08636 }
08637 if (!res && vms->oldmessages)
08638 res = ast_play_and_wait(chan, "vm-and");
08639 }
08640 if (!res && vms->oldmessages) {
08641 if (vms->oldmessages == 1) {
08642 res = ast_play_and_wait(chan, "digits/1");
08643 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08644 res = res ? res : ast_play_and_wait(chan, "vm-message");
08645 } else {
08646 res = say_and_wait(chan, vms->oldmessages, chan->language);
08647 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08648 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08649 }
08650 }
08651
08652 return res;
08653 }
08654
08655
08656 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08657 {
08658
08659 int res;
08660 res = ast_play_and_wait(chan, "vm-youhave");
08661 if (!res) {
08662 if (vms->newmessages) {
08663 if ((vms->newmessages == 1))
08664 res = ast_play_and_wait(chan, "digits/1F");
08665 else
08666 res = say_and_wait(chan, vms->newmessages, chan->language);
08667 if (!res)
08668 res = ast_play_and_wait(chan, "vm-INBOX");
08669 if (vms->oldmessages && !res)
08670 res = ast_play_and_wait(chan, "vm-and");
08671 else if (!res) {
08672 if ((vms->newmessages == 1))
08673 res = ast_play_and_wait(chan, "vm-message");
08674 else
08675 res = ast_play_and_wait(chan, "vm-messages");
08676 }
08677
08678 }
08679 if (!res && vms->oldmessages) {
08680 if (vms->oldmessages == 1)
08681 res = ast_play_and_wait(chan, "digits/1F");
08682 else
08683 res = say_and_wait(chan, vms->oldmessages, chan->language);
08684 if (!res)
08685 res = ast_play_and_wait(chan, "vm-Old");
08686 if (!res) {
08687 if (vms->oldmessages == 1)
08688 res = ast_play_and_wait(chan, "vm-message");
08689 else
08690 res = ast_play_and_wait(chan, "vm-messages");
08691 }
08692 }
08693 if (!res) {
08694 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08695 res = ast_play_and_wait(chan, "vm-no");
08696 if (!res)
08697 res = ast_play_and_wait(chan, "vm-messages");
08698 }
08699 }
08700 }
08701 return res;
08702 }
08703
08704
08705 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08706 {
08707
08708 int res;
08709 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08710 res = ast_play_and_wait(chan, "vm-youhaveno");
08711 if (!res)
08712 res = ast_play_and_wait(chan, "vm-messages");
08713 } else {
08714 res = ast_play_and_wait(chan, "vm-youhave");
08715 }
08716 if (!res) {
08717 if (vms->newmessages) {
08718 if (!res) {
08719 if ((vms->newmessages == 1)) {
08720 res = ast_play_and_wait(chan, "digits/1M");
08721 if (!res)
08722 res = ast_play_and_wait(chan, "vm-message");
08723 if (!res)
08724 res = ast_play_and_wait(chan, "vm-INBOXs");
08725 } else {
08726 res = say_and_wait(chan, vms->newmessages, chan->language);
08727 if (!res)
08728 res = ast_play_and_wait(chan, "vm-messages");
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-INBOX");
08731 }
08732 }
08733 if (vms->oldmessages && !res)
08734 res = ast_play_and_wait(chan, "vm-and");
08735 }
08736 if (vms->oldmessages) {
08737 if (!res) {
08738 if (vms->oldmessages == 1) {
08739 res = ast_play_and_wait(chan, "digits/1M");
08740 if (!res)
08741 res = ast_play_and_wait(chan, "vm-message");
08742 if (!res)
08743 res = ast_play_and_wait(chan, "vm-Olds");
08744 } else {
08745 res = say_and_wait(chan, vms->oldmessages, chan->language);
08746 if (!res)
08747 res = ast_play_and_wait(chan, "vm-messages");
08748 if (!res)
08749 res = ast_play_and_wait(chan, "vm-Old");
08750 }
08751 }
08752 }
08753 }
08754 return res;
08755 }
08756
08757
08758 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08759
08760 int res;
08761 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08762 res = ast_play_and_wait(chan, "vm-nomessages");
08763 return res;
08764 } else {
08765 res = ast_play_and_wait(chan, "vm-youhave");
08766 }
08767 if (vms->newmessages) {
08768 if (!res)
08769 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08770 if ((vms->newmessages == 1)) {
08771 if (!res)
08772 res = ast_play_and_wait(chan, "vm-message");
08773 if (!res)
08774 res = ast_play_and_wait(chan, "vm-INBOXs");
08775 } else {
08776 if (!res)
08777 res = ast_play_and_wait(chan, "vm-messages");
08778 if (!res)
08779 res = ast_play_and_wait(chan, "vm-INBOX");
08780 }
08781 if (vms->oldmessages && !res)
08782 res = ast_play_and_wait(chan, "vm-and");
08783 }
08784 if (vms->oldmessages) {
08785 if (!res)
08786 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08787 if (vms->oldmessages == 1) {
08788 if (!res)
08789 res = ast_play_and_wait(chan, "vm-message");
08790 if (!res)
08791 res = ast_play_and_wait(chan, "vm-Olds");
08792 } else {
08793 if (!res)
08794 res = ast_play_and_wait(chan, "vm-messages");
08795 if (!res)
08796 res = ast_play_and_wait(chan, "vm-Old");
08797 }
08798 }
08799 return res;
08800 }
08801
08802
08803 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08804 {
08805
08806 int res;
08807 res = ast_play_and_wait(chan, "vm-youhave");
08808 if (!res) {
08809 if (vms->newmessages) {
08810 res = say_and_wait(chan, vms->newmessages, chan->language);
08811 if (!res)
08812 res = ast_play_and_wait(chan, "vm-INBOX");
08813 if (vms->oldmessages && !res)
08814 res = ast_play_and_wait(chan, "vm-and");
08815 else if (!res) {
08816 if ((vms->newmessages == 1))
08817 res = ast_play_and_wait(chan, "vm-message");
08818 else
08819 res = ast_play_and_wait(chan, "vm-messages");
08820 }
08821
08822 }
08823 if (!res && vms->oldmessages) {
08824 res = say_and_wait(chan, vms->oldmessages, chan->language);
08825 if (!res)
08826 res = ast_play_and_wait(chan, "vm-Old");
08827 if (!res) {
08828 if (vms->oldmessages == 1)
08829 res = ast_play_and_wait(chan, "vm-message");
08830 else
08831 res = ast_play_and_wait(chan, "vm-messages");
08832 }
08833 }
08834 if (!res) {
08835 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08836 res = ast_play_and_wait(chan, "vm-no");
08837 if (!res)
08838 res = ast_play_and_wait(chan, "vm-messages");
08839 }
08840 }
08841 }
08842 return res;
08843 }
08844
08845
08846 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08847 {
08848
08849 int res;
08850 res = ast_play_and_wait(chan, "vm-youhave");
08851 if (!res) {
08852 if (vms->newmessages) {
08853 res = say_and_wait(chan, vms->newmessages, chan->language);
08854 if (!res) {
08855 if (vms->newmessages == 1)
08856 res = ast_play_and_wait(chan, "vm-INBOXs");
08857 else
08858 res = ast_play_and_wait(chan, "vm-INBOX");
08859 }
08860 if (vms->oldmessages && !res)
08861 res = ast_play_and_wait(chan, "vm-and");
08862 else if (!res) {
08863 if ((vms->newmessages == 1))
08864 res = ast_play_and_wait(chan, "vm-message");
08865 else
08866 res = ast_play_and_wait(chan, "vm-messages");
08867 }
08868
08869 }
08870 if (!res && vms->oldmessages) {
08871 res = say_and_wait(chan, vms->oldmessages, chan->language);
08872 if (!res) {
08873 if (vms->oldmessages == 1)
08874 res = ast_play_and_wait(chan, "vm-Olds");
08875 else
08876 res = ast_play_and_wait(chan, "vm-Old");
08877 }
08878 if (!res) {
08879 if (vms->oldmessages == 1)
08880 res = ast_play_and_wait(chan, "vm-message");
08881 else
08882 res = ast_play_and_wait(chan, "vm-messages");
08883 }
08884 }
08885 if (!res) {
08886 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08887 res = ast_play_and_wait(chan, "vm-no");
08888 if (!res)
08889 res = ast_play_and_wait(chan, "vm-messages");
08890 }
08891 }
08892 }
08893 return res;
08894 }
08895
08896
08897 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08898 {
08899
08900 int res;
08901 res = ast_play_and_wait(chan, "vm-youhave");
08902 if (!res) {
08903 if (vms->newmessages) {
08904 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08905 if (!res) {
08906 if ((vms->newmessages == 1)) {
08907 res = ast_play_and_wait(chan, "vm-message");
08908 if (!res)
08909 res = ast_play_and_wait(chan, "vm-INBOXs");
08910 } else {
08911 res = ast_play_and_wait(chan, "vm-messages");
08912 if (!res)
08913 res = ast_play_and_wait(chan, "vm-INBOX");
08914 }
08915 }
08916 if (vms->oldmessages && !res)
08917 res = ast_play_and_wait(chan, "vm-and");
08918 }
08919 if (!res && vms->oldmessages) {
08920 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08921 if (!res) {
08922 if (vms->oldmessages == 1) {
08923 res = ast_play_and_wait(chan, "vm-message");
08924 if (!res)
08925 res = ast_play_and_wait(chan, "vm-Olds");
08926 } else {
08927 res = ast_play_and_wait(chan, "vm-messages");
08928 if (!res)
08929 res = ast_play_and_wait(chan, "vm-Old");
08930 }
08931 }
08932 }
08933 if (!res) {
08934 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08935 res = ast_play_and_wait(chan, "vm-no");
08936 if (!res)
08937 res = ast_play_and_wait(chan, "vm-messages");
08938 }
08939 }
08940 }
08941 return res;
08942 }
08943
08944
08945
08946
08947
08948
08949
08950
08951
08952
08953
08954
08955
08956
08957
08958
08959
08960 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08961 {
08962 int res;
08963 res = ast_play_and_wait(chan, "vm-youhave");
08964 if (!res) {
08965 if (vms->newmessages) {
08966 if (vms->newmessages == 1) {
08967 res = ast_play_and_wait(chan, "digits/jednu");
08968 } else {
08969 res = say_and_wait(chan, vms->newmessages, chan->language);
08970 }
08971 if (!res) {
08972 if ((vms->newmessages == 1))
08973 res = ast_play_and_wait(chan, "vm-novou");
08974 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08975 res = ast_play_and_wait(chan, "vm-nove");
08976 if (vms->newmessages > 4)
08977 res = ast_play_and_wait(chan, "vm-novych");
08978 }
08979 if (vms->oldmessages && !res)
08980 res = ast_play_and_wait(chan, "vm-and");
08981 else if (!res) {
08982 if ((vms->newmessages == 1))
08983 res = ast_play_and_wait(chan, "vm-zpravu");
08984 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08985 res = ast_play_and_wait(chan, "vm-zpravy");
08986 if (vms->newmessages > 4)
08987 res = ast_play_and_wait(chan, "vm-zprav");
08988 }
08989 }
08990 if (!res && vms->oldmessages) {
08991 res = say_and_wait(chan, vms->oldmessages, chan->language);
08992 if (!res) {
08993 if ((vms->oldmessages == 1))
08994 res = ast_play_and_wait(chan, "vm-starou");
08995 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08996 res = ast_play_and_wait(chan, "vm-stare");
08997 if (vms->oldmessages > 4)
08998 res = ast_play_and_wait(chan, "vm-starych");
08999 }
09000 if (!res) {
09001 if ((vms->oldmessages == 1))
09002 res = ast_play_and_wait(chan, "vm-zpravu");
09003 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09004 res = ast_play_and_wait(chan, "vm-zpravy");
09005 if (vms->oldmessages > 4)
09006 res = ast_play_and_wait(chan, "vm-zprav");
09007 }
09008 }
09009 if (!res) {
09010 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09011 res = ast_play_and_wait(chan, "vm-no");
09012 if (!res)
09013 res = ast_play_and_wait(chan, "vm-zpravy");
09014 }
09015 }
09016 }
09017 return res;
09018 }
09019
09020
09021 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09022 {
09023 int res;
09024
09025 res = ast_play_and_wait(chan, "vm-you");
09026
09027 if (!res && vms->newmessages) {
09028 res = ast_play_and_wait(chan, "vm-have");
09029 if (!res)
09030 res = say_and_wait(chan, vms->newmessages, chan->language);
09031 if (!res)
09032 res = ast_play_and_wait(chan, "vm-tong");
09033 if (!res)
09034 res = ast_play_and_wait(chan, "vm-INBOX");
09035 if (vms->oldmessages && !res)
09036 res = ast_play_and_wait(chan, "vm-and");
09037 else if (!res)
09038 res = ast_play_and_wait(chan, "vm-messages");
09039 }
09040 if (!res && vms->oldmessages) {
09041 res = ast_play_and_wait(chan, "vm-have");
09042 if (!res)
09043 res = say_and_wait(chan, vms->oldmessages, chan->language);
09044 if (!res)
09045 res = ast_play_and_wait(chan, "vm-tong");
09046 if (!res)
09047 res = ast_play_and_wait(chan, "vm-Old");
09048 if (!res)
09049 res = ast_play_and_wait(chan, "vm-messages");
09050 }
09051 if (!res && !vms->oldmessages && !vms->newmessages) {
09052 res = ast_play_and_wait(chan, "vm-haveno");
09053 if (!res)
09054 res = ast_play_and_wait(chan, "vm-messages");
09055 }
09056 return res;
09057 }
09058
09059
09060 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09061 {
09062 int res;
09063
09064
09065 res = ast_play_and_wait(chan, "vm-youhave");
09066 if (!res) {
09067 if (vms->newmessages) {
09068 res = say_and_wait(chan, vms->newmessages, chan->language);
09069 if (!res)
09070 res = ast_play_and_wait(chan, "vm-INBOX");
09071 if (vms->oldmessages && !res)
09072 res = ast_play_and_wait(chan, "vm-and");
09073 }
09074 if (!res && vms->oldmessages) {
09075 res = say_and_wait(chan, vms->oldmessages, chan->language);
09076 if (!res)
09077 res = ast_play_and_wait(chan, "vm-Old");
09078 }
09079 if (!res) {
09080 if (!vms->oldmessages && !vms->newmessages) {
09081 res = ast_play_and_wait(chan, "vm-no");
09082 if (!res)
09083 res = ast_play_and_wait(chan, "vm-message");
09084 }
09085 }
09086 }
09087 return res;
09088 }
09089
09090 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09091 {
09092 char prefile[256];
09093
09094
09095 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09096 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09097 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09098 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09099 ast_play_and_wait(chan, "vm-tempgreetactive");
09100 }
09101 DISPOSE(prefile, -1);
09102 }
09103
09104
09105 if (0) {
09106 return 0;
09107 } else if (!strncasecmp(chan->language, "cs", 2)) {
09108 return vm_intro_cs(chan, vms);
09109 } else if (!strncasecmp(chan->language, "cz", 2)) {
09110 static int deprecation_warning = 0;
09111 if (deprecation_warning++ % 10 == 0) {
09112 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09113 }
09114 return vm_intro_cs(chan, vms);
09115 } else if (!strncasecmp(chan->language, "de", 2)) {
09116 return vm_intro_de(chan, vms);
09117 } else if (!strncasecmp(chan->language, "es", 2)) {
09118 return vm_intro_es(chan, vms);
09119 } else if (!strncasecmp(chan->language, "fr", 2)) {
09120 return vm_intro_fr(chan, vms);
09121 } else if (!strncasecmp(chan->language, "gr", 2)) {
09122 return vm_intro_gr(chan, vms);
09123 } else if (!strncasecmp(chan->language, "he", 2)) {
09124 return vm_intro_he(chan, vms);
09125 } else if (!strncasecmp(chan->language, "it", 2)) {
09126 return vm_intro_it(chan, vms);
09127 } else if (!strncasecmp(chan->language, "nl", 2)) {
09128 return vm_intro_nl(chan, vms);
09129 } else if (!strncasecmp(chan->language, "no", 2)) {
09130 return vm_intro_no(chan, vms);
09131 } else if (!strncasecmp(chan->language, "pl", 2)) {
09132 return vm_intro_pl(chan, vms);
09133 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09134 return vm_intro_pt_BR(chan, vms);
09135 } else if (!strncasecmp(chan->language, "pt", 2)) {
09136 return vm_intro_pt(chan, vms);
09137 } else if (!strncasecmp(chan->language, "ru", 2)) {
09138 return vm_intro_multilang(chan, vms, "n");
09139 } else if (!strncasecmp(chan->language, "se", 2)) {
09140 return vm_intro_se(chan, vms);
09141 } else if (!strncasecmp(chan->language, "ua", 2)) {
09142 return vm_intro_multilang(chan, vms, "n");
09143 } else if (!strncasecmp(chan->language, "vi", 2)) {
09144 return vm_intro_vi(chan, vms);
09145 } else if (!strncasecmp(chan->language, "zh", 2)) {
09146 return vm_intro_zh(chan, vms);
09147 } else {
09148 return vm_intro_en(chan, vms);
09149 }
09150 }
09151
09152 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09153 {
09154 int res = 0;
09155
09156 while (!res) {
09157 if (vms->starting) {
09158 if (vms->lastmsg > -1) {
09159 if (skipadvanced)
09160 res = ast_play_and_wait(chan, "vm-onefor-full");
09161 else
09162 res = ast_play_and_wait(chan, "vm-onefor");
09163 if (!res)
09164 res = vm_play_folder_name(chan, vms->vmbox);
09165 }
09166 if (!res) {
09167 if (skipadvanced)
09168 res = ast_play_and_wait(chan, "vm-opts-full");
09169 else
09170 res = ast_play_and_wait(chan, "vm-opts");
09171 }
09172 } else {
09173
09174 if (skipadvanced) {
09175 res = ast_play_and_wait(chan, "vm-onefor-full");
09176 if (!res)
09177 res = vm_play_folder_name(chan, vms->vmbox);
09178 res = ast_play_and_wait(chan, "vm-opts-full");
09179 }
09180
09181
09182
09183
09184
09185
09186 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09187 res = ast_play_and_wait(chan, "vm-prev");
09188 }
09189 if (!res && !skipadvanced)
09190 res = ast_play_and_wait(chan, "vm-advopts");
09191 if (!res)
09192 res = ast_play_and_wait(chan, "vm-repeat");
09193
09194
09195
09196
09197
09198
09199 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09200 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09201 res = ast_play_and_wait(chan, "vm-next");
09202 }
09203 if (!res) {
09204 int curmsg_deleted;
09205 #ifdef IMAP_STORAGE
09206 ast_mutex_lock(&vms->lock);
09207 #endif
09208 curmsg_deleted = vms->deleted[vms->curmsg];
09209 #ifdef IMAP_STORAGE
09210 ast_mutex_unlock(&vms->lock);
09211 #endif
09212 if (!curmsg_deleted) {
09213 res = ast_play_and_wait(chan, "vm-delete");
09214 } else {
09215 res = ast_play_and_wait(chan, "vm-undelete");
09216 }
09217 if (!res) {
09218 res = ast_play_and_wait(chan, "vm-toforward");
09219 }
09220 if (!res) {
09221 res = ast_play_and_wait(chan, "vm-savemessage");
09222 }
09223 }
09224 }
09225 if (!res) {
09226 res = ast_play_and_wait(chan, "vm-helpexit");
09227 }
09228 if (!res)
09229 res = ast_waitfordigit(chan, 6000);
09230 if (!res) {
09231 vms->repeats++;
09232 if (vms->repeats > 2) {
09233 res = 't';
09234 }
09235 }
09236 }
09237 return res;
09238 }
09239
09240 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09241 {
09242 int res = 0;
09243
09244 while (!res) {
09245 if (vms->lastmsg > -1) {
09246 res = ast_play_and_wait(chan, "vm-listen");
09247 if (!res)
09248 res = vm_play_folder_name(chan, vms->vmbox);
09249 if (!res)
09250 res = ast_play_and_wait(chan, "press");
09251 if (!res)
09252 res = ast_play_and_wait(chan, "digits/1");
09253 }
09254 if (!res)
09255 res = ast_play_and_wait(chan, "vm-opts");
09256 if (!res) {
09257 vms->starting = 0;
09258 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09259 }
09260 }
09261 return res;
09262 }
09263
09264 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09265 {
09266 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09267 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09268 } else {
09269 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09270 }
09271 }
09272
09273
09274 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09275 {
09276 int cmd = 0;
09277 int duration = 0;
09278 int tries = 0;
09279 char newpassword[80] = "";
09280 char newpassword2[80] = "";
09281 char prefile[PATH_MAX] = "";
09282 unsigned char buf[256];
09283 int bytes = 0;
09284
09285 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09286 if (ast_adsi_available(chan)) {
09287 bytes += adsi_logo(buf + bytes);
09288 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09289 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09290 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09291 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09292 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09293 }
09294
09295
09296 if (ast_test_flag(vmu, VM_FORCENAME)) {
09297 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09298 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09299 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09300 if (cmd < 0 || cmd == 't' || cmd == '#')
09301 return cmd;
09302 }
09303 }
09304
09305
09306 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09307 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09308 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09309 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09310 if (cmd < 0 || cmd == 't' || cmd == '#')
09311 return cmd;
09312 }
09313
09314 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09315 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09316 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09317 if (cmd < 0 || cmd == 't' || cmd == '#')
09318 return cmd;
09319 }
09320 }
09321
09322
09323
09324
09325
09326 for (;;) {
09327 newpassword[1] = '\0';
09328 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09329 if (cmd == '#')
09330 newpassword[0] = '\0';
09331 if (cmd < 0 || cmd == 't' || cmd == '#')
09332 return cmd;
09333 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09334 if (cmd < 0 || cmd == 't' || cmd == '#')
09335 return cmd;
09336 cmd = check_password(vmu, newpassword);
09337 if (cmd != 0) {
09338 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09339 cmd = ast_play_and_wait(chan, vm_invalid_password);
09340 } else {
09341 newpassword2[1] = '\0';
09342 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09343 if (cmd == '#')
09344 newpassword2[0] = '\0';
09345 if (cmd < 0 || cmd == 't' || cmd == '#')
09346 return cmd;
09347 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09348 if (cmd < 0 || cmd == 't' || cmd == '#')
09349 return cmd;
09350 if (!strcmp(newpassword, newpassword2))
09351 break;
09352 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09353 cmd = ast_play_and_wait(chan, vm_mismatch);
09354 }
09355 if (++tries == 3)
09356 return -1;
09357 if (cmd != 0) {
09358 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09359 }
09360 }
09361 if (pwdchange & PWDCHANGE_INTERNAL)
09362 vm_change_password(vmu, newpassword);
09363 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09364 vm_change_password_shell(vmu, newpassword);
09365
09366 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09367 cmd = ast_play_and_wait(chan, vm_passchanged);
09368
09369 return cmd;
09370 }
09371
09372 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09373 {
09374 int cmd = 0;
09375 int retries = 0;
09376 int duration = 0;
09377 char newpassword[80] = "";
09378 char newpassword2[80] = "";
09379 char prefile[PATH_MAX] = "";
09380 unsigned char buf[256];
09381 int bytes = 0;
09382
09383 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09384 if (ast_adsi_available(chan)) {
09385 bytes += adsi_logo(buf + bytes);
09386 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09387 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09388 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09389 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09390 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09391 }
09392 while ((cmd >= 0) && (cmd != 't')) {
09393 if (cmd)
09394 retries = 0;
09395 switch (cmd) {
09396 case '1':
09397 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09398 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09399 break;
09400 case '2':
09401 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09402 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09403 break;
09404 case '3':
09405 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09406 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09407 break;
09408 case '4':
09409 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09410 break;
09411 case '5':
09412 if (vmu->password[0] == '-') {
09413 cmd = ast_play_and_wait(chan, "vm-no");
09414 break;
09415 }
09416 newpassword[1] = '\0';
09417 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09418 if (cmd == '#')
09419 newpassword[0] = '\0';
09420 else {
09421 if (cmd < 0)
09422 break;
09423 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09424 break;
09425 }
09426 }
09427 cmd = check_password(vmu, newpassword);
09428 if (cmd != 0) {
09429 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09430 cmd = ast_play_and_wait(chan, vm_invalid_password);
09431 if (!cmd) {
09432 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09433 }
09434 break;
09435 }
09436 newpassword2[1] = '\0';
09437 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09438 if (cmd == '#')
09439 newpassword2[0] = '\0';
09440 else {
09441 if (cmd < 0)
09442 break;
09443
09444 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09445 break;
09446 }
09447 }
09448 if (strcmp(newpassword, newpassword2)) {
09449 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09450 cmd = ast_play_and_wait(chan, vm_mismatch);
09451 if (!cmd) {
09452 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09453 }
09454 break;
09455 }
09456
09457 if (pwdchange & PWDCHANGE_INTERNAL) {
09458 vm_change_password(vmu, newpassword);
09459 }
09460 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09461 vm_change_password_shell(vmu, newpassword);
09462 }
09463
09464 ast_debug(1, "User %s set password to %s of length %d\n",
09465 vms->username, newpassword, (int) strlen(newpassword));
09466 cmd = ast_play_and_wait(chan, vm_passchanged);
09467 break;
09468 case '*':
09469 cmd = 't';
09470 break;
09471 default:
09472 cmd = 0;
09473 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09474 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09475 if (ast_fileexists(prefile, NULL, NULL)) {
09476 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09477 }
09478 DISPOSE(prefile, -1);
09479 if (!cmd) {
09480 cmd = ast_play_and_wait(chan, "vm-options");
09481 }
09482 if (!cmd) {
09483 cmd = ast_waitfordigit(chan, 6000);
09484 }
09485 if (!cmd) {
09486 retries++;
09487 }
09488 if (retries > 3) {
09489 cmd = 't';
09490 }
09491 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09492 }
09493 }
09494 if (cmd == 't')
09495 cmd = 0;
09496 return cmd;
09497 }
09498
09499
09500
09501
09502
09503
09504
09505
09506
09507
09508
09509
09510
09511
09512
09513
09514
09515 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09516 {
09517 int cmd = 0;
09518 int retries = 0;
09519 int duration = 0;
09520 char prefile[PATH_MAX] = "";
09521 unsigned char buf[256];
09522 int bytes = 0;
09523
09524 if (ast_adsi_available(chan)) {
09525 bytes += adsi_logo(buf + bytes);
09526 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09527 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09528 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09529 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09530 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09531 }
09532
09533 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09534 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09535 while ((cmd >= 0) && (cmd != 't')) {
09536 if (cmd)
09537 retries = 0;
09538 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09539 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09540 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09541 if (cmd == -1) {
09542 break;
09543 }
09544 cmd = 't';
09545 } else {
09546 switch (cmd) {
09547 case '1':
09548 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09549 break;
09550 case '2':
09551 DELETE(prefile, -1, prefile, vmu);
09552 ast_play_and_wait(chan, "vm-tempremoved");
09553 cmd = 't';
09554 break;
09555 case '*':
09556 cmd = 't';
09557 break;
09558 default:
09559 cmd = ast_play_and_wait(chan,
09560 ast_fileexists(prefile, NULL, NULL) > 0 ?
09561 "vm-tempgreeting2" : "vm-tempgreeting");
09562 if (!cmd) {
09563 cmd = ast_waitfordigit(chan, 6000);
09564 }
09565 if (!cmd) {
09566 retries++;
09567 }
09568 if (retries > 3) {
09569 cmd = 't';
09570 }
09571 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09572 }
09573 }
09574 DISPOSE(prefile, -1);
09575 }
09576 if (cmd == 't')
09577 cmd = 0;
09578 return cmd;
09579 }
09580
09581
09582
09583
09584
09585
09586
09587
09588
09589 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09590 {
09591 int cmd = 0;
09592
09593 if (vms->lastmsg > -1) {
09594 cmd = play_message(chan, vmu, vms);
09595 } else {
09596 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09597 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09598 if (!cmd) {
09599 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09600 cmd = ast_play_and_wait(chan, vms->fn);
09601 }
09602 if (!cmd)
09603 cmd = ast_play_and_wait(chan, "vm-messages");
09604 } else {
09605 if (!cmd)
09606 cmd = ast_play_and_wait(chan, "vm-messages");
09607 if (!cmd) {
09608 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09609 cmd = ast_play_and_wait(chan, vms->fn);
09610 }
09611 }
09612 }
09613 return cmd;
09614 }
09615
09616
09617 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09618 {
09619 int cmd = 0;
09620
09621 if (vms->lastmsg > -1) {
09622 cmd = play_message(chan, vmu, vms);
09623 } else {
09624 if (!strcasecmp(vms->fn, "INBOX")) {
09625 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09626 } else {
09627 cmd = ast_play_and_wait(chan, "vm-nomessages");
09628 }
09629 }
09630 return cmd;
09631 }
09632
09633
09634
09635
09636
09637
09638
09639
09640
09641 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09642 {
09643 int cmd = 0;
09644
09645 if (vms->lastmsg > -1) {
09646 cmd = play_message(chan, vmu, vms);
09647 } else {
09648 cmd = ast_play_and_wait(chan, "vm-youhave");
09649 if (!cmd)
09650 cmd = ast_play_and_wait(chan, "vm-no");
09651 if (!cmd) {
09652 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09653 cmd = ast_play_and_wait(chan, vms->fn);
09654 }
09655 if (!cmd)
09656 cmd = ast_play_and_wait(chan, "vm-messages");
09657 }
09658 return cmd;
09659 }
09660
09661
09662
09663
09664
09665
09666
09667
09668
09669 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09670 {
09671 int cmd;
09672
09673 if (vms->lastmsg > -1) {
09674 cmd = play_message(chan, vmu, vms);
09675 } else {
09676 cmd = ast_play_and_wait(chan, "vm-no");
09677 if (!cmd)
09678 cmd = ast_play_and_wait(chan, "vm-message");
09679 if (!cmd) {
09680 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09681 cmd = ast_play_and_wait(chan, vms->fn);
09682 }
09683 }
09684 return cmd;
09685 }
09686
09687
09688
09689
09690
09691
09692
09693
09694
09695 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09696 {
09697 int cmd;
09698
09699 if (vms->lastmsg > -1) {
09700 cmd = play_message(chan, vmu, vms);
09701 } else {
09702 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09703 if (!cmd)
09704 cmd = ast_play_and_wait(chan, "vm-messages");
09705 if (!cmd) {
09706 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09707 cmd = ast_play_and_wait(chan, vms->fn);
09708 }
09709 }
09710 return cmd;
09711 }
09712
09713
09714
09715
09716
09717
09718
09719
09720
09721 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09722 {
09723 int cmd;
09724
09725 if (vms->lastmsg > -1) {
09726 cmd = play_message(chan, vmu, vms);
09727 } else {
09728 cmd = ast_play_and_wait(chan, "vm-no");
09729 if (!cmd) {
09730 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09731 cmd = ast_play_and_wait(chan, vms->fn);
09732 }
09733 if (!cmd)
09734 cmd = ast_play_and_wait(chan, "vm-messages");
09735 }
09736 return cmd;
09737 }
09738
09739
09740
09741
09742
09743
09744
09745
09746
09747 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09748 {
09749 int cmd;
09750
09751 if (vms->lastmsg > -1) {
09752 cmd = play_message(chan, vmu, vms);
09753 } else {
09754 cmd = ast_play_and_wait(chan, "vm-you");
09755 if (!cmd)
09756 cmd = ast_play_and_wait(chan, "vm-haveno");
09757 if (!cmd)
09758 cmd = ast_play_and_wait(chan, "vm-messages");
09759 if (!cmd) {
09760 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09761 cmd = ast_play_and_wait(chan, vms->fn);
09762 }
09763 }
09764 return cmd;
09765 }
09766
09767
09768
09769
09770
09771
09772
09773
09774
09775 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09776 {
09777 int cmd = 0;
09778
09779 if (vms->lastmsg > -1) {
09780 cmd = play_message(chan, vmu, vms);
09781 } else {
09782 cmd = ast_play_and_wait(chan, "vm-no");
09783 if (!cmd) {
09784 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09785 cmd = ast_play_and_wait(chan, vms->fn);
09786 }
09787 }
09788 return cmd;
09789 }
09790
09791
09792
09793
09794
09795
09796
09797
09798
09799
09800
09801
09802 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09803 {
09804 if (!strncasecmp(chan->language, "es", 2)) {
09805 return vm_browse_messages_es(chan, vms, vmu);
09806 } else if (!strncasecmp(chan->language, "gr", 2)) {
09807 return vm_browse_messages_gr(chan, vms, vmu);
09808 } else if (!strncasecmp(chan->language, "he", 2)) {
09809 return vm_browse_messages_he(chan, vms, vmu);
09810 } else if (!strncasecmp(chan->language, "it", 2)) {
09811 return vm_browse_messages_it(chan, vms, vmu);
09812 } else if (!strncasecmp(chan->language, "pt", 2)) {
09813 return vm_browse_messages_pt(chan, vms, vmu);
09814 } else if (!strncasecmp(chan->language, "vi", 2)) {
09815 return vm_browse_messages_vi(chan, vms, vmu);
09816 } else if (!strncasecmp(chan->language, "zh", 2)) {
09817 return vm_browse_messages_zh(chan, vms, vmu);
09818 } else {
09819 return vm_browse_messages_en(chan, vms, vmu);
09820 }
09821 }
09822
09823 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09824 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09825 int skipuser, int max_logins, int silent)
09826 {
09827 int useadsi = 0, valid = 0, logretries = 0;
09828 char password[AST_MAX_EXTENSION]="", *passptr;
09829 struct ast_vm_user vmus, *vmu = NULL;
09830
09831
09832 adsi_begin(chan, &useadsi);
09833 if (!skipuser && useadsi)
09834 adsi_login(chan);
09835 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09836 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09837 return -1;
09838 }
09839
09840
09841
09842 while (!valid && (logretries < max_logins)) {
09843
09844 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09845 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09846 return -1;
09847 }
09848 if (ast_strlen_zero(mailbox)) {
09849 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09850 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09851 } else {
09852 ast_verb(3, "Username not entered\n");
09853 return -1;
09854 }
09855 } else if (mailbox[0] == '*') {
09856
09857 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09858 if (ast_exists_extension(chan, chan->context, "a", 1,
09859 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09860 return -1;
09861 }
09862 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09863 mailbox[0] = '\0';
09864 }
09865
09866 if (useadsi)
09867 adsi_password(chan);
09868
09869 if (!ast_strlen_zero(prefix)) {
09870 char fullusername[80] = "";
09871 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09872 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09873 ast_copy_string(mailbox, fullusername, mailbox_size);
09874 }
09875
09876 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09877 vmu = find_user(&vmus, context, mailbox);
09878 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09879
09880 password[0] = '\0';
09881 } else {
09882 if (ast_streamfile(chan, vm_password, chan->language)) {
09883 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09884 return -1;
09885 }
09886 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09887 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09888 return -1;
09889 } else if (password[0] == '*') {
09890
09891 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09892 if (ast_exists_extension(chan, chan->context, "a", 1,
09893 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09894 mailbox[0] = '*';
09895 return -1;
09896 }
09897 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09898 mailbox[0] = '\0';
09899
09900 vmu = NULL;
09901 }
09902 }
09903
09904 if (vmu) {
09905 passptr = vmu->password;
09906 if (passptr[0] == '-') passptr++;
09907 }
09908 if (vmu && !strcmp(passptr, password))
09909 valid++;
09910 else {
09911 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09912 if (!ast_strlen_zero(prefix))
09913 mailbox[0] = '\0';
09914 }
09915 logretries++;
09916 if (!valid) {
09917 if (skipuser || logretries >= max_logins) {
09918 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09919 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09920 return -1;
09921 }
09922 } else {
09923 if (useadsi)
09924 adsi_login(chan);
09925 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09926 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09927 return -1;
09928 }
09929 }
09930 if (ast_waitstream(chan, ""))
09931 return -1;
09932 }
09933 }
09934 if (!valid && (logretries >= max_logins)) {
09935 ast_stopstream(chan);
09936 ast_play_and_wait(chan, "vm-goodbye");
09937 return -1;
09938 }
09939 if (vmu && !skipuser) {
09940 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09941 }
09942 return 0;
09943 }
09944
09945 static int vm_execmain(struct ast_channel *chan, const char *data)
09946 {
09947
09948
09949
09950 int res = -1;
09951 int cmd = 0;
09952 int valid = 0;
09953 char prefixstr[80] ="";
09954 char ext_context[256]="";
09955 int box;
09956 int useadsi = 0;
09957 int skipuser = 0;
09958 struct vm_state vms;
09959 struct ast_vm_user *vmu = NULL, vmus;
09960 char *context = NULL;
09961 int silentexit = 0;
09962 struct ast_flags flags = { 0 };
09963 signed char record_gain = 0;
09964 int play_auto = 0;
09965 int play_folder = 0;
09966 int in_urgent = 0;
09967 #ifdef IMAP_STORAGE
09968 int deleted = 0;
09969 #endif
09970
09971
09972 memset(&vms, 0, sizeof(vms));
09973
09974 vms.lastmsg = -1;
09975
09976 memset(&vmus, 0, sizeof(vmus));
09977
09978 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09979 if (chan->_state != AST_STATE_UP) {
09980 ast_debug(1, "Before ast_answer\n");
09981 ast_answer(chan);
09982 }
09983
09984 if (!ast_strlen_zero(data)) {
09985 char *opts[OPT_ARG_ARRAY_SIZE];
09986 char *parse;
09987 AST_DECLARE_APP_ARGS(args,
09988 AST_APP_ARG(argv0);
09989 AST_APP_ARG(argv1);
09990 );
09991
09992 parse = ast_strdupa(data);
09993
09994 AST_STANDARD_APP_ARGS(args, parse);
09995
09996 if (args.argc == 2) {
09997 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09998 return -1;
09999 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10000 int gain;
10001 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
10002 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10003 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10004 return -1;
10005 } else {
10006 record_gain = (signed char) gain;
10007 }
10008 } else {
10009 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
10010 }
10011 }
10012 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
10013 play_auto = 1;
10014 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
10015
10016 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
10017 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
10018 play_folder = -1;
10019 }
10020 } else {
10021 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
10022 }
10023 } else {
10024 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10025 }
10026 if (play_folder > 9 || play_folder < 0) {
10027 ast_log(AST_LOG_WARNING,
10028 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10029 opts[OPT_ARG_PLAYFOLDER]);
10030 play_folder = 0;
10031 }
10032 }
10033 } else {
10034
10035 while (*(args.argv0)) {
10036 if (*(args.argv0) == 's')
10037 ast_set_flag(&flags, OPT_SILENT);
10038 else if (*(args.argv0) == 'p')
10039 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10040 else
10041 break;
10042 (args.argv0)++;
10043 }
10044
10045 }
10046
10047 valid = ast_test_flag(&flags, OPT_SILENT);
10048
10049 if ((context = strchr(args.argv0, '@')))
10050 *context++ = '\0';
10051
10052 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10053 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10054 else
10055 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10056
10057 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10058 skipuser++;
10059 else
10060 valid = 0;
10061 }
10062
10063 if (!valid)
10064 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10065
10066 ast_debug(1, "After vm_authenticate\n");
10067
10068 if (vms.username[0] == '*') {
10069 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10070
10071
10072 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10073 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10074 res = 0;
10075 goto out;
10076 }
10077 }
10078
10079 if (!res) {
10080 valid = 1;
10081 if (!skipuser)
10082 vmu = &vmus;
10083 } else {
10084 res = 0;
10085 }
10086
10087
10088 adsi_begin(chan, &useadsi);
10089
10090 ast_test_suite_assert(valid);
10091 if (!valid) {
10092 goto out;
10093 }
10094 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10095
10096 #ifdef IMAP_STORAGE
10097 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10098 pthread_setspecific(ts_vmstate.key, &vms);
10099
10100 vms.interactive = 1;
10101 vms.updated = 1;
10102 if (vmu)
10103 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10104 vmstate_insert(&vms);
10105 init_vm_state(&vms);
10106 #endif
10107
10108
10109 if (!ast_strlen_zero(vmu->language))
10110 ast_string_field_set(chan, language, vmu->language);
10111
10112
10113 ast_debug(1, "Before open_mailbox\n");
10114 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10115 if (res < 0)
10116 goto out;
10117 vms.oldmessages = vms.lastmsg + 1;
10118 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10119
10120 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10121 if (res < 0)
10122 goto out;
10123 vms.newmessages = vms.lastmsg + 1;
10124 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10125
10126 in_urgent = 1;
10127 res = open_mailbox(&vms, vmu, 11);
10128 if (res < 0)
10129 goto out;
10130 vms.urgentmessages = vms.lastmsg + 1;
10131 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10132
10133
10134 if (play_auto) {
10135 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10136 if (vms.urgentmessages) {
10137 in_urgent = 1;
10138 res = open_mailbox(&vms, vmu, 11);
10139 } else {
10140 in_urgent = 0;
10141 res = open_mailbox(&vms, vmu, play_folder);
10142 }
10143 if (res < 0)
10144 goto out;
10145
10146
10147 if (vms.lastmsg == -1) {
10148 in_urgent = 0;
10149 cmd = vm_browse_messages(chan, &vms, vmu);
10150 res = 0;
10151 goto out;
10152 }
10153 } else {
10154 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10155
10156 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10157 in_urgent = 0;
10158 play_folder = 1;
10159 if (res < 0)
10160 goto out;
10161 } else if (!vms.urgentmessages && vms.newmessages) {
10162
10163 in_urgent = 0;
10164 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10165 if (res < 0)
10166 goto out;
10167 }
10168 }
10169
10170 if (useadsi)
10171 adsi_status(chan, &vms);
10172 res = 0;
10173
10174
10175 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10176 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10177 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10178 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10179 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10180 if ((cmd == 't') || (cmd == '#')) {
10181
10182 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10183 res = 0;
10184 goto out;
10185 } else if (cmd < 0) {
10186
10187 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10188 res = -1;
10189 goto out;
10190 }
10191 }
10192 #ifdef IMAP_STORAGE
10193 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10194 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10195 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10196 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10197 }
10198 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10199 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10200 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10201 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10202 }
10203 #endif
10204
10205 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10206 if (play_auto) {
10207 cmd = '1';
10208 } else {
10209 cmd = vm_intro(chan, vmu, &vms);
10210 }
10211 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10212
10213 vms.repeats = 0;
10214 vms.starting = 1;
10215 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10216
10217 switch (cmd) {
10218 case '1':
10219 vms.curmsg = 0;
10220
10221 case '5':
10222 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10223 cmd = vm_browse_messages(chan, &vms, vmu);
10224 break;
10225 case '2':
10226 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10227 if (useadsi)
10228 adsi_folders(chan, 0, "Change to folder...");
10229
10230 cmd = get_folder2(chan, "vm-changeto", 0);
10231 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10232 if (cmd == '#') {
10233 cmd = 0;
10234 } else if (cmd > 0) {
10235 cmd = cmd - '0';
10236 res = close_mailbox(&vms, vmu);
10237 if (res == ERROR_LOCK_PATH)
10238 goto out;
10239
10240 if (cmd != 11) in_urgent = 0;
10241 res = open_mailbox(&vms, vmu, cmd);
10242 if (res < 0)
10243 goto out;
10244 play_folder = cmd;
10245 cmd = 0;
10246 }
10247 if (useadsi)
10248 adsi_status2(chan, &vms);
10249
10250 if (!cmd) {
10251 cmd = vm_play_folder_name(chan, vms.vmbox);
10252 }
10253
10254 vms.starting = 1;
10255 vms.curmsg = 0;
10256 break;
10257 case '3':
10258 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10259 cmd = 0;
10260 vms.repeats = 0;
10261 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10262 switch (cmd) {
10263 case '1':
10264 if (vms.lastmsg > -1 && !vms.starting) {
10265 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10266 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10267 res = cmd;
10268 goto out;
10269 }
10270 } else {
10271 cmd = ast_play_and_wait(chan, "vm-sorry");
10272 }
10273 cmd = 't';
10274 break;
10275 case '2':
10276 if (!vms.starting)
10277 ast_verb(3, "Callback Requested\n");
10278 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10279 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10280 if (cmd == 9) {
10281 silentexit = 1;
10282 goto out;
10283 } else if (cmd == ERROR_LOCK_PATH) {
10284 res = cmd;
10285 goto out;
10286 }
10287 } else {
10288 cmd = ast_play_and_wait(chan, "vm-sorry");
10289 }
10290 cmd = 't';
10291 break;
10292 case '3':
10293 if (vms.lastmsg > -1 && !vms.starting) {
10294 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10295 if (cmd == ERROR_LOCK_PATH) {
10296 res = cmd;
10297 goto out;
10298 }
10299 } else {
10300 cmd = ast_play_and_wait(chan, "vm-sorry");
10301 }
10302 cmd = 't';
10303 break;
10304 case '4':
10305 if (!ast_strlen_zero(vmu->dialout)) {
10306 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10307 if (cmd == 9) {
10308 silentexit = 1;
10309 goto out;
10310 }
10311 } else {
10312 cmd = ast_play_and_wait(chan, "vm-sorry");
10313 }
10314 cmd = 't';
10315 break;
10316
10317 case '5':
10318 if (ast_test_flag(vmu, VM_SVMAIL)) {
10319 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10320 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10321 res = cmd;
10322 goto out;
10323 }
10324 } else {
10325 cmd = ast_play_and_wait(chan, "vm-sorry");
10326 }
10327 cmd = 't';
10328 break;
10329
10330 case '*':
10331 cmd = 't';
10332 break;
10333
10334 default:
10335 cmd = 0;
10336 if (!vms.starting) {
10337 cmd = ast_play_and_wait(chan, "vm-toreply");
10338 }
10339 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10340 cmd = ast_play_and_wait(chan, "vm-tocallback");
10341 }
10342 if (!cmd && !vms.starting) {
10343 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10344 }
10345 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10346 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10347 }
10348 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10349 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10350 }
10351 if (!cmd) {
10352 cmd = ast_play_and_wait(chan, "vm-starmain");
10353 }
10354 if (!cmd) {
10355 cmd = ast_waitfordigit(chan, 6000);
10356 }
10357 if (!cmd) {
10358 vms.repeats++;
10359 }
10360 if (vms.repeats > 3) {
10361 cmd = 't';
10362 }
10363 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10364 }
10365 }
10366 if (cmd == 't') {
10367 cmd = 0;
10368 vms.repeats = 0;
10369 }
10370 break;
10371 case '4':
10372 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10373 if (vms.curmsg > 0) {
10374 vms.curmsg--;
10375 cmd = play_message(chan, vmu, &vms);
10376 } else {
10377
10378
10379
10380
10381 if (in_urgent == 0 && vms.urgentmessages > 0) {
10382
10383 in_urgent = 1;
10384 res = close_mailbox(&vms, vmu);
10385 if (res == ERROR_LOCK_PATH)
10386 goto out;
10387 res = open_mailbox(&vms, vmu, 11);
10388 if (res < 0)
10389 goto out;
10390 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10391 vms.curmsg = vms.lastmsg;
10392 if (vms.lastmsg < 0) {
10393 cmd = ast_play_and_wait(chan, "vm-nomore");
10394 }
10395 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10396 vms.curmsg = vms.lastmsg;
10397 cmd = play_message(chan, vmu, &vms);
10398 } else {
10399 cmd = ast_play_and_wait(chan, "vm-nomore");
10400 }
10401 }
10402 break;
10403 case '6':
10404 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10405 if (vms.curmsg < vms.lastmsg) {
10406 vms.curmsg++;
10407 cmd = play_message(chan, vmu, &vms);
10408 } else {
10409 if (in_urgent && vms.newmessages > 0) {
10410
10411
10412
10413
10414 in_urgent = 0;
10415 res = close_mailbox(&vms, vmu);
10416 if (res == ERROR_LOCK_PATH)
10417 goto out;
10418 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10419 if (res < 0)
10420 goto out;
10421 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10422 vms.curmsg = -1;
10423 if (vms.lastmsg < 0) {
10424 cmd = ast_play_and_wait(chan, "vm-nomore");
10425 }
10426 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10427 vms.curmsg = 0;
10428 cmd = play_message(chan, vmu, &vms);
10429 } else {
10430 cmd = ast_play_and_wait(chan, "vm-nomore");
10431 }
10432 }
10433 break;
10434 case '7':
10435 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10436 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10437 if (useadsi)
10438 adsi_delete(chan, &vms);
10439 if (vms.deleted[vms.curmsg]) {
10440 if (play_folder == 0) {
10441 if (in_urgent) {
10442 vms.urgentmessages--;
10443 } else {
10444 vms.newmessages--;
10445 }
10446 }
10447 else if (play_folder == 1)
10448 vms.oldmessages--;
10449 cmd = ast_play_and_wait(chan, "vm-deleted");
10450 } else {
10451 if (play_folder == 0) {
10452 if (in_urgent) {
10453 vms.urgentmessages++;
10454 } else {
10455 vms.newmessages++;
10456 }
10457 }
10458 else if (play_folder == 1)
10459 vms.oldmessages++;
10460 cmd = ast_play_and_wait(chan, "vm-undeleted");
10461 }
10462 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10463 if (vms.curmsg < vms.lastmsg) {
10464 vms.curmsg++;
10465 cmd = play_message(chan, vmu, &vms);
10466 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10467 vms.curmsg = 0;
10468 cmd = play_message(chan, vmu, &vms);
10469 } else {
10470
10471
10472
10473
10474 if (in_urgent == 1) {
10475
10476 in_urgent = 0;
10477 res = close_mailbox(&vms, vmu);
10478 if (res == ERROR_LOCK_PATH)
10479 goto out;
10480 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10481 if (res < 0)
10482 goto out;
10483 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10484 vms.curmsg = -1;
10485 if (vms.lastmsg < 0) {
10486 cmd = ast_play_and_wait(chan, "vm-nomore");
10487 }
10488 } else {
10489 cmd = ast_play_and_wait(chan, "vm-nomore");
10490 }
10491 }
10492 }
10493 } else
10494 cmd = 0;
10495 #ifdef IMAP_STORAGE
10496 deleted = 1;
10497 #endif
10498 break;
10499
10500 case '8':
10501 if (vms.lastmsg > -1) {
10502 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10503 if (cmd == ERROR_LOCK_PATH) {
10504 res = cmd;
10505 goto out;
10506 }
10507 } else {
10508
10509
10510
10511
10512 if (in_urgent == 1 && vms.newmessages > 0) {
10513
10514 in_urgent = 0;
10515 res = close_mailbox(&vms, vmu);
10516 if (res == ERROR_LOCK_PATH)
10517 goto out;
10518 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10519 if (res < 0)
10520 goto out;
10521 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10522 vms.curmsg = -1;
10523 if (vms.lastmsg < 0) {
10524 cmd = ast_play_and_wait(chan, "vm-nomore");
10525 }
10526 } else {
10527 cmd = ast_play_and_wait(chan, "vm-nomore");
10528 }
10529 }
10530 break;
10531 case '9':
10532 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10533 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10534
10535 cmd = 0;
10536 break;
10537 }
10538 if (useadsi)
10539 adsi_folders(chan, 1, "Save to folder...");
10540 cmd = get_folder2(chan, "vm-savefolder", 1);
10541 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10542 box = 0;
10543 if (cmd == '#') {
10544 cmd = 0;
10545 break;
10546 } else if (cmd > 0) {
10547 box = cmd = cmd - '0';
10548 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10549 if (cmd == ERROR_LOCK_PATH) {
10550 res = cmd;
10551 goto out;
10552 #ifndef IMAP_STORAGE
10553 } else if (!cmd) {
10554 vms.deleted[vms.curmsg] = 1;
10555 #endif
10556 } else {
10557 vms.deleted[vms.curmsg] = 0;
10558 vms.heard[vms.curmsg] = 0;
10559 }
10560 }
10561 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10562 if (useadsi)
10563 adsi_message(chan, &vms);
10564 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10565 if (!cmd) {
10566 cmd = ast_play_and_wait(chan, "vm-message");
10567 if (!cmd)
10568 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10569 if (!cmd)
10570 cmd = ast_play_and_wait(chan, "vm-savedto");
10571 if (!cmd)
10572 cmd = vm_play_folder_name(chan, vms.fn);
10573 } else {
10574 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10575 }
10576 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10577 if (vms.curmsg < vms.lastmsg) {
10578 vms.curmsg++;
10579 cmd = play_message(chan, vmu, &vms);
10580 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10581 vms.curmsg = 0;
10582 cmd = play_message(chan, vmu, &vms);
10583 } else {
10584
10585
10586
10587
10588 if (in_urgent == 1 && vms.newmessages > 0) {
10589
10590 in_urgent = 0;
10591 res = close_mailbox(&vms, vmu);
10592 if (res == ERROR_LOCK_PATH)
10593 goto out;
10594 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10595 if (res < 0)
10596 goto out;
10597 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10598 vms.curmsg = -1;
10599 if (vms.lastmsg < 0) {
10600 cmd = ast_play_and_wait(chan, "vm-nomore");
10601 }
10602 } else {
10603 cmd = ast_play_and_wait(chan, "vm-nomore");
10604 }
10605 }
10606 }
10607 break;
10608 case '*':
10609 if (!vms.starting) {
10610 cmd = ast_play_and_wait(chan, "vm-onefor");
10611 if (!strncasecmp(chan->language, "he", 2)) {
10612 cmd = ast_play_and_wait(chan, "vm-for");
10613 }
10614 if (!cmd)
10615 cmd = vm_play_folder_name(chan, vms.vmbox);
10616 if (!cmd)
10617 cmd = ast_play_and_wait(chan, "vm-opts");
10618 if (!cmd)
10619 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10620 } else
10621 cmd = 0;
10622 break;
10623 case '0':
10624 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10625 if (useadsi)
10626 adsi_status(chan, &vms);
10627 break;
10628 default:
10629 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10630 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10631 break;
10632 }
10633 }
10634 if ((cmd == 't') || (cmd == '#')) {
10635
10636 res = 0;
10637 } else {
10638
10639 res = -1;
10640 }
10641
10642 out:
10643 if (res > -1) {
10644 ast_stopstream(chan);
10645 adsi_goodbye(chan);
10646 if (valid && res != OPERATOR_EXIT) {
10647 if (silentexit)
10648 res = ast_play_and_wait(chan, "vm-dialout");
10649 else
10650 res = ast_play_and_wait(chan, "vm-goodbye");
10651 }
10652 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10653 res = 0;
10654 }
10655 if (useadsi)
10656 ast_adsi_unload_session(chan);
10657 }
10658 if (vmu)
10659 close_mailbox(&vms, vmu);
10660 if (valid) {
10661 int new = 0, old = 0, urgent = 0;
10662 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10663 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10664
10665 run_externnotify(vmu->context, vmu->mailbox, NULL);
10666 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10667 queue_mwi_event(ext_context, urgent, new, old);
10668 }
10669 #ifdef IMAP_STORAGE
10670
10671 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10672 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10673 ast_mutex_lock(&vms.lock);
10674 #ifdef HAVE_IMAP_TK2006
10675 if (LEVELUIDPLUS (vms.mailstream)) {
10676 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10677 } else
10678 #endif
10679 mail_expunge(vms.mailstream);
10680 ast_mutex_unlock(&vms.lock);
10681 }
10682
10683
10684 if (vmu) {
10685 vmstate_delete(&vms);
10686 }
10687 #endif
10688 if (vmu)
10689 free_user(vmu);
10690
10691 #ifdef IMAP_STORAGE
10692 pthread_setspecific(ts_vmstate.key, NULL);
10693 #endif
10694 return res;
10695 }
10696
10697 static int vm_exec(struct ast_channel *chan, const char *data)
10698 {
10699 int res = 0;
10700 char *tmp;
10701 struct leave_vm_options leave_options;
10702 struct ast_flags flags = { 0 };
10703 char *opts[OPT_ARG_ARRAY_SIZE];
10704 AST_DECLARE_APP_ARGS(args,
10705 AST_APP_ARG(argv0);
10706 AST_APP_ARG(argv1);
10707 );
10708
10709 memset(&leave_options, 0, sizeof(leave_options));
10710
10711 if (chan->_state != AST_STATE_UP)
10712 ast_answer(chan);
10713
10714 if (!ast_strlen_zero(data)) {
10715 tmp = ast_strdupa(data);
10716 AST_STANDARD_APP_ARGS(args, tmp);
10717 if (args.argc == 2) {
10718 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10719 return -1;
10720 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10721 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10722 int gain;
10723
10724 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10725 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10726 return -1;
10727 } else {
10728 leave_options.record_gain = (signed char) gain;
10729 }
10730 }
10731 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10732 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10733 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10734 }
10735 }
10736 } else {
10737 char temp[256];
10738 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10739 if (res < 0)
10740 return res;
10741 if (ast_strlen_zero(temp))
10742 return 0;
10743 args.argv0 = ast_strdupa(temp);
10744 }
10745
10746 res = leave_voicemail(chan, args.argv0, &leave_options);
10747 if (res == 't') {
10748 ast_play_and_wait(chan, "vm-goodbye");
10749 res = 0;
10750 }
10751
10752 if (res == OPERATOR_EXIT) {
10753 res = 0;
10754 }
10755
10756 if (res == ERROR_LOCK_PATH) {
10757 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10758 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10759 res = 0;
10760 }
10761
10762 return res;
10763 }
10764
10765 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10766 {
10767 struct ast_vm_user *vmu;
10768
10769 if (!ast_strlen_zero(box) && box[0] == '*') {
10770 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10771 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10772 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10773 "\n\tand will be ignored.\n", box, context);
10774 return NULL;
10775 }
10776
10777 AST_LIST_TRAVERSE(&users, vmu, list) {
10778 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10779 if (strcasecmp(vmu->context, context)) {
10780 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10781 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10782 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10783 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10784 }
10785 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10786 return NULL;
10787 }
10788 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10789 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10790 return NULL;
10791 }
10792 }
10793
10794 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10795 return NULL;
10796
10797 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10798 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10799
10800 AST_LIST_INSERT_TAIL(&users, vmu, list);
10801
10802 return vmu;
10803 }
10804
10805 static int append_mailbox(const char *context, const char *box, const char *data)
10806 {
10807
10808 char *tmp;
10809 char *stringp;
10810 char *s;
10811 struct ast_vm_user *vmu;
10812 char *mailbox_full;
10813 int new = 0, old = 0, urgent = 0;
10814 char secretfn[PATH_MAX] = "";
10815
10816 tmp = ast_strdupa(data);
10817
10818 if (!(vmu = find_or_create(context, box)))
10819 return -1;
10820
10821 populate_defaults(vmu);
10822
10823 stringp = tmp;
10824 if ((s = strsep(&stringp, ","))) {
10825 if (!ast_strlen_zero(s) && s[0] == '*') {
10826 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10827 "\n\tmust be reset in voicemail.conf.\n", box);
10828 }
10829
10830 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10831 }
10832 if (stringp && (s = strsep(&stringp, ","))) {
10833 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10834 }
10835 if (stringp && (s = strsep(&stringp, ","))) {
10836 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10837 }
10838 if (stringp && (s = strsep(&stringp, ","))) {
10839 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10840 }
10841 if (stringp && (s = strsep(&stringp, ","))) {
10842 apply_options(vmu, s);
10843 }
10844
10845 switch (vmu->passwordlocation) {
10846 case OPT_PWLOC_SPOOLDIR:
10847 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10848 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10849 }
10850
10851 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10852 strcpy(mailbox_full, box);
10853 strcat(mailbox_full, "@");
10854 strcat(mailbox_full, context);
10855
10856 inboxcount2(mailbox_full, &urgent, &new, &old);
10857 queue_mwi_event(mailbox_full, urgent, new, old);
10858
10859 return 0;
10860 }
10861
10862 AST_TEST_DEFINE(test_voicemail_vmuser)
10863 {
10864 int res = 0;
10865 struct ast_vm_user *vmu;
10866
10867 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10868 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10869 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10870 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10871 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10872 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10873 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10874 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10875 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10876 #ifdef IMAP_STORAGE
10877 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10878 "imapfolder=INBOX|imapvmshareid=6000";
10879 #endif
10880
10881 switch (cmd) {
10882 case TEST_INIT:
10883 info->name = "vmuser";
10884 info->category = "/apps/app_voicemail/";
10885 info->summary = "Vmuser unit test";
10886 info->description =
10887 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10888 return AST_TEST_NOT_RUN;
10889 case TEST_EXECUTE:
10890 break;
10891 }
10892
10893 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10894 return AST_TEST_NOT_RUN;
10895 }
10896 populate_defaults(vmu);
10897 ast_set_flag(vmu, VM_ALLOCED);
10898
10899 apply_options(vmu, options_string);
10900
10901 if (!ast_test_flag(vmu, VM_ATTACH)) {
10902 ast_test_status_update(test, "Parse failure for attach option\n");
10903 res = 1;
10904 }
10905 if (strcasecmp(vmu->attachfmt, "wav49")) {
10906 ast_test_status_update(test, "Parse failure for attachftm option\n");
10907 res = 1;
10908 }
10909 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10910 ast_test_status_update(test, "Parse failure for serveremail option\n");
10911 res = 1;
10912 }
10913 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10914 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10915 res = 1;
10916 }
10917 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10918 ast_test_status_update(test, "Parse failure for emailbody option\n");
10919 res = 1;
10920 }
10921 if (strcasecmp(vmu->zonetag, "central")) {
10922 ast_test_status_update(test, "Parse failure for tz option\n");
10923 res = 1;
10924 }
10925 if (!ast_test_flag(vmu, VM_DELETE)) {
10926 ast_test_status_update(test, "Parse failure for delete option\n");
10927 res = 1;
10928 }
10929 if (!ast_test_flag(vmu, VM_SAYCID)) {
10930 ast_test_status_update(test, "Parse failure for saycid option\n");
10931 res = 1;
10932 }
10933 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10934 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10935 res = 1;
10936 }
10937 if (!ast_test_flag(vmu, VM_REVIEW)) {
10938 ast_test_status_update(test, "Parse failure for review option\n");
10939 res = 1;
10940 }
10941 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10942 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10943 res = 1;
10944 }
10945 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10946 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10947 res = 1;
10948 }
10949 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10950 ast_test_status_update(test, "Parse failure for operator option\n");
10951 res = 1;
10952 }
10953 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10954 ast_test_status_update(test, "Parse failure for envelope option\n");
10955 res = 1;
10956 }
10957 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10958 ast_test_status_update(test, "Parse failure for moveheard option\n");
10959 res = 1;
10960 }
10961 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10962 ast_test_status_update(test, "Parse failure for sayduration option\n");
10963 res = 1;
10964 }
10965 if (vmu->saydurationm != 5) {
10966 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10967 res = 1;
10968 }
10969 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10970 ast_test_status_update(test, "Parse failure for forcename option\n");
10971 res = 1;
10972 }
10973 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10974 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10975 res = 1;
10976 }
10977 if (strcasecmp(vmu->callback, "somecontext")) {
10978 ast_test_status_update(test, "Parse failure for callbacks option\n");
10979 res = 1;
10980 }
10981 if (strcasecmp(vmu->dialout, "somecontext2")) {
10982 ast_test_status_update(test, "Parse failure for dialout option\n");
10983 res = 1;
10984 }
10985 if (strcasecmp(vmu->exit, "somecontext3")) {
10986 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10987 res = 1;
10988 }
10989 if (vmu->minsecs != 10) {
10990 ast_test_status_update(test, "Parse failure for minsecs option\n");
10991 res = 1;
10992 }
10993 if (vmu->maxsecs != 100) {
10994 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10995 res = 1;
10996 }
10997 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10998 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10999 res = 1;
11000 }
11001 if (vmu->maxdeletedmsg != 50) {
11002 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
11003 res = 1;
11004 }
11005 if (vmu->volgain != 1.3) {
11006 ast_test_status_update(test, "Parse failure for volgain option\n");
11007 res = 1;
11008 }
11009 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
11010 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
11011 res = 1;
11012 }
11013 #ifdef IMAP_STORAGE
11014 apply_options(vmu, option_string2);
11015
11016 if (strcasecmp(vmu->imapuser, "imapuser")) {
11017 ast_test_status_update(test, "Parse failure for imapuser option\n");
11018 res = 1;
11019 }
11020 if (strcasecmp(vmu->imappassword, "imappasswd")) {
11021 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11022 res = 1;
11023 }
11024 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11025 ast_test_status_update(test, "Parse failure for imapfolder option\n");
11026 res = 1;
11027 }
11028 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11029 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11030 res = 1;
11031 }
11032 #endif
11033
11034 free_user(vmu);
11035 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11036 }
11037
11038 static int vm_box_exists(struct ast_channel *chan, const char *data)
11039 {
11040 struct ast_vm_user svm;
11041 char *context, *box;
11042 AST_DECLARE_APP_ARGS(args,
11043 AST_APP_ARG(mbox);
11044 AST_APP_ARG(options);
11045 );
11046 static int dep_warning = 0;
11047
11048 if (ast_strlen_zero(data)) {
11049 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11050 return -1;
11051 }
11052
11053 if (!dep_warning) {
11054 dep_warning = 1;
11055 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11056 }
11057
11058 box = ast_strdupa(data);
11059
11060 AST_STANDARD_APP_ARGS(args, box);
11061
11062 if (args.options) {
11063 }
11064
11065 if ((context = strchr(args.mbox, '@'))) {
11066 *context = '\0';
11067 context++;
11068 }
11069
11070 if (find_user(&svm, context, args.mbox)) {
11071 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11072 } else
11073 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11074
11075 return 0;
11076 }
11077
11078 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11079 {
11080 struct ast_vm_user svm;
11081 AST_DECLARE_APP_ARGS(arg,
11082 AST_APP_ARG(mbox);
11083 AST_APP_ARG(context);
11084 );
11085
11086 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11087
11088 if (ast_strlen_zero(arg.mbox)) {
11089 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11090 return -1;
11091 }
11092
11093 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11094 return 0;
11095 }
11096
11097 static struct ast_custom_function mailbox_exists_acf = {
11098 .name = "MAILBOX_EXISTS",
11099 .read = acf_mailbox_exists,
11100 };
11101
11102 static int vmauthenticate(struct ast_channel *chan, const char *data)
11103 {
11104 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11105 struct ast_vm_user vmus;
11106 char *options = NULL;
11107 int silent = 0, skipuser = 0;
11108 int res = -1;
11109
11110 if (data) {
11111 s = ast_strdupa(data);
11112 user = strsep(&s, ",");
11113 options = strsep(&s, ",");
11114 if (user) {
11115 s = user;
11116 user = strsep(&s, "@");
11117 context = strsep(&s, "");
11118 if (!ast_strlen_zero(user))
11119 skipuser++;
11120 ast_copy_string(mailbox, user, sizeof(mailbox));
11121 }
11122 }
11123
11124 if (options) {
11125 silent = (strchr(options, 's')) != NULL;
11126 }
11127
11128 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11129 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11130 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11131 ast_play_and_wait(chan, "auth-thankyou");
11132 res = 0;
11133 } else if (mailbox[0] == '*') {
11134
11135 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11136 res = 0;
11137 }
11138 }
11139
11140 return res;
11141 }
11142
11143 static char *show_users_realtime(int fd, const char *context)
11144 {
11145 struct ast_config *cfg;
11146 const char *cat = NULL;
11147
11148 if (!(cfg = ast_load_realtime_multientry("voicemail",
11149 "context", context, SENTINEL))) {
11150 return CLI_FAILURE;
11151 }
11152
11153 ast_cli(fd,
11154 "\n"
11155 "=============================================================\n"
11156 "=== Configured Voicemail Users ==============================\n"
11157 "=============================================================\n"
11158 "===\n");
11159
11160 while ((cat = ast_category_browse(cfg, cat))) {
11161 struct ast_variable *var = NULL;
11162 ast_cli(fd,
11163 "=== Mailbox ...\n"
11164 "===\n");
11165 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11166 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11167 ast_cli(fd,
11168 "===\n"
11169 "=== ---------------------------------------------------------\n"
11170 "===\n");
11171 }
11172
11173 ast_cli(fd,
11174 "=============================================================\n"
11175 "\n");
11176
11177 ast_config_destroy(cfg);
11178
11179 return CLI_SUCCESS;
11180 }
11181
11182 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11183 {
11184 int which = 0;
11185 int wordlen;
11186 struct ast_vm_user *vmu;
11187 const char *context = "";
11188
11189
11190 if (pos > 4)
11191 return NULL;
11192 if (pos == 3)
11193 return (state == 0) ? ast_strdup("for") : NULL;
11194 wordlen = strlen(word);
11195 AST_LIST_TRAVERSE(&users, vmu, list) {
11196 if (!strncasecmp(word, vmu->context, wordlen)) {
11197 if (context && strcmp(context, vmu->context) && ++which > state)
11198 return ast_strdup(vmu->context);
11199
11200 context = vmu->context;
11201 }
11202 }
11203 return NULL;
11204 }
11205
11206
11207 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11208 {
11209 struct ast_vm_user *vmu;
11210 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11211 const char *context = NULL;
11212 int users_counter = 0;
11213
11214 switch (cmd) {
11215 case CLI_INIT:
11216 e->command = "voicemail show users";
11217 e->usage =
11218 "Usage: voicemail show users [for <context>]\n"
11219 " Lists all mailboxes currently set up\n";
11220 return NULL;
11221 case CLI_GENERATE:
11222 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11223 }
11224
11225 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11226 return CLI_SHOWUSAGE;
11227 if (a->argc == 5) {
11228 if (strcmp(a->argv[3],"for"))
11229 return CLI_SHOWUSAGE;
11230 context = a->argv[4];
11231 }
11232
11233 if (ast_check_realtime("voicemail")) {
11234 if (!context) {
11235 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11236 return CLI_SHOWUSAGE;
11237 }
11238 return show_users_realtime(a->fd, context);
11239 }
11240
11241 AST_LIST_LOCK(&users);
11242 if (AST_LIST_EMPTY(&users)) {
11243 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11244 AST_LIST_UNLOCK(&users);
11245 return CLI_FAILURE;
11246 }
11247 if (!context) {
11248 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11249 } else {
11250 int count = 0;
11251 AST_LIST_TRAVERSE(&users, vmu, list) {
11252 if (!strcmp(context, vmu->context)) {
11253 count++;
11254 break;
11255 }
11256 }
11257 if (count) {
11258 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11259 } else {
11260 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11261 AST_LIST_UNLOCK(&users);
11262 return CLI_FAILURE;
11263 }
11264 }
11265 AST_LIST_TRAVERSE(&users, vmu, list) {
11266 int newmsgs = 0, oldmsgs = 0;
11267 char count[12], tmp[256] = "";
11268
11269 if (!context || !strcmp(context, vmu->context)) {
11270 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11271 inboxcount(tmp, &newmsgs, &oldmsgs);
11272 snprintf(count, sizeof(count), "%d", newmsgs);
11273 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11274 users_counter++;
11275 }
11276 }
11277 AST_LIST_UNLOCK(&users);
11278 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11279 return CLI_SUCCESS;
11280 }
11281
11282
11283 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11284 {
11285 struct vm_zone *zone;
11286 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11287 char *res = CLI_SUCCESS;
11288
11289 switch (cmd) {
11290 case CLI_INIT:
11291 e->command = "voicemail show zones";
11292 e->usage =
11293 "Usage: voicemail show zones\n"
11294 " Lists zone message formats\n";
11295 return NULL;
11296 case CLI_GENERATE:
11297 return NULL;
11298 }
11299
11300 if (a->argc != 3)
11301 return CLI_SHOWUSAGE;
11302
11303 AST_LIST_LOCK(&zones);
11304 if (!AST_LIST_EMPTY(&zones)) {
11305 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11306 AST_LIST_TRAVERSE(&zones, zone, list) {
11307 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11308 }
11309 } else {
11310 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11311 res = CLI_FAILURE;
11312 }
11313 AST_LIST_UNLOCK(&zones);
11314
11315 return res;
11316 }
11317
11318
11319 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11320 {
11321 switch (cmd) {
11322 case CLI_INIT:
11323 e->command = "voicemail reload";
11324 e->usage =
11325 "Usage: voicemail reload\n"
11326 " Reload voicemail configuration\n";
11327 return NULL;
11328 case CLI_GENERATE:
11329 return NULL;
11330 }
11331
11332 if (a->argc != 2)
11333 return CLI_SHOWUSAGE;
11334
11335 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11336 load_config(1);
11337
11338 return CLI_SUCCESS;
11339 }
11340
11341 static struct ast_cli_entry cli_voicemail[] = {
11342 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11343 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11344 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11345 };
11346
11347 #ifdef IMAP_STORAGE
11348 #define DATA_EXPORT_VM_USERS(USER) \
11349 USER(ast_vm_user, context, AST_DATA_STRING) \
11350 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11351 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11352 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11353 USER(ast_vm_user, email, AST_DATA_STRING) \
11354 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11355 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11356 USER(ast_vm_user, pager, AST_DATA_STRING) \
11357 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11358 USER(ast_vm_user, language, AST_DATA_STRING) \
11359 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11360 USER(ast_vm_user, callback, AST_DATA_STRING) \
11361 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11362 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11363 USER(ast_vm_user, exit, AST_DATA_STRING) \
11364 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11365 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11366 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11367 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11368 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11369 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11370 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11371 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11372 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11373 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11374 #else
11375 #define DATA_EXPORT_VM_USERS(USER) \
11376 USER(ast_vm_user, context, AST_DATA_STRING) \
11377 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11378 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11379 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11380 USER(ast_vm_user, email, AST_DATA_STRING) \
11381 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11382 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11383 USER(ast_vm_user, pager, AST_DATA_STRING) \
11384 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11385 USER(ast_vm_user, language, AST_DATA_STRING) \
11386 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11387 USER(ast_vm_user, callback, AST_DATA_STRING) \
11388 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11389 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11390 USER(ast_vm_user, exit, AST_DATA_STRING) \
11391 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11392 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11393 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11394 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11395 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11396 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11397 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11398 #endif
11399
11400 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11401
11402 #define DATA_EXPORT_VM_ZONES(ZONE) \
11403 ZONE(vm_zone, name, AST_DATA_STRING) \
11404 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11405 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11406
11407 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11408
11409
11410
11411
11412
11413
11414
11415
11416 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11417 struct ast_data *data_root, struct ast_vm_user *user)
11418 {
11419 struct ast_data *data_user, *data_zone;
11420 struct ast_data *data_state;
11421 struct vm_zone *zone = NULL;
11422 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11423 char ext_context[256] = "";
11424
11425 data_user = ast_data_add_node(data_root, "user");
11426 if (!data_user) {
11427 return -1;
11428 }
11429
11430 ast_data_add_structure(ast_vm_user, data_user, user);
11431
11432 AST_LIST_LOCK(&zones);
11433 AST_LIST_TRAVERSE(&zones, zone, list) {
11434 if (!strcmp(zone->name, user->zonetag)) {
11435 break;
11436 }
11437 }
11438 AST_LIST_UNLOCK(&zones);
11439
11440
11441 data_state = ast_data_add_node(data_user, "state");
11442 if (!data_state) {
11443 return -1;
11444 }
11445 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11446 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11447 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11448 ast_data_add_int(data_state, "newmsg", newmsg);
11449 ast_data_add_int(data_state, "oldmsg", oldmsg);
11450
11451 if (zone) {
11452 data_zone = ast_data_add_node(data_user, "zone");
11453 ast_data_add_structure(vm_zone, data_zone, zone);
11454 }
11455
11456 if (!ast_data_search_match(search, data_user)) {
11457 ast_data_remove_node(data_root, data_user);
11458 }
11459
11460 return 0;
11461 }
11462
11463 static int vm_users_data_provider_get(const struct ast_data_search *search,
11464 struct ast_data *data_root)
11465 {
11466 struct ast_vm_user *user;
11467
11468 AST_LIST_LOCK(&users);
11469 AST_LIST_TRAVERSE(&users, user, list) {
11470 vm_users_data_provider_get_helper(search, data_root, user);
11471 }
11472 AST_LIST_UNLOCK(&users);
11473
11474 return 0;
11475 }
11476
11477 static const struct ast_data_handler vm_users_data_provider = {
11478 .version = AST_DATA_HANDLER_VERSION,
11479 .get = vm_users_data_provider_get
11480 };
11481
11482 static const struct ast_data_entry vm_data_providers[] = {
11483 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11484 };
11485
11486 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11487 {
11488 int new = 0, old = 0, urgent = 0;
11489
11490 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11491
11492 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11493 mwi_sub->old_urgent = urgent;
11494 mwi_sub->old_new = new;
11495 mwi_sub->old_old = old;
11496 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11497 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11498 }
11499 }
11500
11501 static void poll_subscribed_mailboxes(void)
11502 {
11503 struct mwi_sub *mwi_sub;
11504
11505 AST_RWLIST_RDLOCK(&mwi_subs);
11506 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11507 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11508 poll_subscribed_mailbox(mwi_sub);
11509 }
11510 }
11511 AST_RWLIST_UNLOCK(&mwi_subs);
11512 }
11513
11514 static void *mb_poll_thread(void *data)
11515 {
11516 while (poll_thread_run) {
11517 struct timespec ts = { 0, };
11518 struct timeval wait;
11519
11520 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11521 ts.tv_sec = wait.tv_sec;
11522 ts.tv_nsec = wait.tv_usec * 1000;
11523
11524 ast_mutex_lock(&poll_lock);
11525 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11526 ast_mutex_unlock(&poll_lock);
11527
11528 if (!poll_thread_run)
11529 break;
11530
11531 poll_subscribed_mailboxes();
11532 }
11533
11534 return NULL;
11535 }
11536
11537 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11538 {
11539 ast_free(mwi_sub);
11540 }
11541
11542 static int handle_unsubscribe(void *datap)
11543 {
11544 struct mwi_sub *mwi_sub;
11545 uint32_t *uniqueid = datap;
11546
11547 AST_RWLIST_WRLOCK(&mwi_subs);
11548 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11549 if (mwi_sub->uniqueid == *uniqueid) {
11550 AST_LIST_REMOVE_CURRENT(entry);
11551 break;
11552 }
11553 }
11554 AST_RWLIST_TRAVERSE_SAFE_END
11555 AST_RWLIST_UNLOCK(&mwi_subs);
11556
11557 if (mwi_sub)
11558 mwi_sub_destroy(mwi_sub);
11559
11560 ast_free(uniqueid);
11561 return 0;
11562 }
11563
11564 static int handle_subscribe(void *datap)
11565 {
11566 unsigned int len;
11567 struct mwi_sub *mwi_sub;
11568 struct mwi_sub_task *p = datap;
11569
11570 len = sizeof(*mwi_sub);
11571 if (!ast_strlen_zero(p->mailbox))
11572 len += strlen(p->mailbox);
11573
11574 if (!ast_strlen_zero(p->context))
11575 len += strlen(p->context) + 1;
11576
11577 if (!(mwi_sub = ast_calloc(1, len)))
11578 return -1;
11579
11580 mwi_sub->uniqueid = p->uniqueid;
11581 if (!ast_strlen_zero(p->mailbox))
11582 strcpy(mwi_sub->mailbox, p->mailbox);
11583
11584 if (!ast_strlen_zero(p->context)) {
11585 strcat(mwi_sub->mailbox, "@");
11586 strcat(mwi_sub->mailbox, p->context);
11587 }
11588
11589 AST_RWLIST_WRLOCK(&mwi_subs);
11590 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11591 AST_RWLIST_UNLOCK(&mwi_subs);
11592 ast_free((void *) p->mailbox);
11593 ast_free((void *) p->context);
11594 ast_free(p);
11595 poll_subscribed_mailbox(mwi_sub);
11596 return 0;
11597 }
11598
11599 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11600 {
11601 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11602
11603 if (!uniqueid) {
11604 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11605 return;
11606 }
11607
11608 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11609 ast_free(uniqueid);
11610 return;
11611 }
11612
11613 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11614 ast_free(uniqueid);
11615 return;
11616 }
11617
11618 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11619 *uniqueid = u;
11620 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11621 ast_free(uniqueid);
11622 }
11623 }
11624
11625 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11626 {
11627 struct mwi_sub_task *mwist;
11628
11629 if (ast_event_get_type(event) != AST_EVENT_SUB)
11630 return;
11631
11632 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11633 return;
11634
11635 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11636 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11637 return;
11638 }
11639 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11640 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11641 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11642
11643 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11644 ast_free(mwist);
11645 }
11646 }
11647
11648 static void start_poll_thread(void)
11649 {
11650 int errcode;
11651 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11652 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11653 AST_EVENT_IE_END);
11654
11655 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11656 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11657 AST_EVENT_IE_END);
11658
11659 if (mwi_sub_sub)
11660 ast_event_report_subs(mwi_sub_sub);
11661
11662 poll_thread_run = 1;
11663
11664 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11665 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11666 }
11667 }
11668
11669 static void stop_poll_thread(void)
11670 {
11671 poll_thread_run = 0;
11672
11673 if (mwi_sub_sub) {
11674 ast_event_unsubscribe(mwi_sub_sub);
11675 mwi_sub_sub = NULL;
11676 }
11677
11678 if (mwi_unsub_sub) {
11679 ast_event_unsubscribe(mwi_unsub_sub);
11680 mwi_unsub_sub = NULL;
11681 }
11682
11683 ast_mutex_lock(&poll_lock);
11684 ast_cond_signal(&poll_cond);
11685 ast_mutex_unlock(&poll_lock);
11686
11687 pthread_join(poll_thread, NULL);
11688
11689 poll_thread = AST_PTHREADT_NULL;
11690 }
11691
11692
11693 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11694 {
11695 struct ast_vm_user *vmu = NULL;
11696 const char *id = astman_get_header(m, "ActionID");
11697 char actionid[128] = "";
11698
11699 if (!ast_strlen_zero(id))
11700 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11701
11702 AST_LIST_LOCK(&users);
11703
11704 if (AST_LIST_EMPTY(&users)) {
11705 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11706 AST_LIST_UNLOCK(&users);
11707 return RESULT_SUCCESS;
11708 }
11709
11710 astman_send_ack(s, m, "Voicemail user list will follow");
11711
11712 AST_LIST_TRAVERSE(&users, vmu, list) {
11713 char dirname[256];
11714
11715 #ifdef IMAP_STORAGE
11716 int new, old;
11717 inboxcount(vmu->mailbox, &new, &old);
11718 #endif
11719
11720 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11721 astman_append(s,
11722 "%s"
11723 "Event: VoicemailUserEntry\r\n"
11724 "VMContext: %s\r\n"
11725 "VoiceMailbox: %s\r\n"
11726 "Fullname: %s\r\n"
11727 "Email: %s\r\n"
11728 "Pager: %s\r\n"
11729 "ServerEmail: %s\r\n"
11730 "MailCommand: %s\r\n"
11731 "Language: %s\r\n"
11732 "TimeZone: %s\r\n"
11733 "Callback: %s\r\n"
11734 "Dialout: %s\r\n"
11735 "UniqueID: %s\r\n"
11736 "ExitContext: %s\r\n"
11737 "SayDurationMinimum: %d\r\n"
11738 "SayEnvelope: %s\r\n"
11739 "SayCID: %s\r\n"
11740 "AttachMessage: %s\r\n"
11741 "AttachmentFormat: %s\r\n"
11742 "DeleteMessage: %s\r\n"
11743 "VolumeGain: %.2f\r\n"
11744 "CanReview: %s\r\n"
11745 "CallOperator: %s\r\n"
11746 "MaxMessageCount: %d\r\n"
11747 "MaxMessageLength: %d\r\n"
11748 "NewMessageCount: %d\r\n"
11749 #ifdef IMAP_STORAGE
11750 "OldMessageCount: %d\r\n"
11751 "IMAPUser: %s\r\n"
11752 #endif
11753 "\r\n",
11754 actionid,
11755 vmu->context,
11756 vmu->mailbox,
11757 vmu->fullname,
11758 vmu->email,
11759 vmu->pager,
11760 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11761 mailcmd,
11762 vmu->language,
11763 vmu->zonetag,
11764 vmu->callback,
11765 vmu->dialout,
11766 vmu->uniqueid,
11767 vmu->exit,
11768 vmu->saydurationm,
11769 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11770 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11771 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11772 vmu->attachfmt,
11773 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11774 vmu->volgain,
11775 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11776 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11777 vmu->maxmsg,
11778 vmu->maxsecs,
11779 #ifdef IMAP_STORAGE
11780 new, old, vmu->imapuser
11781 #else
11782 count_messages(vmu, dirname)
11783 #endif
11784 );
11785 }
11786 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11787
11788 AST_LIST_UNLOCK(&users);
11789
11790 return RESULT_SUCCESS;
11791 }
11792
11793
11794 static void free_vm_users(void)
11795 {
11796 struct ast_vm_user *current;
11797 AST_LIST_LOCK(&users);
11798 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11799 ast_set_flag(current, VM_ALLOCED);
11800 free_user(current);
11801 }
11802 AST_LIST_UNLOCK(&users);
11803 }
11804
11805
11806 static void free_vm_zones(void)
11807 {
11808 struct vm_zone *zcur;
11809 AST_LIST_LOCK(&zones);
11810 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11811 free_zone(zcur);
11812 AST_LIST_UNLOCK(&zones);
11813 }
11814
11815 static const char *substitute_escapes(const char *value)
11816 {
11817 char *current;
11818
11819
11820 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11821
11822 ast_str_reset(str);
11823
11824
11825 for (current = (char *) value; *current; current++) {
11826 if (*current == '\\') {
11827 current++;
11828 if (!*current) {
11829 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11830 break;
11831 }
11832 switch (*current) {
11833 case '\\':
11834 ast_str_append(&str, 0, "\\");
11835 break;
11836 case 'r':
11837 ast_str_append(&str, 0, "\r");
11838 break;
11839 case 'n':
11840 #ifdef IMAP_STORAGE
11841 if (!str->used || str->str[str->used - 1] != '\r') {
11842 ast_str_append(&str, 0, "\r");
11843 }
11844 #endif
11845 ast_str_append(&str, 0, "\n");
11846 break;
11847 case 't':
11848 ast_str_append(&str, 0, "\t");
11849 break;
11850 default:
11851 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11852 break;
11853 }
11854 } else {
11855 ast_str_append(&str, 0, "%c", *current);
11856 }
11857 }
11858
11859 return ast_str_buffer(str);
11860 }
11861
11862 static int load_config(int reload)
11863 {
11864 struct ast_config *cfg, *ucfg;
11865 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11866 int res;
11867
11868 ast_unload_realtime("voicemail");
11869 ast_unload_realtime("voicemail_data");
11870
11871 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11872 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11873 return 0;
11874 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11875 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11876 ucfg = NULL;
11877 }
11878 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11879 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11880 ast_config_destroy(ucfg);
11881 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11882 return 0;
11883 }
11884 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11885 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11886 return 0;
11887 } else {
11888 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11889 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11890 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11891 ucfg = NULL;
11892 }
11893 }
11894
11895 res = actual_load_config(reload, cfg, ucfg);
11896
11897 ast_config_destroy(cfg);
11898 ast_config_destroy(ucfg);
11899
11900 return res;
11901 }
11902
11903 #ifdef TEST_FRAMEWORK
11904 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11905 {
11906 ast_unload_realtime("voicemail");
11907 ast_unload_realtime("voicemail_data");
11908 return actual_load_config(reload, cfg, ucfg);
11909 }
11910 #endif
11911
11912 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11913 {
11914 struct ast_vm_user *current;
11915 char *cat;
11916 struct ast_variable *var;
11917 const char *val;
11918 char *q, *stringp, *tmp;
11919 int x;
11920 unsigned int tmpadsi[4];
11921 char secretfn[PATH_MAX] = "";
11922
11923 #ifdef IMAP_STORAGE
11924 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11925 #endif
11926
11927 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11928 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11929 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11930 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11931 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11932
11933
11934 free_vm_users();
11935
11936
11937 free_vm_zones();
11938
11939 AST_LIST_LOCK(&users);
11940
11941 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11942 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11943
11944 if (cfg) {
11945
11946
11947 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11948 val = "default";
11949 ast_copy_string(userscontext, val, sizeof(userscontext));
11950
11951 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11952 val = "yes";
11953 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11954
11955 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11956 val = "no";
11957 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11958
11959 volgain = 0.0;
11960 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11961 sscanf(val, "%30lf", &volgain);
11962
11963 #ifdef ODBC_STORAGE
11964 strcpy(odbc_database, "asterisk");
11965 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11966 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11967 }
11968 strcpy(odbc_table, "voicemessages");
11969 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11970 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11971 }
11972 #endif
11973
11974 strcpy(mailcmd, SENDMAIL);
11975 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11976 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11977
11978 maxsilence = 0;
11979 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11980 maxsilence = atoi(val);
11981 if (maxsilence > 0)
11982 maxsilence *= 1000;
11983 }
11984
11985 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11986 maxmsg = MAXMSG;
11987 } else {
11988 maxmsg = atoi(val);
11989 if (maxmsg < 0) {
11990 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11991 maxmsg = MAXMSG;
11992 } else if (maxmsg > MAXMSGLIMIT) {
11993 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11994 maxmsg = MAXMSGLIMIT;
11995 }
11996 }
11997
11998 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11999 maxdeletedmsg = 0;
12000 } else {
12001 if (sscanf(val, "%30d", &x) == 1)
12002 maxdeletedmsg = x;
12003 else if (ast_true(val))
12004 maxdeletedmsg = MAXMSG;
12005 else
12006 maxdeletedmsg = 0;
12007
12008 if (maxdeletedmsg < 0) {
12009 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
12010 maxdeletedmsg = MAXMSG;
12011 } else if (maxdeletedmsg > MAXMSGLIMIT) {
12012 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12013 maxdeletedmsg = MAXMSGLIMIT;
12014 }
12015 }
12016
12017
12018 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
12019 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
12020 }
12021
12022
12023 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
12024 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
12025 }
12026
12027
12028 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
12029 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12030 pwdchange = PWDCHANGE_EXTERNAL;
12031 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12032 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12033 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12034 }
12035
12036
12037 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12038 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12039 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12040 }
12041
12042 #ifdef IMAP_STORAGE
12043
12044 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12045 ast_copy_string(imapserver, val, sizeof(imapserver));
12046 } else {
12047 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12048 }
12049
12050 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12051 ast_copy_string(imapport, val, sizeof(imapport));
12052 } else {
12053 ast_copy_string(imapport, "143", sizeof(imapport));
12054 }
12055
12056 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12057 ast_copy_string(imapflags, val, sizeof(imapflags));
12058 }
12059
12060 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12061 ast_copy_string(authuser, val, sizeof(authuser));
12062 }
12063
12064 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12065 ast_copy_string(authpassword, val, sizeof(authpassword));
12066 }
12067
12068 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12069 if (ast_false(val))
12070 expungeonhangup = 0;
12071 else
12072 expungeonhangup = 1;
12073 } else {
12074 expungeonhangup = 1;
12075 }
12076
12077 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12078 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12079 } else {
12080 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12081 }
12082 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12083 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12084 }
12085 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12086 imapgreetings = ast_true(val);
12087 } else {
12088 imapgreetings = 0;
12089 }
12090 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12091 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12092 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12093
12094 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12095 } else {
12096 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12097 }
12098
12099
12100
12101
12102
12103 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12104 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12105 } else {
12106 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12107 }
12108
12109 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12110 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12111 } else {
12112 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12113 }
12114
12115 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12116 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12117 } else {
12118 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12119 }
12120
12121 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12122 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12123 } else {
12124 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12125 }
12126
12127
12128 imapversion++;
12129 #endif
12130
12131 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12132 ast_copy_string(externnotify, val, sizeof(externnotify));
12133 ast_debug(1, "found externnotify: %s\n", externnotify);
12134 } else {
12135 externnotify[0] = '\0';
12136 }
12137
12138
12139 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12140 ast_debug(1, "Enabled SMDI voicemail notification\n");
12141 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12142 smdi_iface = ast_smdi_interface_find(val);
12143 } else {
12144 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12145 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12146 }
12147 if (!smdi_iface) {
12148 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12149 }
12150 }
12151
12152
12153 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12154 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12155 silencethreshold = atoi(val);
12156
12157 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12158 val = ASTERISK_USERNAME;
12159 ast_copy_string(serveremail, val, sizeof(serveremail));
12160
12161 vmmaxsecs = 0;
12162 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12163 if (sscanf(val, "%30d", &x) == 1) {
12164 vmmaxsecs = x;
12165 } else {
12166 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12167 }
12168 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12169 static int maxmessage_deprecate = 0;
12170 if (maxmessage_deprecate == 0) {
12171 maxmessage_deprecate = 1;
12172 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12173 }
12174 if (sscanf(val, "%30d", &x) == 1) {
12175 vmmaxsecs = x;
12176 } else {
12177 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12178 }
12179 }
12180
12181 vmminsecs = 0;
12182 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12183 if (sscanf(val, "%30d", &x) == 1) {
12184 vmminsecs = x;
12185 if (maxsilence / 1000 >= vmminsecs) {
12186 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12187 }
12188 } else {
12189 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12190 }
12191 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12192 static int maxmessage_deprecate = 0;
12193 if (maxmessage_deprecate == 0) {
12194 maxmessage_deprecate = 1;
12195 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12196 }
12197 if (sscanf(val, "%30d", &x) == 1) {
12198 vmminsecs = x;
12199 if (maxsilence / 1000 >= vmminsecs) {
12200 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12201 }
12202 } else {
12203 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12204 }
12205 }
12206
12207 val = ast_variable_retrieve(cfg, "general", "format");
12208 if (!val) {
12209 val = "wav";
12210 } else {
12211 tmp = ast_strdupa(val);
12212 val = ast_format_str_reduce(tmp);
12213 if (!val) {
12214 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12215 val = "wav";
12216 }
12217 }
12218 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12219
12220 skipms = 3000;
12221 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12222 if (sscanf(val, "%30d", &x) == 1) {
12223 maxgreet = x;
12224 } else {
12225 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12226 }
12227 }
12228
12229 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12230 if (sscanf(val, "%30d", &x) == 1) {
12231 skipms = x;
12232 } else {
12233 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12234 }
12235 }
12236
12237 maxlogins = 3;
12238 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12239 if (sscanf(val, "%30d", &x) == 1) {
12240 maxlogins = x;
12241 } else {
12242 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12243 }
12244 }
12245
12246 minpassword = MINPASSWORD;
12247 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12248 if (sscanf(val, "%30d", &x) == 1) {
12249 minpassword = x;
12250 } else {
12251 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12252 }
12253 }
12254
12255
12256 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12257 val = "no";
12258 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12259
12260
12261 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12262 val = "no";
12263 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12264
12265 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12266 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12267 stringp = ast_strdupa(val);
12268 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12269 if (!ast_strlen_zero(stringp)) {
12270 q = strsep(&stringp, ",");
12271 while ((*q == ' ')||(*q == '\t'))
12272 q++;
12273 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12274 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12275 } else {
12276 cidinternalcontexts[x][0] = '\0';
12277 }
12278 }
12279 }
12280 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12281 ast_debug(1, "VM Review Option disabled globally\n");
12282 val = "no";
12283 }
12284 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12285
12286
12287 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12288 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12289 val = "no";
12290 } else {
12291 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12292 }
12293 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12294 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12295 ast_debug(1, "VM next message wrap disabled globally\n");
12296 val = "no";
12297 }
12298 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12299
12300 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12301 ast_debug(1, "VM Operator break disabled globally\n");
12302 val = "no";
12303 }
12304 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12305
12306 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12307 ast_debug(1, "VM CID Info before msg disabled globally\n");
12308 val = "no";
12309 }
12310 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12311
12312 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12313 ast_debug(1, "Send Voicemail msg disabled globally\n");
12314 val = "no";
12315 }
12316 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12317
12318 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12319 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12320 val = "yes";
12321 }
12322 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12323
12324 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12325 ast_debug(1, "Move Heard enabled globally\n");
12326 val = "yes";
12327 }
12328 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12329
12330 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12331 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12332 val = "no";
12333 }
12334 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12335
12336 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12337 ast_debug(1, "Duration info before msg enabled globally\n");
12338 val = "yes";
12339 }
12340 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12341
12342 saydurationminfo = 2;
12343 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12344 if (sscanf(val, "%30d", &x) == 1) {
12345 saydurationminfo = x;
12346 } else {
12347 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12348 }
12349 }
12350
12351 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12352 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12353 val = "no";
12354 }
12355 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12356
12357 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12358 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12359 ast_debug(1, "found dialout context: %s\n", dialcontext);
12360 } else {
12361 dialcontext[0] = '\0';
12362 }
12363
12364 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12365 ast_copy_string(callcontext, val, sizeof(callcontext));
12366 ast_debug(1, "found callback context: %s\n", callcontext);
12367 } else {
12368 callcontext[0] = '\0';
12369 }
12370
12371 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12372 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12373 ast_debug(1, "found operator context: %s\n", exitcontext);
12374 } else {
12375 exitcontext[0] = '\0';
12376 }
12377
12378
12379 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12380 ast_copy_string(vm_password, val, sizeof(vm_password));
12381 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12382 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12383 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12384 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12385 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12386 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12387 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12388 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12389 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12390 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12391 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12392 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12393 }
12394 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12395 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12396 }
12397
12398 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12399 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12400 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12401 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12402 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12403 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12404 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12405 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12406 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12407 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12408
12409 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12410 val = "no";
12411 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12412
12413 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12414 val = "voicemail.conf";
12415 }
12416 if (!(strcmp(val, "spooldir"))) {
12417 passwordlocation = OPT_PWLOC_SPOOLDIR;
12418 } else {
12419 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12420 }
12421
12422 poll_freq = DEFAULT_POLL_FREQ;
12423 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12424 if (sscanf(val, "%30u", &poll_freq) != 1) {
12425 poll_freq = DEFAULT_POLL_FREQ;
12426 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12427 }
12428 }
12429
12430 poll_mailboxes = 0;
12431 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12432 poll_mailboxes = ast_true(val);
12433
12434 memset(fromstring, 0, sizeof(fromstring));
12435 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12436 strcpy(charset, "ISO-8859-1");
12437 if (emailbody) {
12438 ast_free(emailbody);
12439 emailbody = NULL;
12440 }
12441 if (emailsubject) {
12442 ast_free(emailsubject);
12443 emailsubject = NULL;
12444 }
12445 if (pagerbody) {
12446 ast_free(pagerbody);
12447 pagerbody = NULL;
12448 }
12449 if (pagersubject) {
12450 ast_free(pagersubject);
12451 pagersubject = NULL;
12452 }
12453 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12454 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12455 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12456 ast_copy_string(fromstring, val, sizeof(fromstring));
12457 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12458 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12459 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12460 ast_copy_string(charset, val, sizeof(charset));
12461 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12462 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12463 for (x = 0; x < 4; x++) {
12464 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12465 }
12466 }
12467 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12468 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12469 for (x = 0; x < 4; x++) {
12470 memcpy(&adsisec[x], &tmpadsi[x], 1);
12471 }
12472 }
12473 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12474 if (atoi(val)) {
12475 adsiver = atoi(val);
12476 }
12477 }
12478 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12479 ast_copy_string(zonetag, val, sizeof(zonetag));
12480 }
12481 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12482 ast_copy_string(locale, val, sizeof(locale));
12483 }
12484 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12485 emailsubject = ast_strdup(substitute_escapes(val));
12486 }
12487 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12488 emailbody = ast_strdup(substitute_escapes(val));
12489 }
12490 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12491 pagersubject = ast_strdup(substitute_escapes(val));
12492 }
12493 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12494 pagerbody = ast_strdup(substitute_escapes(val));
12495 }
12496
12497
12498 if (ucfg) {
12499 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12500 if (!strcasecmp(cat, "general")) {
12501 continue;
12502 }
12503 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12504 continue;
12505 if ((current = find_or_create(userscontext, cat))) {
12506 populate_defaults(current);
12507 apply_options_full(current, ast_variable_browse(ucfg, cat));
12508 ast_copy_string(current->context, userscontext, sizeof(current->context));
12509 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12510 current->passwordlocation = OPT_PWLOC_USERSCONF;
12511 }
12512
12513 switch (current->passwordlocation) {
12514 case OPT_PWLOC_SPOOLDIR:
12515 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12516 read_password_from_file(secretfn, current->password, sizeof(current->password));
12517 }
12518 }
12519 }
12520 }
12521
12522
12523 cat = ast_category_browse(cfg, NULL);
12524 while (cat) {
12525 if (strcasecmp(cat, "general")) {
12526 var = ast_variable_browse(cfg, cat);
12527 if (strcasecmp(cat, "zonemessages")) {
12528
12529 while (var) {
12530 append_mailbox(cat, var->name, var->value);
12531 var = var->next;
12532 }
12533 } else {
12534
12535 while (var) {
12536 struct vm_zone *z;
12537 if ((z = ast_malloc(sizeof(*z)))) {
12538 char *msg_format, *tzone;
12539 msg_format = ast_strdupa(var->value);
12540 tzone = strsep(&msg_format, "|,");
12541 if (msg_format) {
12542 ast_copy_string(z->name, var->name, sizeof(z->name));
12543 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12544 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12545 AST_LIST_LOCK(&zones);
12546 AST_LIST_INSERT_HEAD(&zones, z, list);
12547 AST_LIST_UNLOCK(&zones);
12548 } else {
12549 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12550 ast_free(z);
12551 }
12552 } else {
12553 AST_LIST_UNLOCK(&users);
12554 return -1;
12555 }
12556 var = var->next;
12557 }
12558 }
12559 }
12560 cat = ast_category_browse(cfg, cat);
12561 }
12562
12563 AST_LIST_UNLOCK(&users);
12564
12565 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12566 start_poll_thread();
12567 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12568 stop_poll_thread();;
12569
12570 return 0;
12571 } else {
12572 AST_LIST_UNLOCK(&users);
12573 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12574 return 0;
12575 }
12576 }
12577
12578 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12579 {
12580 int res = -1;
12581 char dir[PATH_MAX];
12582 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12583 ast_debug(2, "About to try retrieving name file %s\n", dir);
12584 RETRIEVE(dir, -1, mailbox, context);
12585 if (ast_fileexists(dir, NULL, NULL)) {
12586 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12587 }
12588 DISPOSE(dir, -1);
12589 return res;
12590 }
12591
12592 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12593 struct ast_config *pwconf;
12594 struct ast_flags config_flags = { 0 };
12595
12596 pwconf = ast_config_load(secretfn, config_flags);
12597 if (valid_config(pwconf)) {
12598 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12599 if (val) {
12600 ast_copy_string(password, val, passwordlen);
12601 ast_config_destroy(pwconf);
12602 return;
12603 }
12604 ast_config_destroy(pwconf);
12605 }
12606 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12607 }
12608
12609 static int write_password_to_file(const char *secretfn, const char *password) {
12610 struct ast_config *conf;
12611 struct ast_category *cat;
12612 struct ast_variable *var;
12613 int res = -1;
12614
12615 if (!(conf = ast_config_new())) {
12616 ast_log(LOG_ERROR, "Error creating new config structure\n");
12617 return res;
12618 }
12619 if (!(cat = ast_category_new("general", "", 1))) {
12620 ast_log(LOG_ERROR, "Error creating new category structure\n");
12621 ast_config_destroy(conf);
12622 return res;
12623 }
12624 if (!(var = ast_variable_new("password", password, ""))) {
12625 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12626 ast_config_destroy(conf);
12627 ast_category_destroy(cat);
12628 return res;
12629 }
12630 ast_category_append(conf, cat);
12631 ast_variable_append(cat, var);
12632 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12633 res = 0;
12634 } else {
12635 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12636 }
12637
12638 ast_config_destroy(conf);
12639 return res;
12640 }
12641
12642 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12643 {
12644 char *context;
12645 char *args_copy;
12646 int res;
12647
12648 if (ast_strlen_zero(data)) {
12649 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12650 return -1;
12651 }
12652
12653 args_copy = ast_strdupa(data);
12654 if ((context = strchr(args_copy, '@'))) {
12655 *context++ = '\0';
12656 } else {
12657 context = "default";
12658 }
12659
12660 if ((res = sayname(chan, args_copy, context) < 0)) {
12661 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12662 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12663 if (!res) {
12664 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12665 }
12666 }
12667
12668 return res;
12669 }
12670
12671 #ifdef TEST_FRAMEWORK
12672 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12673 {
12674 return 0;
12675 }
12676
12677 static struct ast_frame *fake_read(struct ast_channel *ast)
12678 {
12679 return &ast_null_frame;
12680 }
12681
12682 AST_TEST_DEFINE(test_voicemail_vmsayname)
12683 {
12684 char dir[PATH_MAX];
12685 char dir2[PATH_MAX];
12686 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12687 static const char TEST_EXTENSION[] = "1234";
12688
12689 struct ast_channel *test_channel1 = NULL;
12690 int res = -1;
12691
12692 static const struct ast_channel_tech fake_tech = {
12693 .write = fake_write,
12694 .read = fake_read,
12695 };
12696
12697 switch (cmd) {
12698 case TEST_INIT:
12699 info->name = "vmsayname_exec";
12700 info->category = "/apps/app_voicemail/";
12701 info->summary = "Vmsayname unit test";
12702 info->description =
12703 "This tests passing various parameters to vmsayname";
12704 return AST_TEST_NOT_RUN;
12705 case TEST_EXECUTE:
12706 break;
12707 }
12708
12709 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12710 NULL, NULL, 0, 0, "TestChannel1"))) {
12711 goto exit_vmsayname_test;
12712 }
12713
12714
12715 test_channel1->nativeformats = AST_FORMAT_GSM;
12716 test_channel1->writeformat = AST_FORMAT_GSM;
12717 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12718 test_channel1->readformat = AST_FORMAT_GSM;
12719 test_channel1->rawreadformat = AST_FORMAT_GSM;
12720 test_channel1->tech = &fake_tech;
12721
12722 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12723 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12724 if (!(res = vmsayname_exec(test_channel1, dir))) {
12725 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12726 if (ast_fileexists(dir, NULL, NULL)) {
12727 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12728 res = -1;
12729 goto exit_vmsayname_test;
12730 } else {
12731
12732 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12733 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12734 goto exit_vmsayname_test;
12735 }
12736 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12737 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12738
12739 if ((res = symlink(dir, dir2))) {
12740 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12741 goto exit_vmsayname_test;
12742 }
12743 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12744 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12745 res = vmsayname_exec(test_channel1, dir);
12746
12747
12748 unlink(dir2);
12749 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12750 rmdir(dir2);
12751 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12752 rmdir(dir2);
12753 }
12754 }
12755
12756 exit_vmsayname_test:
12757
12758 if (test_channel1) {
12759 ast_hangup(test_channel1);
12760 }
12761
12762 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12763 }
12764
12765 AST_TEST_DEFINE(test_voicemail_msgcount)
12766 {
12767 int i, j, res = AST_TEST_PASS, syserr;
12768 struct ast_vm_user *vmu;
12769 struct ast_vm_user svm;
12770 struct vm_state vms;
12771 #ifdef IMAP_STORAGE
12772 struct ast_channel *chan = NULL;
12773 #endif
12774 struct {
12775 char dir[256];
12776 char file[256];
12777 char txtfile[256];
12778 } tmp[3];
12779 char syscmd[256];
12780 const char origweasels[] = "tt-weasels";
12781 const char testcontext[] = "test";
12782 const char testmailbox[] = "00000000";
12783 const char testspec[] = "00000000@test";
12784 FILE *txt;
12785 int new, old, urgent;
12786 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12787 const int folder2mbox[3] = { 1, 11, 0 };
12788 const int expected_results[3][12] = {
12789
12790 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12791 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12792 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12793 };
12794
12795 switch (cmd) {
12796 case TEST_INIT:
12797 info->name = "test_voicemail_msgcount";
12798 info->category = "/apps/app_voicemail/";
12799 info->summary = "Test Voicemail status checks";
12800 info->description =
12801 "Verify that message counts are correct when retrieved through the public API";
12802 return AST_TEST_NOT_RUN;
12803 case TEST_EXECUTE:
12804 break;
12805 }
12806
12807
12808 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12809 if ((syserr = ast_safe_system(syscmd))) {
12810 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12811 syserr > 0 ? strerror(syserr) : "unable to fork()");
12812 return AST_TEST_FAIL;
12813 }
12814
12815 #ifdef IMAP_STORAGE
12816 if (!(chan = ast_dummy_channel_alloc())) {
12817 ast_test_status_update(test, "Unable to create dummy channel\n");
12818 return AST_TEST_FAIL;
12819 }
12820 #endif
12821
12822 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12823 !(vmu = find_or_create(testcontext, testmailbox))) {
12824 ast_test_status_update(test, "Cannot create vmu structure\n");
12825 ast_unreplace_sigchld();
12826 #ifdef IMAP_STORAGE
12827 chan = ast_channel_unref(chan);
12828 #endif
12829 return AST_TEST_FAIL;
12830 }
12831
12832 populate_defaults(vmu);
12833 memset(&vms, 0, sizeof(vms));
12834
12835
12836 for (i = 0; i < 3; i++) {
12837 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12838 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12839 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12840
12841 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12842 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12843 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12844 if ((syserr = ast_safe_system(syscmd))) {
12845 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12846 syserr > 0 ? strerror(syserr) : "unable to fork()");
12847 ast_unreplace_sigchld();
12848 #ifdef IMAP_STORAGE
12849 chan = ast_channel_unref(chan);
12850 #endif
12851 return AST_TEST_FAIL;
12852 }
12853 }
12854
12855 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12856 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12857 fclose(txt);
12858 } else {
12859 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12860 res = AST_TEST_FAIL;
12861 break;
12862 }
12863 open_mailbox(&vms, vmu, folder2mbox[i]);
12864 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12865
12866
12867 for (j = 0; j < 3; j++) {
12868
12869 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12870 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12871 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12872 res = AST_TEST_FAIL;
12873 }
12874 }
12875
12876 new = old = urgent = 0;
12877 if (ast_app_inboxcount(testspec, &new, &old)) {
12878 ast_test_status_update(test, "inboxcount returned failure\n");
12879 res = AST_TEST_FAIL;
12880 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12881 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12882 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12883 res = AST_TEST_FAIL;
12884 }
12885
12886 new = old = urgent = 0;
12887 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12888 ast_test_status_update(test, "inboxcount2 returned failure\n");
12889 res = AST_TEST_FAIL;
12890 } else if (old != expected_results[i][6 + 0] ||
12891 urgent != expected_results[i][6 + 1] ||
12892 new != expected_results[i][6 + 2] ) {
12893 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12894 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12895 res = AST_TEST_FAIL;
12896 }
12897
12898 new = old = urgent = 0;
12899 for (j = 0; j < 3; j++) {
12900 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12901 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12902 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12903 res = AST_TEST_FAIL;
12904 }
12905 }
12906 }
12907
12908 for (i = 0; i < 3; i++) {
12909
12910
12911
12912 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12913 DISPOSE(tmp[i].dir, 0);
12914 }
12915
12916 if (vms.deleted) {
12917 ast_free(vms.deleted);
12918 }
12919 if (vms.heard) {
12920 ast_free(vms.heard);
12921 }
12922
12923 #ifdef IMAP_STORAGE
12924 chan = ast_channel_unref(chan);
12925 #endif
12926
12927
12928 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12929 if ((syserr = ast_safe_system(syscmd))) {
12930 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12931 syserr > 0 ? strerror(syserr) : "unable to fork()");
12932 }
12933
12934 return res;
12935 }
12936
12937 AST_TEST_DEFINE(test_voicemail_notify_endl)
12938 {
12939 int res = AST_TEST_PASS;
12940 char testcontext[] = "test";
12941 char testmailbox[] = "00000000";
12942 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12943 char attach[256], attach2[256];
12944 char buf[256] = "";
12945 struct ast_channel *chan = NULL;
12946 struct ast_vm_user *vmu, vmus = {
12947 .flags = 0,
12948 };
12949 FILE *file;
12950 struct {
12951 char *name;
12952 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12953 void *location;
12954 union {
12955 int intval;
12956 char *strval;
12957 } u;
12958 } test_items[] = {
12959 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12960 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12961 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12962 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12963 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12964 { "attach2", STRPTR, attach2, .u.strval = "" },
12965 { "attach", STRPTR, attach, .u.strval = "" },
12966 };
12967 int which;
12968
12969 switch (cmd) {
12970 case TEST_INIT:
12971 info->name = "test_voicemail_notify_endl";
12972 info->category = "/apps/app_voicemail/";
12973 info->summary = "Test Voicemail notification end-of-line";
12974 info->description =
12975 "Verify that notification emails use a consistent end-of-line character";
12976 return AST_TEST_NOT_RUN;
12977 case TEST_EXECUTE:
12978 break;
12979 }
12980
12981 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12982 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12983
12984 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12985 !(vmu = find_or_create(testcontext, testmailbox))) {
12986 ast_test_status_update(test, "Cannot create vmu structure\n");
12987 return AST_TEST_NOT_RUN;
12988 }
12989
12990 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12991 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12992 return AST_TEST_NOT_RUN;
12993 }
12994
12995 populate_defaults(vmu);
12996 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12997 #ifdef IMAP_STORAGE
12998
12999 #endif
13000
13001 file = tmpfile();
13002 for (which = 0; which < ARRAY_LEN(test_items); which++) {
13003
13004 rewind(file);
13005 if (ftruncate(fileno(file), 0)) {
13006 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
13007 res = AST_TEST_FAIL;
13008 break;
13009 }
13010
13011
13012 if (test_items[which].type == INT) {
13013 *((int *) test_items[which].location) = test_items[which].u.intval;
13014 } else if (test_items[which].type == FLAGVAL) {
13015 if (ast_test_flag(vmu, test_items[which].u.intval)) {
13016 ast_clear_flag(vmu, test_items[which].u.intval);
13017 } else {
13018 ast_set_flag(vmu, test_items[which].u.intval);
13019 }
13020 } else if (test_items[which].type == STATIC) {
13021 strcpy(test_items[which].location, test_items[which].u.strval);
13022 } else if (test_items[which].type == STRPTR) {
13023 test_items[which].location = test_items[which].u.strval;
13024 }
13025
13026 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
13027 rewind(file);
13028 while (fgets(buf, sizeof(buf), file)) {
13029 if (
13030 #ifdef IMAP_STORAGE
13031 buf[strlen(buf) - 2] != '\r'
13032 #else
13033 buf[strlen(buf) - 2] == '\r'
13034 #endif
13035 || buf[strlen(buf) - 1] != '\n') {
13036 res = AST_TEST_FAIL;
13037 }
13038 }
13039 }
13040 fclose(file);
13041 return res;
13042 }
13043
13044 AST_TEST_DEFINE(test_voicemail_load_config)
13045 {
13046 int res = AST_TEST_PASS;
13047 struct ast_vm_user *vmu;
13048 struct ast_config *cfg;
13049 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13050 int fd;
13051 FILE *file;
13052 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13053
13054 switch (cmd) {
13055 case TEST_INIT:
13056 info->name = "test_voicemail_load_config";
13057 info->category = "/apps/app_voicemail/";
13058 info->summary = "Test loading Voicemail config";
13059 info->description =
13060 "Verify that configuration is loaded consistently. "
13061 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13062 "some options were loaded after the mailboxes were instantiated, causing "
13063 "those options not to be set correctly.";
13064 return AST_TEST_NOT_RUN;
13065 case TEST_EXECUTE:
13066 break;
13067 }
13068
13069
13070 if ((fd = mkstemp(config_filename)) < 0) {
13071 return AST_TEST_FAIL;
13072 }
13073 if (!(file = fdopen(fd, "w"))) {
13074 close(fd);
13075 unlink(config_filename);
13076 return AST_TEST_FAIL;
13077 }
13078 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13079 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13080 fputs("00000002 => 9999,Mrs. Test\n", file);
13081 fclose(file);
13082
13083 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
13084 res = AST_TEST_FAIL;
13085 goto cleanup;
13086 }
13087
13088 load_config_from_memory(1, cfg, NULL);
13089 ast_config_destroy(cfg);
13090
13091 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13092 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13093 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13094
13095 AST_LIST_LOCK(&users);
13096 AST_LIST_TRAVERSE(&users, vmu, list) {
13097 if (!strcmp(vmu->mailbox, "00000001")) {
13098 if (0);
13099 CHECK(vmu, callback, "othercontext")
13100 CHECK(vmu, locale, "nl_NL.UTF-8")
13101 CHECK(vmu, zonetag, "central")
13102 } else if (!strcmp(vmu->mailbox, "00000002")) {
13103 if (0);
13104 CHECK(vmu, callback, "somecontext")
13105 CHECK(vmu, locale, "de_DE.UTF-8")
13106 CHECK(vmu, zonetag, "european")
13107 }
13108 }
13109 AST_LIST_UNLOCK(&users);
13110
13111 #undef CHECK
13112
13113
13114 load_config(1);
13115
13116 cleanup:
13117 unlink(config_filename);
13118 return res;
13119 }
13120
13121 #endif
13122
13123 static int reload(void)
13124 {
13125 return load_config(1);
13126 }
13127
13128 static int unload_module(void)
13129 {
13130 int res;
13131
13132 res = ast_unregister_application(app);
13133 res |= ast_unregister_application(app2);
13134 res |= ast_unregister_application(app3);
13135 res |= ast_unregister_application(app4);
13136 res |= ast_unregister_application(sayname_app);
13137 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13138 res |= ast_manager_unregister("VoicemailUsersList");
13139 res |= ast_data_unregister(NULL);
13140 #ifdef TEST_FRAMEWORK
13141 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13142 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13143 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13144 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13145 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13146 #endif
13147 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13148 ast_uninstall_vm_functions();
13149 ao2_ref(inprocess_container, -1);
13150
13151 if (poll_thread != AST_PTHREADT_NULL)
13152 stop_poll_thread();
13153
13154 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13155 ast_unload_realtime("voicemail");
13156 ast_unload_realtime("voicemail_data");
13157
13158 free_vm_users();
13159 free_vm_zones();
13160 return res;
13161 }
13162
13163 static int load_module(void)
13164 {
13165 int res;
13166 my_umask = umask(0);
13167 umask(my_umask);
13168
13169 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13170 return AST_MODULE_LOAD_DECLINE;
13171 }
13172
13173
13174 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13175
13176 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13177 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13178 }
13179
13180 if ((res = load_config(0)))
13181 return res;
13182
13183 res = ast_register_application_xml(app, vm_exec);
13184 res |= ast_register_application_xml(app2, vm_execmain);
13185 res |= ast_register_application_xml(app3, vm_box_exists);
13186 res |= ast_register_application_xml(app4, vmauthenticate);
13187 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13188 res |= ast_custom_function_register(&mailbox_exists_acf);
13189 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13190 #ifdef TEST_FRAMEWORK
13191 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13192 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13193 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13194 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13195 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13196 #endif
13197
13198 if (res)
13199 return res;
13200
13201 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13202 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13203
13204 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13205 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13206 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13207
13208 return res;
13209 }
13210
13211 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13212 {
13213 int cmd = 0;
13214 char destination[80] = "";
13215 int retries = 0;
13216
13217 if (!num) {
13218 ast_verb(3, "Destination number will be entered manually\n");
13219 while (retries < 3 && cmd != 't') {
13220 destination[1] = '\0';
13221 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13222 if (!cmd)
13223 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13224 if (!cmd)
13225 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13226 if (!cmd) {
13227 cmd = ast_waitfordigit(chan, 6000);
13228 if (cmd)
13229 destination[0] = cmd;
13230 }
13231 if (!cmd) {
13232 retries++;
13233 } else {
13234
13235 if (cmd < 0)
13236 return 0;
13237 if (cmd == '*') {
13238 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13239 return 0;
13240 }
13241 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13242 retries++;
13243 else
13244 cmd = 't';
13245 }
13246 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13247 }
13248 if (retries >= 3) {
13249 return 0;
13250 }
13251
13252 } else {
13253 if (option_verbose > 2)
13254 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13255 ast_copy_string(destination, num, sizeof(destination));
13256 }
13257
13258 if (!ast_strlen_zero(destination)) {
13259 if (destination[strlen(destination) -1 ] == '*')
13260 return 0;
13261 if (option_verbose > 2)
13262 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13263 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13264 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13265 chan->priority = 0;
13266 return 9;
13267 }
13268 return 0;
13269 }
13270
13271
13272
13273
13274
13275
13276
13277
13278
13279
13280
13281
13282
13283
13284 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)
13285 {
13286 int res = 0;
13287 char filename[PATH_MAX];
13288 struct ast_config *msg_cfg = NULL;
13289 const char *origtime, *context;
13290 char *name, *num;
13291 int retries = 0;
13292 char *cid;
13293 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13294
13295 vms->starting = 0;
13296
13297 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13298
13299
13300 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13301 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13302 msg_cfg = ast_config_load(filename, config_flags);
13303 DISPOSE(vms->curdir, vms->curmsg);
13304 if (!valid_config(msg_cfg)) {
13305 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13306 return 0;
13307 }
13308
13309 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13310 ast_config_destroy(msg_cfg);
13311 return 0;
13312 }
13313
13314 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13315
13316 context = ast_variable_retrieve(msg_cfg, "message", "context");
13317 if (!strncasecmp("macro", context, 5))
13318 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13319 switch (option) {
13320 case 3:
13321 if (!res)
13322 res = play_message_datetime(chan, vmu, origtime, filename);
13323 if (!res)
13324 res = play_message_callerid(chan, vms, cid, context, 0);
13325
13326 res = 't';
13327 break;
13328
13329 case 2:
13330
13331 if (ast_strlen_zero(cid))
13332 break;
13333
13334 ast_callerid_parse(cid, &name, &num);
13335 while ((res > -1) && (res != 't')) {
13336 switch (res) {
13337 case '1':
13338 if (num) {
13339
13340 res = dialout(chan, vmu, num, vmu->callback);
13341 if (res) {
13342 ast_config_destroy(msg_cfg);
13343 return 9;
13344 }
13345 } else {
13346 res = '2';
13347 }
13348 break;
13349
13350 case '2':
13351
13352 if (!ast_strlen_zero(vmu->dialout)) {
13353 res = dialout(chan, vmu, NULL, vmu->dialout);
13354 if (res) {
13355 ast_config_destroy(msg_cfg);
13356 return 9;
13357 }
13358 } else {
13359 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13360 res = ast_play_and_wait(chan, "vm-sorry");
13361 }
13362 ast_config_destroy(msg_cfg);
13363 return res;
13364 case '*':
13365 res = 't';
13366 break;
13367 case '3':
13368 case '4':
13369 case '5':
13370 case '6':
13371 case '7':
13372 case '8':
13373 case '9':
13374 case '0':
13375
13376 res = ast_play_and_wait(chan, "vm-sorry");
13377 retries++;
13378 break;
13379 default:
13380 if (num) {
13381 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13382 res = ast_play_and_wait(chan, "vm-num-i-have");
13383 if (!res)
13384 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13385 if (!res)
13386 res = ast_play_and_wait(chan, "vm-tocallnum");
13387
13388 if (!ast_strlen_zero(vmu->dialout)) {
13389 if (!res)
13390 res = ast_play_and_wait(chan, "vm-calldiffnum");
13391 }
13392 } else {
13393 res = ast_play_and_wait(chan, "vm-nonumber");
13394 if (!ast_strlen_zero(vmu->dialout)) {
13395 if (!res)
13396 res = ast_play_and_wait(chan, "vm-toenternumber");
13397 }
13398 }
13399 if (!res) {
13400 res = ast_play_and_wait(chan, "vm-star-cancel");
13401 }
13402 if (!res) {
13403 res = ast_waitfordigit(chan, 6000);
13404 }
13405 if (!res) {
13406 retries++;
13407 if (retries > 3) {
13408 res = 't';
13409 }
13410 }
13411 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13412 break;
13413
13414 }
13415 if (res == 't')
13416 res = 0;
13417 else if (res == '*')
13418 res = -1;
13419 }
13420 break;
13421
13422 case 1:
13423
13424 if (ast_strlen_zero(cid))
13425 break;
13426
13427 ast_callerid_parse(cid, &name, &num);
13428 if (!num) {
13429 ast_verb(3, "No CID number available, no reply sent\n");
13430 if (!res)
13431 res = ast_play_and_wait(chan, "vm-nonumber");
13432 ast_config_destroy(msg_cfg);
13433 return res;
13434 } else {
13435 struct ast_vm_user vmu2;
13436 if (find_user(&vmu2, vmu->context, num)) {
13437 struct leave_vm_options leave_options;
13438 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13439 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13440
13441 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13442
13443 memset(&leave_options, 0, sizeof(leave_options));
13444 leave_options.record_gain = record_gain;
13445 res = leave_voicemail(chan, mailbox, &leave_options);
13446 if (!res)
13447 res = 't';
13448 ast_config_destroy(msg_cfg);
13449 return res;
13450 } else {
13451
13452 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13453 ast_play_and_wait(chan, "vm-nobox");
13454 res = 't';
13455 ast_config_destroy(msg_cfg);
13456 return res;
13457 }
13458 }
13459 res = 0;
13460
13461 break;
13462 }
13463
13464 ast_config_destroy(msg_cfg);
13465
13466 #ifndef IMAP_STORAGE
13467 if (!res) {
13468 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13469 vms->heard[msg] = 1;
13470 res = wait_file(chan, vms, vms->fn);
13471 }
13472 #endif
13473 return res;
13474 }
13475
13476 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13477 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13478 signed char record_gain, struct vm_state *vms, char *flag)
13479 {
13480
13481 int res = 0;
13482 int cmd = 0;
13483 int max_attempts = 3;
13484 int attempts = 0;
13485 int recorded = 0;
13486 int msg_exists = 0;
13487 signed char zero_gain = 0;
13488 char tempfile[PATH_MAX];
13489 char *acceptdtmf = "#";
13490 char *canceldtmf = "";
13491 int canceleddtmf = 0;
13492
13493
13494
13495
13496 if (duration == NULL) {
13497 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13498 return -1;
13499 }
13500
13501 if (!outsidecaller)
13502 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13503 else
13504 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13505
13506 cmd = '3';
13507
13508 while ((cmd >= 0) && (cmd != 't')) {
13509 switch (cmd) {
13510 case '1':
13511 if (!msg_exists) {
13512
13513 cmd = '3';
13514 break;
13515 } else {
13516
13517 ast_verb(3, "Saving message as is\n");
13518 if (!outsidecaller)
13519 ast_filerename(tempfile, recordfile, NULL);
13520 ast_stream_and_wait(chan, "vm-msgsaved", "");
13521 if (!outsidecaller) {
13522
13523 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13524 DISPOSE(recordfile, -1);
13525 }
13526 cmd = 't';
13527 return res;
13528 }
13529 case '2':
13530
13531 ast_verb(3, "Reviewing the message\n");
13532 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13533 break;
13534 case '3':
13535 msg_exists = 0;
13536
13537 if (recorded == 1)
13538 ast_verb(3, "Re-recording the message\n");
13539 else
13540 ast_verb(3, "Recording the message\n");
13541
13542 if (recorded && outsidecaller) {
13543 cmd = ast_play_and_wait(chan, INTRO);
13544 cmd = ast_play_and_wait(chan, "beep");
13545 }
13546 recorded = 1;
13547
13548 if (record_gain)
13549 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13550 if (ast_test_flag(vmu, VM_OPERATOR))
13551 canceldtmf = "0";
13552 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13553 if (strchr(canceldtmf, cmd)) {
13554
13555 canceleddtmf = 1;
13556 }
13557 if (record_gain)
13558 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13559 if (cmd == -1) {
13560
13561 if (!outsidecaller) {
13562
13563 ast_filedelete(tempfile, NULL);
13564 }
13565 return cmd;
13566 }
13567 if (cmd == '0') {
13568 break;
13569 } else if (cmd == '*') {
13570 break;
13571 #if 0
13572 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13573
13574 ast_verb(3, "Message too short\n");
13575 cmd = ast_play_and_wait(chan, "vm-tooshort");
13576 cmd = ast_filedelete(tempfile, NULL);
13577 break;
13578 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13579
13580 ast_verb(3, "Nothing recorded\n");
13581 cmd = ast_filedelete(tempfile, NULL);
13582 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13583 if (!cmd)
13584 cmd = ast_play_and_wait(chan, "vm-speakup");
13585 break;
13586 #endif
13587 } else {
13588
13589 msg_exists = 1;
13590 cmd = 0;
13591 }
13592 break;
13593 case '4':
13594 if (outsidecaller) {
13595
13596 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13597 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13598 res = ast_play_and_wait(chan, "vm-marked-urgent");
13599 strcpy(flag, "Urgent");
13600 } else if (flag) {
13601 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13602 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13603 strcpy(flag, "");
13604 } else {
13605 ast_play_and_wait(chan, "vm-sorry");
13606 }
13607 cmd = 0;
13608 } else {
13609 cmd = ast_play_and_wait(chan, "vm-sorry");
13610 }
13611 break;
13612 case '5':
13613 case '6':
13614 case '7':
13615 case '8':
13616 case '9':
13617 case '*':
13618 case '#':
13619 cmd = ast_play_and_wait(chan, "vm-sorry");
13620 break;
13621 #if 0
13622
13623
13624 case '*':
13625
13626 cmd = ast_play_and_wait(chan, "vm-deleted");
13627 cmd = ast_filedelete(tempfile, NULL);
13628 if (outsidecaller) {
13629 res = vm_exec(chan, NULL);
13630 return res;
13631 }
13632 else
13633 return 1;
13634 #endif
13635 case '0':
13636 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13637 cmd = ast_play_and_wait(chan, "vm-sorry");
13638 break;
13639 }
13640 if (msg_exists || recorded) {
13641 cmd = ast_play_and_wait(chan, "vm-saveoper");
13642 if (!cmd)
13643 cmd = ast_waitfordigit(chan, 3000);
13644 if (cmd == '1') {
13645 ast_filerename(tempfile, recordfile, NULL);
13646 ast_play_and_wait(chan, "vm-msgsaved");
13647 cmd = '0';
13648 } else if (cmd == '4') {
13649 if (flag) {
13650 ast_play_and_wait(chan, "vm-marked-urgent");
13651 strcpy(flag, "Urgent");
13652 }
13653 ast_play_and_wait(chan, "vm-msgsaved");
13654 cmd = '0';
13655 } else {
13656 ast_play_and_wait(chan, "vm-deleted");
13657 DELETE(tempfile, -1, tempfile, vmu);
13658 cmd = '0';
13659 }
13660 }
13661 return cmd;
13662 default:
13663
13664
13665
13666 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13667 return cmd;
13668 if (msg_exists) {
13669 cmd = ast_play_and_wait(chan, "vm-review");
13670 if (!cmd && outsidecaller) {
13671 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13672 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13673 } else if (flag) {
13674 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13675 }
13676 }
13677 } else {
13678 cmd = ast_play_and_wait(chan, "vm-torerecord");
13679 if (!cmd)
13680 cmd = ast_waitfordigit(chan, 600);
13681 }
13682
13683 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13684 cmd = ast_play_and_wait(chan, "vm-reachoper");
13685 if (!cmd)
13686 cmd = ast_waitfordigit(chan, 600);
13687 }
13688 #if 0
13689 if (!cmd)
13690 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13691 #endif
13692 if (!cmd)
13693 cmd = ast_waitfordigit(chan, 6000);
13694 if (!cmd) {
13695 attempts++;
13696 }
13697 if (attempts > max_attempts) {
13698 cmd = 't';
13699 }
13700 }
13701 }
13702 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13703
13704 ast_filedelete(tempfile, NULL);
13705 }
13706
13707 if (cmd != 't' && outsidecaller)
13708 ast_play_and_wait(chan, "vm-goodbye");
13709
13710 return cmd;
13711 }
13712
13713
13714
13715
13716
13717 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13718 .load = load_module,
13719 .unload = unload_module,
13720 .reload = reload,
13721 .nonoptreq = "res_adsi,res_smdi",
13722 );