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: 376262 $")
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[VMSTATE_MAX_MSG_ARRAY];
00702 MAILSTREAM *mailstream;
00703 int vmArrayIndex;
00704 char imapuser[80];
00705 char imapfolder[64];
00706 int imapversion;
00707 int interactive;
00708 char introfn[PATH_MAX];
00709 unsigned int quota_limit;
00710 unsigned int quota_usage;
00711 struct vm_state *persist_vms;
00712 #endif
00713 };
00714
00715 #ifdef ODBC_STORAGE
00716 static char odbc_database[80];
00717 static char odbc_table[80];
00718 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00719 #define DISPOSE(a,b) remove_file(a,b)
00720 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00721 #define EXISTS(a,b,c,d) (message_exists(a,b))
00722 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00723 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00724 #define DELETE(a,b,c,d) (delete_file(a,b))
00725 #else
00726 #ifdef IMAP_STORAGE
00727 #define DISPOSE(a,b) (imap_remove_file(a,b))
00728 #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))
00729 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00730 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00731 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00732 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00733 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00734 #else
00735 #define RETRIEVE(a,b,c,d)
00736 #define DISPOSE(a,b)
00737 #define STORE(a,b,c,d,e,f,g,h,i,j)
00738 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00739 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00740 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00741 #define DELETE(a,b,c,d) (vm_delete(c))
00742 #endif
00743 #endif
00744
00745 static char VM_SPOOL_DIR[PATH_MAX];
00746
00747 static char ext_pass_cmd[128];
00748 static char ext_pass_check_cmd[128];
00749
00750 static int my_umask;
00751
00752 #define PWDCHANGE_INTERNAL (1 << 1)
00753 #define PWDCHANGE_EXTERNAL (1 << 2)
00754 static int pwdchange = PWDCHANGE_INTERNAL;
00755
00756 #ifdef ODBC_STORAGE
00757 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00758 #else
00759 # ifdef IMAP_STORAGE
00760 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00761 # else
00762 # define tdesc "Comedian Mail (Voicemail System)"
00763 # endif
00764 #endif
00765
00766 static char userscontext[AST_MAX_EXTENSION] = "default";
00767
00768 static char *addesc = "Comedian Mail";
00769
00770
00771 static char *app = "VoiceMail";
00772
00773
00774 static char *app2 = "VoiceMailMain";
00775
00776 static char *app3 = "MailboxExists";
00777 static char *app4 = "VMAuthenticate";
00778
00779 static char *sayname_app = "VMSayName";
00780
00781 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00782 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00783 static char zonetag[80];
00784 static char locale[20];
00785 static int maxsilence;
00786 static int maxmsg;
00787 static int maxdeletedmsg;
00788 static int silencethreshold = 128;
00789 static char serveremail[80];
00790 static char mailcmd[160];
00791 static char externnotify[160];
00792 static struct ast_smdi_interface *smdi_iface = NULL;
00793 static char vmfmts[80];
00794 static double volgain;
00795 static int vmminsecs;
00796 static int vmmaxsecs;
00797 static int maxgreet;
00798 static int skipms;
00799 static int maxlogins;
00800 static int minpassword;
00801 static int passwordlocation;
00802
00803
00804
00805 static unsigned int poll_mailboxes;
00806
00807
00808 static unsigned int poll_freq;
00809
00810 #define DEFAULT_POLL_FREQ 30
00811
00812 AST_MUTEX_DEFINE_STATIC(poll_lock);
00813 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00814 static pthread_t poll_thread = AST_PTHREADT_NULL;
00815 static unsigned char poll_thread_run;
00816
00817
00818 static struct ast_event_sub *mwi_sub_sub;
00819
00820 static struct ast_event_sub *mwi_unsub_sub;
00821
00822
00823
00824
00825
00826
00827
00828
00829 struct mwi_sub {
00830 AST_RWLIST_ENTRY(mwi_sub) entry;
00831 int old_urgent;
00832 int old_new;
00833 int old_old;
00834 uint32_t uniqueid;
00835 char mailbox[1];
00836 };
00837
00838 struct mwi_sub_task {
00839 const char *mailbox;
00840 const char *context;
00841 uint32_t uniqueid;
00842 };
00843
00844 static struct ast_taskprocessor *mwi_subscription_tps;
00845
00846 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00847
00848
00849 static char listen_control_forward_key[12];
00850 static char listen_control_reverse_key[12];
00851 static char listen_control_pause_key[12];
00852 static char listen_control_restart_key[12];
00853 static char listen_control_stop_key[12];
00854
00855
00856 static char vm_password[80] = "vm-password";
00857 static char vm_newpassword[80] = "vm-newpassword";
00858 static char vm_passchanged[80] = "vm-passchanged";
00859 static char vm_reenterpassword[80] = "vm-reenterpassword";
00860 static char vm_mismatch[80] = "vm-mismatch";
00861 static char vm_invalid_password[80] = "vm-invalid-password";
00862 static char vm_pls_try_again[80] = "vm-pls-try-again";
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874 static char vm_prepend_timeout[80] = "vm-then-pound";
00875
00876 static struct ast_flags globalflags = {0};
00877
00878 static int saydurationminfo;
00879
00880 static char dialcontext[AST_MAX_CONTEXT] = "";
00881 static char callcontext[AST_MAX_CONTEXT] = "";
00882 static char exitcontext[AST_MAX_CONTEXT] = "";
00883
00884 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00885
00886
00887 static char *emailbody = NULL;
00888 static char *emailsubject = NULL;
00889 static char *pagerbody = NULL;
00890 static char *pagersubject = NULL;
00891 static char fromstring[100];
00892 static char pagerfromstring[100];
00893 static char charset[32] = "ISO-8859-1";
00894
00895 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00896 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00897 static int adsiver = 1;
00898 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00899 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00900
00901
00902 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00903 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);
00904 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00905 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00906 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00907 signed char record_gain, struct vm_state *vms, char *flag);
00908 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00909 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00910 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);
00911 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);
00912 static void apply_options(struct ast_vm_user *vmu, const char *options);
00913 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);
00914 static int is_valid_dtmf(const char *key);
00915 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00916 static int write_password_to_file(const char *secretfn, const char *password);
00917 static const char *substitute_escapes(const char *value);
00918 static void free_user(struct ast_vm_user *vmu);
00919
00920 struct ao2_container *inprocess_container;
00921
00922 struct inprocess {
00923 int count;
00924 char *context;
00925 char mailbox[0];
00926 };
00927
00928 static int inprocess_hash_fn(const void *obj, const int flags)
00929 {
00930 const struct inprocess *i = obj;
00931 return atoi(i->mailbox);
00932 }
00933
00934 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00935 {
00936 struct inprocess *i = obj, *j = arg;
00937 if (strcmp(i->mailbox, j->mailbox)) {
00938 return 0;
00939 }
00940 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00941 }
00942
00943 static int inprocess_count(const char *context, const char *mailbox, int delta)
00944 {
00945 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00946 arg->context = arg->mailbox + strlen(mailbox) + 1;
00947 strcpy(arg->mailbox, mailbox);
00948 strcpy(arg->context, context);
00949 ao2_lock(inprocess_container);
00950 if ((i = ao2_find(inprocess_container, arg, 0))) {
00951 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00952 ao2_unlock(inprocess_container);
00953 ao2_ref(i, -1);
00954 return ret;
00955 }
00956 if (delta < 0) {
00957 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00958 }
00959 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00960 ao2_unlock(inprocess_container);
00961 return 0;
00962 }
00963 i->context = i->mailbox + strlen(mailbox) + 1;
00964 strcpy(i->mailbox, mailbox);
00965 strcpy(i->context, context);
00966 i->count = delta;
00967 ao2_link(inprocess_container, i);
00968 ao2_unlock(inprocess_container);
00969 ao2_ref(i, -1);
00970 return 0;
00971 }
00972
00973 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00974 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00975 #endif
00976
00977
00978
00979
00980
00981
00982
00983 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00984 {
00985 char *bufptr = buf;
00986 for (; *input; input++) {
00987 if (*input < 32) {
00988 continue;
00989 }
00990 *bufptr++ = *input;
00991 if (bufptr == buf + buflen - 1) {
00992 break;
00993 }
00994 }
00995 *bufptr = '\0';
00996 return buf;
00997 }
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 static void populate_defaults(struct ast_vm_user *vmu)
01014 {
01015 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01016 vmu->passwordlocation = passwordlocation;
01017 if (saydurationminfo) {
01018 vmu->saydurationm = saydurationminfo;
01019 }
01020 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01021 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01022 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01023 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01024 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01025 if (vmminsecs) {
01026 vmu->minsecs = vmminsecs;
01027 }
01028 if (vmmaxsecs) {
01029 vmu->maxsecs = vmmaxsecs;
01030 }
01031 if (maxmsg) {
01032 vmu->maxmsg = maxmsg;
01033 }
01034 if (maxdeletedmsg) {
01035 vmu->maxdeletedmsg = maxdeletedmsg;
01036 }
01037 vmu->volgain = volgain;
01038 ast_free(vmu->emailsubject);
01039 vmu->emailsubject = NULL;
01040 ast_free(vmu->emailbody);
01041 vmu->emailbody = NULL;
01042 #ifdef IMAP_STORAGE
01043 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01044 #endif
01045 }
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01056 {
01057 int x;
01058 if (!strcasecmp(var, "attach")) {
01059 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01060 } else if (!strcasecmp(var, "attachfmt")) {
01061 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01062 } else if (!strcasecmp(var, "serveremail")) {
01063 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01064 } else if (!strcasecmp(var, "emailbody")) {
01065 vmu->emailbody = ast_strdup(substitute_escapes(value));
01066 } else if (!strcasecmp(var, "emailsubject")) {
01067 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01068 } else if (!strcasecmp(var, "language")) {
01069 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01070 } else if (!strcasecmp(var, "tz")) {
01071 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01072 } else if (!strcasecmp(var, "locale")) {
01073 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01074 #ifdef IMAP_STORAGE
01075 } else if (!strcasecmp(var, "imapuser")) {
01076 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01077 vmu->imapversion = imapversion;
01078 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01079 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01080 vmu->imapversion = imapversion;
01081 } else if (!strcasecmp(var, "imapfolder")) {
01082 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01083 } else if (!strcasecmp(var, "imapvmshareid")) {
01084 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01085 vmu->imapversion = imapversion;
01086 #endif
01087 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01088 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01089 } else if (!strcasecmp(var, "saycid")){
01090 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01091 } else if (!strcasecmp(var, "sendvoicemail")){
01092 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01093 } else if (!strcasecmp(var, "review")){
01094 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01095 } else if (!strcasecmp(var, "tempgreetwarn")){
01096 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01097 } else if (!strcasecmp(var, "messagewrap")){
01098 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01099 } else if (!strcasecmp(var, "operator")) {
01100 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01101 } else if (!strcasecmp(var, "envelope")){
01102 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01103 } else if (!strcasecmp(var, "moveheard")){
01104 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01105 } else if (!strcasecmp(var, "sayduration")){
01106 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01107 } else if (!strcasecmp(var, "saydurationm")){
01108 if (sscanf(value, "%30d", &x) == 1) {
01109 vmu->saydurationm = x;
01110 } else {
01111 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01112 }
01113 } else if (!strcasecmp(var, "forcename")){
01114 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01115 } else if (!strcasecmp(var, "forcegreetings")){
01116 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01117 } else if (!strcasecmp(var, "callback")) {
01118 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01119 } else if (!strcasecmp(var, "dialout")) {
01120 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01121 } else if (!strcasecmp(var, "exitcontext")) {
01122 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01123 } else if (!strcasecmp(var, "minsecs")) {
01124 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01125 vmu->minsecs = x;
01126 } else {
01127 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01128 vmu->minsecs = vmminsecs;
01129 }
01130 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01131 vmu->maxsecs = atoi(value);
01132 if (vmu->maxsecs <= 0) {
01133 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01134 vmu->maxsecs = vmmaxsecs;
01135 } else {
01136 vmu->maxsecs = atoi(value);
01137 }
01138 if (!strcasecmp(var, "maxmessage"))
01139 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01140 } else if (!strcasecmp(var, "maxmsg")) {
01141 vmu->maxmsg = atoi(value);
01142
01143 if (vmu->maxmsg < 0) {
01144 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01145 vmu->maxmsg = MAXMSG;
01146 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01147 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01148 vmu->maxmsg = MAXMSGLIMIT;
01149 }
01150 } else if (!strcasecmp(var, "nextaftercmd")) {
01151 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01152 } else if (!strcasecmp(var, "backupdeleted")) {
01153 if (sscanf(value, "%30d", &x) == 1)
01154 vmu->maxdeletedmsg = x;
01155 else if (ast_true(value))
01156 vmu->maxdeletedmsg = MAXMSG;
01157 else
01158 vmu->maxdeletedmsg = 0;
01159
01160 if (vmu->maxdeletedmsg < 0) {
01161 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01162 vmu->maxdeletedmsg = MAXMSG;
01163 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01164 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01165 vmu->maxdeletedmsg = MAXMSGLIMIT;
01166 }
01167 } else if (!strcasecmp(var, "volgain")) {
01168 sscanf(value, "%30lf", &vmu->volgain);
01169 } else if (!strcasecmp(var, "passwordlocation")) {
01170 if (!strcasecmp(value, "spooldir")) {
01171 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01172 } else {
01173 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01174 }
01175 } else if (!strcasecmp(var, "options")) {
01176 apply_options(vmu, value);
01177 }
01178 }
01179
01180 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01181 {
01182 int fds[2], pid = 0;
01183
01184 memset(buf, 0, len);
01185
01186 if (pipe(fds)) {
01187 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01188 } else {
01189
01190 pid = ast_safe_fork(0);
01191
01192 if (pid < 0) {
01193
01194 close(fds[0]);
01195 close(fds[1]);
01196 snprintf(buf, len, "FAILURE: Fork failed");
01197 } else if (pid) {
01198
01199 close(fds[1]);
01200 if (read(fds[0], buf, len) < 0) {
01201 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01202 }
01203 close(fds[0]);
01204 } else {
01205
01206 AST_DECLARE_APP_ARGS(arg,
01207 AST_APP_ARG(v)[20];
01208 );
01209 char *mycmd = ast_strdupa(command);
01210
01211 close(fds[0]);
01212 dup2(fds[1], STDOUT_FILENO);
01213 close(fds[1]);
01214 ast_close_fds_above_n(STDOUT_FILENO);
01215
01216 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01217
01218 execv(arg.v[0], arg.v);
01219 printf("FAILURE: %s", strerror(errno));
01220 _exit(0);
01221 }
01222 }
01223 return buf;
01224 }
01225
01226
01227
01228
01229
01230
01231
01232
01233 static int check_password(struct ast_vm_user *vmu, char *password)
01234 {
01235
01236 if (strlen(password) < minpassword)
01237 return 1;
01238
01239 if (!ast_strlen_zero(password) && password[0] == '*')
01240 return 1;
01241 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01242 char cmd[255], buf[255];
01243
01244 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01245
01246 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01247 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01248 ast_debug(5, "Result: %s\n", buf);
01249 if (!strncasecmp(buf, "VALID", 5)) {
01250 ast_debug(3, "Passed password check: '%s'\n", buf);
01251 return 0;
01252 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01253 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01254 return 0;
01255 } else {
01256 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01257 return 1;
01258 }
01259 }
01260 }
01261 return 0;
01262 }
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01275 {
01276 int res = -1;
01277 if (!strcmp(vmu->password, password)) {
01278
01279 return 0;
01280 }
01281
01282 if (strlen(password) > 10) {
01283 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01284 }
01285 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01286 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01287 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01288 res = 0;
01289 }
01290 return res;
01291 }
01292
01293
01294
01295
01296 static void apply_options(struct ast_vm_user *vmu, const char *options)
01297 {
01298 char *stringp;
01299 char *s;
01300 char *var, *value;
01301 stringp = ast_strdupa(options);
01302 while ((s = strsep(&stringp, "|"))) {
01303 value = s;
01304 if ((var = strsep(&value, "=")) && value) {
01305 apply_option(vmu, var, value);
01306 }
01307 }
01308 }
01309
01310
01311
01312
01313
01314
01315 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01316 {
01317 for (; var; var = var->next) {
01318 if (!strcasecmp(var->name, "vmsecret")) {
01319 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01320 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01321 if (ast_strlen_zero(retval->password)) {
01322 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01323 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01324 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01325 } else {
01326 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01327 }
01328 }
01329 } else if (!strcasecmp(var->name, "uniqueid")) {
01330 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01331 } else if (!strcasecmp(var->name, "pager")) {
01332 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01333 } else if (!strcasecmp(var->name, "email")) {
01334 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01335 } else if (!strcasecmp(var->name, "fullname")) {
01336 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01337 } else if (!strcasecmp(var->name, "context")) {
01338 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01339 } else if (!strcasecmp(var->name, "emailsubject")) {
01340 ast_free(retval->emailsubject);
01341 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01342 } else if (!strcasecmp(var->name, "emailbody")) {
01343 ast_free(retval->emailbody);
01344 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01345 #ifdef IMAP_STORAGE
01346 } else if (!strcasecmp(var->name, "imapuser")) {
01347 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01348 retval->imapversion = imapversion;
01349 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01350 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01351 retval->imapversion = imapversion;
01352 } else if (!strcasecmp(var->name, "imapfolder")) {
01353 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01354 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01355 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01356 retval->imapversion = imapversion;
01357 #endif
01358 } else
01359 apply_option(retval, var->name, var->value);
01360 }
01361 }
01362
01363
01364
01365
01366
01367
01368
01369
01370 static int is_valid_dtmf(const char *key)
01371 {
01372 int i;
01373 char *local_key = ast_strdupa(key);
01374
01375 for (i = 0; i < strlen(key); ++i) {
01376 if (!strchr(VALID_DTMF, *local_key)) {
01377 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01378 return 0;
01379 }
01380 local_key++;
01381 }
01382 return 1;
01383 }
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01396 {
01397 struct ast_variable *var;
01398 struct ast_vm_user *retval;
01399
01400 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01401 if (ivm) {
01402 memset(retval, 0, sizeof(*retval));
01403 }
01404 populate_defaults(retval);
01405 if (!ivm) {
01406 ast_set_flag(retval, VM_ALLOCED);
01407 }
01408 if (mailbox) {
01409 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01410 }
01411 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01412 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01413 } else {
01414 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01415 }
01416 if (var) {
01417 apply_options_full(retval, var);
01418 ast_variables_destroy(var);
01419 } else {
01420 if (!ivm)
01421 free_user(retval);
01422 retval = NULL;
01423 }
01424 }
01425 return retval;
01426 }
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01437 {
01438
01439 struct ast_vm_user *vmu = NULL, *cur;
01440 AST_LIST_LOCK(&users);
01441
01442 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01443 context = "default";
01444
01445 AST_LIST_TRAVERSE(&users, cur, list) {
01446 #ifdef IMAP_STORAGE
01447 if (cur->imapversion != imapversion) {
01448 continue;
01449 }
01450 #endif
01451 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01452 break;
01453 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01454 break;
01455 }
01456 if (cur) {
01457
01458 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01459 *vmu = *cur;
01460 if (!ivm) {
01461 vmu->emailbody = ast_strdup(cur->emailbody);
01462 vmu->emailsubject = ast_strdup(cur->emailsubject);
01463 }
01464 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01465 AST_LIST_NEXT(vmu, list) = NULL;
01466 }
01467 } else
01468 vmu = find_user_realtime(ivm, context, mailbox);
01469 AST_LIST_UNLOCK(&users);
01470 return vmu;
01471 }
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01484 {
01485
01486 struct ast_vm_user *cur;
01487 int res = -1;
01488 AST_LIST_LOCK(&users);
01489 AST_LIST_TRAVERSE(&users, cur, list) {
01490 if ((!context || !strcasecmp(context, cur->context)) &&
01491 (!strcasecmp(mailbox, cur->mailbox)))
01492 break;
01493 }
01494 if (cur) {
01495 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01496 res = 0;
01497 }
01498 AST_LIST_UNLOCK(&users);
01499 return res;
01500 }
01501
01502
01503
01504
01505
01506
01507
01508
01509 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01510 {
01511 struct ast_config *cfg = NULL;
01512 struct ast_variable *var = NULL;
01513 struct ast_category *cat = NULL;
01514 char *category = NULL, *value = NULL, *new = NULL;
01515 const char *tmp = NULL;
01516 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01517 char secretfn[PATH_MAX] = "";
01518 int found = 0;
01519
01520 if (!change_password_realtime(vmu, newpassword))
01521 return;
01522
01523
01524 switch (vmu->passwordlocation) {
01525 case OPT_PWLOC_SPOOLDIR:
01526 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01527 if (write_password_to_file(secretfn, newpassword) == 0) {
01528 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01529 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01530 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01531 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01532 break;
01533 } else {
01534 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01535 }
01536
01537 case OPT_PWLOC_VOICEMAILCONF:
01538 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01539 while ((category = ast_category_browse(cfg, category))) {
01540 if (!strcasecmp(category, vmu->context)) {
01541 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01542 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01543 break;
01544 }
01545 value = strstr(tmp, ",");
01546 if (!value) {
01547 new = ast_alloca(strlen(newpassword)+1);
01548 sprintf(new, "%s", newpassword);
01549 } else {
01550 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01551 sprintf(new, "%s%s", newpassword, value);
01552 }
01553 if (!(cat = ast_category_get(cfg, category))) {
01554 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01555 break;
01556 }
01557 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01558 found = 1;
01559 }
01560 }
01561
01562 if (found) {
01563 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01564 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01565 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01566 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01567 break;
01568 }
01569 }
01570
01571 case OPT_PWLOC_USERSCONF:
01572
01573
01574 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01575 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01576 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01577 ast_debug(4, "users.conf: %s\n", category);
01578 if (!strcasecmp(category, vmu->mailbox)) {
01579 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01580 ast_debug(3, "looks like we need to make vmsecret!\n");
01581 var = ast_variable_new("vmsecret", newpassword, "");
01582 } else {
01583 var = NULL;
01584 }
01585 new = ast_alloca(strlen(newpassword) + 1);
01586 sprintf(new, "%s", newpassword);
01587 if (!(cat = ast_category_get(cfg, category))) {
01588 ast_debug(4, "failed to get category!\n");
01589 ast_free(var);
01590 break;
01591 }
01592 if (!var) {
01593 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01594 } else {
01595 ast_variable_append(cat, var);
01596 }
01597 found = 1;
01598 break;
01599 }
01600 }
01601
01602 if (found) {
01603 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01604 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01605 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01606 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01607 }
01608 }
01609 }
01610 }
01611
01612 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01613 {
01614 char buf[255];
01615 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01616 ast_debug(1, "External password: %s\n",buf);
01617 if (!ast_safe_system(buf)) {
01618 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01619 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01620
01621 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01622 }
01623 }
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01639 {
01640 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01641 }
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655 static int make_file(char *dest, const int len, const char *dir, const int num)
01656 {
01657 return snprintf(dest, len, "%s/msg%04d", dir, num);
01658 }
01659
01660
01661 static FILE *vm_mkftemp(char *template)
01662 {
01663 FILE *p = NULL;
01664 int pfd = mkstemp(template);
01665 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01666 if (pfd > -1) {
01667 p = fdopen(pfd, "w+");
01668 if (!p) {
01669 close(pfd);
01670 pfd = -1;
01671 }
01672 }
01673 return p;
01674 }
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01685 {
01686 mode_t mode = VOICEMAIL_DIR_MODE;
01687 int res;
01688
01689 make_dir(dest, len, context, ext, folder);
01690 if ((res = ast_mkdir(dest, mode))) {
01691 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01692 return -1;
01693 }
01694 return 0;
01695 }
01696
01697 static const char * const mailbox_folders[] = {
01698 #ifdef IMAP_STORAGE
01699 imapfolder,
01700 #else
01701 "INBOX",
01702 #endif
01703 "Old",
01704 "Work",
01705 "Family",
01706 "Friends",
01707 "Cust1",
01708 "Cust2",
01709 "Cust3",
01710 "Cust4",
01711 "Cust5",
01712 "Deleted",
01713 "Urgent",
01714 };
01715
01716 static const char *mbox(struct ast_vm_user *vmu, int id)
01717 {
01718 #ifdef IMAP_STORAGE
01719 if (vmu && id == 0) {
01720 return vmu->imapfolder;
01721 }
01722 #endif
01723 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01724 }
01725
01726 static int get_folder_by_name(const char *name)
01727 {
01728 size_t i;
01729
01730 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01731 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01732 return i;
01733 }
01734 }
01735
01736 return -1;
01737 }
01738
01739 static void free_user(struct ast_vm_user *vmu)
01740 {
01741 if (ast_test_flag(vmu, VM_ALLOCED)) {
01742
01743 ast_free(vmu->emailbody);
01744 vmu->emailbody = NULL;
01745
01746 ast_free(vmu->emailsubject);
01747 vmu->emailsubject = NULL;
01748
01749 ast_free(vmu);
01750 }
01751 }
01752
01753 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01754
01755 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01756
01757
01758 if (vms->deleted) {
01759 ast_free(vms->deleted);
01760 vms->deleted = NULL;
01761 }
01762 if (vms->heard) {
01763 ast_free(vms->heard);
01764 vms->heard = NULL;
01765 }
01766 vms->dh_arraysize = 0;
01767
01768 if (arraysize > 0) {
01769 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01770 return -1;
01771 }
01772 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01773 ast_free(vms->deleted);
01774 vms->deleted = NULL;
01775 return -1;
01776 }
01777 vms->dh_arraysize = arraysize;
01778 }
01779
01780 return 0;
01781 }
01782
01783
01784
01785 #ifdef IMAP_STORAGE
01786 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01787 {
01788 char arg[10];
01789 struct vm_state *vms;
01790 unsigned long messageNum;
01791
01792
01793 if (msgnum < 0 && !imapgreetings) {
01794 ast_filedelete(file, NULL);
01795 return;
01796 }
01797
01798 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01799 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);
01800 return;
01801 }
01802
01803 if (msgnum < 0) {
01804 imap_delete_old_greeting(file, vms);
01805 return;
01806 }
01807
01808
01809
01810 messageNum = vms->msgArray[msgnum];
01811 if (messageNum == 0) {
01812 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01813 return;
01814 }
01815 if (option_debug > 2)
01816 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01817
01818 snprintf (arg, sizeof(arg), "%lu", messageNum);
01819 ast_mutex_lock(&vms->lock);
01820 mail_setflag (vms->mailstream, arg, "\\DELETED");
01821 mail_expunge(vms->mailstream);
01822 ast_mutex_unlock(&vms->lock);
01823 }
01824
01825 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01826 {
01827 struct vm_state *vms_p;
01828 char *file, *filename;
01829 char *attachment;
01830 int i;
01831 BODY *body;
01832
01833
01834
01835
01836 if (msgnum > -1 || !imapgreetings) {
01837 return 0;
01838 } else {
01839 file = strrchr(ast_strdupa(dir), '/');
01840 if (file)
01841 *file++ = '\0';
01842 else {
01843 ast_debug (1, "Failed to procure file name from directory passed.\n");
01844 return -1;
01845 }
01846 }
01847
01848
01849 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01850 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01851
01852
01853
01854
01855 if (!(vms_p = create_vm_state_from_user(vmu))) {
01856 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01857 return -1;
01858 }
01859 }
01860
01861
01862 *vms_p->introfn = '\0';
01863
01864 ast_mutex_lock(&vms_p->lock);
01865 init_mailstream(vms_p, GREETINGS_FOLDER);
01866 if (!vms_p->mailstream) {
01867 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01868 ast_mutex_unlock(&vms_p->lock);
01869 return -1;
01870 }
01871
01872
01873 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01874 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01875
01876 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01877 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01878 } else {
01879 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01880 ast_mutex_unlock(&vms_p->lock);
01881 return -1;
01882 }
01883 filename = strsep(&attachment, ".");
01884 if (!strcmp(filename, file)) {
01885 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01886 vms_p->msgArray[vms_p->curmsg] = i + 1;
01887 save_body(body, vms_p, "2", attachment, 0);
01888 ast_mutex_unlock(&vms_p->lock);
01889 return 0;
01890 }
01891 }
01892 ast_mutex_unlock(&vms_p->lock);
01893
01894 return -1;
01895 }
01896
01897 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01898 {
01899 BODY *body;
01900 char *header_content;
01901 char *attachedfilefmt;
01902 char buf[80];
01903 struct vm_state *vms;
01904 char text_file[PATH_MAX];
01905 FILE *text_file_ptr;
01906 int res = 0;
01907 struct ast_vm_user *vmu;
01908
01909 if (!(vmu = find_user(NULL, context, mailbox))) {
01910 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01911 return -1;
01912 }
01913
01914 if (msgnum < 0) {
01915 if (imapgreetings) {
01916 res = imap_retrieve_greeting(dir, msgnum, vmu);
01917 goto exit;
01918 } else {
01919 res = 0;
01920 goto exit;
01921 }
01922 }
01923
01924
01925
01926
01927 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01928
01929
01930
01931
01932
01933
01934
01935 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01936 res = -1;
01937 goto exit;
01938 }
01939
01940 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01941 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01942
01943
01944 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01945 res = 0;
01946 goto exit;
01947 }
01948
01949 if (option_debug > 2)
01950 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01951 if (vms->msgArray[msgnum] == 0) {
01952 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01953 res = -1;
01954 goto exit;
01955 }
01956
01957
01958 ast_mutex_lock(&vms->lock);
01959 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01960 ast_mutex_unlock(&vms->lock);
01961
01962 if (ast_strlen_zero(header_content)) {
01963 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01964 res = -1;
01965 goto exit;
01966 }
01967
01968 ast_mutex_lock(&vms->lock);
01969 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01970 ast_mutex_unlock(&vms->lock);
01971
01972
01973 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01974 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01975 } else {
01976 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01977 res = -1;
01978 goto exit;
01979 }
01980
01981
01982
01983 strsep(&attachedfilefmt, ".");
01984 if (!attachedfilefmt) {
01985 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01986 res = -1;
01987 goto exit;
01988 }
01989
01990 save_body(body, vms, "2", attachedfilefmt, 0);
01991 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01992 *vms->introfn = '\0';
01993 }
01994
01995
01996 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01997
01998 if (!(text_file_ptr = fopen(text_file, "w"))) {
01999 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02000 }
02001
02002 fprintf(text_file_ptr, "%s\n", "[message]");
02003
02004 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02005 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02006 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02007 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02008 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02009 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02010 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02011 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02012 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02013 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02014 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02015 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02016 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02017 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02018 fclose(text_file_ptr);
02019
02020 exit:
02021 free_user(vmu);
02022 return res;
02023 }
02024
02025 static int folder_int(const char *folder)
02026 {
02027
02028 if (!folder) {
02029 return 0;
02030 }
02031 if (!strcasecmp(folder, imapfolder)) {
02032 return 0;
02033 } else if (!strcasecmp(folder, "Old")) {
02034 return 1;
02035 } else if (!strcasecmp(folder, "Work")) {
02036 return 2;
02037 } else if (!strcasecmp(folder, "Family")) {
02038 return 3;
02039 } else if (!strcasecmp(folder, "Friends")) {
02040 return 4;
02041 } else if (!strcasecmp(folder, "Cust1")) {
02042 return 5;
02043 } else if (!strcasecmp(folder, "Cust2")) {
02044 return 6;
02045 } else if (!strcasecmp(folder, "Cust3")) {
02046 return 7;
02047 } else if (!strcasecmp(folder, "Cust4")) {
02048 return 8;
02049 } else if (!strcasecmp(folder, "Cust5")) {
02050 return 9;
02051 } else if (!strcasecmp(folder, "Urgent")) {
02052 return 11;
02053 } else {
02054 return 0;
02055 }
02056 }
02057
02058 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02059 {
02060 SEARCHPGM *pgm;
02061 SEARCHHEADER *hdr;
02062
02063 struct ast_vm_user *vmu, vmus;
02064 struct vm_state *vms_p;
02065 int ret = 0;
02066 int fold = folder_int(folder);
02067 int urgent = 0;
02068
02069
02070 if (fold == 11) {
02071 fold = NEW_FOLDER;
02072 urgent = 1;
02073 }
02074
02075 if (ast_strlen_zero(mailbox))
02076 return 0;
02077
02078
02079 vmu = find_user(&vmus, context, mailbox);
02080 if (!vmu) {
02081 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02082 return -1;
02083 } else {
02084
02085 if (vmu->imapuser[0] == '\0') {
02086 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02087 return -1;
02088 }
02089 }
02090
02091
02092 if (vmu->imapuser[0] == '\0') {
02093 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02094 free_user(vmu);
02095 return -1;
02096 }
02097
02098
02099 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02100 if (!vms_p) {
02101 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02102 }
02103 if (vms_p) {
02104 ast_debug(3, "Returning before search - user is logged in\n");
02105 if (fold == 0) {
02106 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02107 }
02108 if (fold == 1) {
02109 return vms_p->oldmessages;
02110 }
02111 }
02112
02113
02114 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02115 if (!vms_p) {
02116 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02117 }
02118
02119 if (!vms_p) {
02120 vms_p = create_vm_state_from_user(vmu);
02121 }
02122 ret = init_mailstream(vms_p, fold);
02123 if (!vms_p->mailstream) {
02124 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02125 return -1;
02126 }
02127 if (ret == 0) {
02128 ast_mutex_lock(&vms_p->lock);
02129 pgm = mail_newsearchpgm ();
02130 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02131 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02132 pgm->header = hdr;
02133 if (fold != OLD_FOLDER) {
02134 pgm->unseen = 1;
02135 pgm->seen = 0;
02136 }
02137
02138
02139
02140 else {
02141 pgm->unseen = 0;
02142 pgm->seen = 1;
02143 }
02144
02145 if (fold == NEW_FOLDER) {
02146 if (urgent) {
02147 pgm->flagged = 1;
02148 pgm->unflagged = 0;
02149 } else {
02150 pgm->flagged = 0;
02151 pgm->unflagged = 1;
02152 }
02153 }
02154 pgm->undeleted = 1;
02155 pgm->deleted = 0;
02156
02157 vms_p->vmArrayIndex = 0;
02158 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02159 if (fold == 0 && urgent == 0)
02160 vms_p->newmessages = vms_p->vmArrayIndex;
02161 if (fold == 1)
02162 vms_p->oldmessages = vms_p->vmArrayIndex;
02163 if (fold == 0 && urgent == 1)
02164 vms_p->urgentmessages = vms_p->vmArrayIndex;
02165
02166 mail_free_searchpgm(&pgm);
02167 ast_mutex_unlock(&vms_p->lock);
02168 vms_p->updated = 0;
02169 return vms_p->vmArrayIndex;
02170 } else {
02171 ast_mutex_lock(&vms_p->lock);
02172 mail_ping(vms_p->mailstream);
02173 ast_mutex_unlock(&vms_p->lock);
02174 }
02175 return 0;
02176 }
02177
02178 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02179 {
02180
02181 check_quota(vms, vmu->imapfolder);
02182 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02183 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02184 ast_play_and_wait(chan, "vm-mailboxfull");
02185 return -1;
02186 }
02187
02188
02189 ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
02190 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02191 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02192 ast_play_and_wait(chan, "vm-mailboxfull");
02193 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02194 return -1;
02195 }
02196
02197 return 0;
02198 }
02199
02200
02201
02202
02203
02204
02205
02206
02207
02208
02209 static int messagecount(const char *context, const char *mailbox, const char *folder)
02210 {
02211 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02212 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02213 } else {
02214 return __messagecount(context, mailbox, folder);
02215 }
02216 }
02217
02218 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag)
02219 {
02220 char *myserveremail = serveremail;
02221 char fn[PATH_MAX];
02222 char introfn[PATH_MAX];
02223 char mailbox[256];
02224 char *stringp;
02225 FILE *p = NULL;
02226 char tmp[80] = "/tmp/astmail-XXXXXX";
02227 long len;
02228 void *buf;
02229 int tempcopy = 0;
02230 STRING str;
02231 int ret;
02232 char *imap_flags = NIL;
02233 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02234 int box = NEW_FOLDER;
02235
02236
02237 if (msgnum < 0) {
02238 if(!imapgreetings) {
02239 return 0;
02240 } else {
02241 box = GREETINGS_FOLDER;
02242 }
02243 }
02244
02245 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02246 return -1;
02247 }
02248
02249
02250 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02251 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02252 imap_flags = "\\FLAGGED";
02253 }
02254
02255
02256 fmt = ast_strdupa(fmt);
02257 stringp = fmt;
02258 strsep(&stringp, "|");
02259
02260 if (!ast_strlen_zero(vmu->serveremail))
02261 myserveremail = vmu->serveremail;
02262
02263 if (msgnum > -1)
02264 make_file(fn, sizeof(fn), dir, msgnum);
02265 else
02266 ast_copy_string (fn, dir, sizeof(fn));
02267
02268 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02269 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02270 *introfn = '\0';
02271 }
02272
02273 if (ast_strlen_zero(vmu->email)) {
02274
02275
02276
02277
02278
02279 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02280 tempcopy = 1;
02281 }
02282
02283 if (!strcmp(fmt, "wav49"))
02284 fmt = "WAV";
02285 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02286
02287
02288
02289 if (!(p = vm_mkftemp(tmp))) {
02290 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02291 if (tempcopy)
02292 *(vmu->email) = '\0';
02293 return -1;
02294 }
02295
02296 if (msgnum < 0 && imapgreetings) {
02297 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02298 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02299 return -1;
02300 }
02301 imap_delete_old_greeting(fn, vms);
02302 }
02303
02304 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02305 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02306 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02307 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02308
02309 len = ftell(p);
02310 rewind(p);
02311 if (!(buf = ast_malloc(len + 1))) {
02312 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02313 fclose(p);
02314 if (tempcopy)
02315 *(vmu->email) = '\0';
02316 return -1;
02317 }
02318 if (fread(buf, len, 1, p) < len) {
02319 if (ferror(p)) {
02320 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02321 return -1;
02322 }
02323 }
02324 ((char *) buf)[len] = '\0';
02325 INIT(&str, mail_string, buf, len);
02326 ret = init_mailstream(vms, box);
02327 if (ret == 0) {
02328 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02329 ast_mutex_lock(&vms->lock);
02330 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02331 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02332 ast_mutex_unlock(&vms->lock);
02333 fclose(p);
02334 unlink(tmp);
02335 ast_free(buf);
02336 } else {
02337 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02338 fclose(p);
02339 unlink(tmp);
02340 ast_free(buf);
02341 return -1;
02342 }
02343 ast_debug(3, "%s stored\n", fn);
02344
02345 if (tempcopy)
02346 *(vmu->email) = '\0';
02347 inprocess_count(vmu->mailbox, vmu->context, -1);
02348 return 0;
02349
02350 }
02351
02352
02353
02354
02355
02356
02357
02358
02359
02360
02361
02362
02363
02364
02365 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02366 {
02367 char tmp[PATH_MAX] = "";
02368 char *mailboxnc;
02369 char *context;
02370 char *mb;
02371 char *cur;
02372 if (newmsgs)
02373 *newmsgs = 0;
02374 if (oldmsgs)
02375 *oldmsgs = 0;
02376 if (urgentmsgs)
02377 *urgentmsgs = 0;
02378
02379 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02380
02381 if (ast_strlen_zero(mailbox_context))
02382 return 0;
02383
02384 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02385 context = strchr(tmp, '@');
02386 if (strchr(mailbox_context, ',')) {
02387 int tmpnew, tmpold, tmpurgent;
02388 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02389 mb = tmp;
02390 while ((cur = strsep(&mb, ", "))) {
02391 if (!ast_strlen_zero(cur)) {
02392 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02393 return -1;
02394 else {
02395 if (newmsgs)
02396 *newmsgs += tmpnew;
02397 if (oldmsgs)
02398 *oldmsgs += tmpold;
02399 if (urgentmsgs)
02400 *urgentmsgs += tmpurgent;
02401 }
02402 }
02403 }
02404 return 0;
02405 }
02406 if (context) {
02407 *context = '\0';
02408 mailboxnc = tmp;
02409 context++;
02410 } else {
02411 context = "default";
02412 mailboxnc = (char *) mailbox_context;
02413 }
02414
02415 if (newmsgs) {
02416 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02417 if (!vmu) {
02418 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02419 return -1;
02420 }
02421 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02422 free_user(vmu);
02423 return -1;
02424 }
02425 free_user(vmu);
02426 }
02427 if (oldmsgs) {
02428 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02429 return -1;
02430 }
02431 }
02432 if (urgentmsgs) {
02433 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02434 return -1;
02435 }
02436 }
02437 return 0;
02438 }
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450 static int has_voicemail(const char *mailbox, const char *folder)
02451 {
02452 char tmp[256], *tmp2, *box, *context;
02453 ast_copy_string(tmp, mailbox, sizeof(tmp));
02454 tmp2 = tmp;
02455 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02456 while ((box = strsep(&tmp2, ",&"))) {
02457 if (!ast_strlen_zero(box)) {
02458 if (has_voicemail(box, folder)) {
02459 return 1;
02460 }
02461 }
02462 }
02463 }
02464 if ((context = strchr(tmp, '@'))) {
02465 *context++ = '\0';
02466 } else {
02467 context = "default";
02468 }
02469 return __messagecount(context, tmp, folder) ? 1 : 0;
02470 }
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487 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)
02488 {
02489 struct vm_state *sendvms = NULL, *destvms = NULL;
02490 char messagestring[10];
02491 if (msgnum >= recip->maxmsg) {
02492 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02493 return -1;
02494 }
02495 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02496 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02497 return -1;
02498 }
02499 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02500 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02501 return -1;
02502 }
02503 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02504 ast_mutex_lock(&sendvms->lock);
02505 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02506 ast_mutex_unlock(&sendvms->lock);
02507 return 0;
02508 }
02509 ast_mutex_unlock(&sendvms->lock);
02510 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02511 return -1;
02512 }
02513
02514 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02515 {
02516 char tmp[256], *t = tmp;
02517 size_t left = sizeof(tmp);
02518
02519 if (box == OLD_FOLDER) {
02520 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02521 } else {
02522 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02523 }
02524
02525 if (box == NEW_FOLDER) {
02526 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02527 } else {
02528 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02529 }
02530
02531
02532 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02533
02534
02535 if (!ast_strlen_zero(authuser))
02536 ast_build_string(&t, &left, "/authuser=%s", authuser);
02537
02538
02539 if (!ast_strlen_zero(imapflags))
02540 ast_build_string(&t, &left, "/%s", imapflags);
02541
02542
02543 #if 1
02544 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02545 #else
02546 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02547 #endif
02548 if (box == NEW_FOLDER || box == OLD_FOLDER)
02549 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02550 else if (box == GREETINGS_FOLDER)
02551 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02552 else {
02553 if (!ast_strlen_zero(imapparentfolder)) {
02554
02555 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02556 } else {
02557 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02558 }
02559 }
02560 }
02561
02562 static int init_mailstream(struct vm_state *vms, int box)
02563 {
02564 MAILSTREAM *stream = NIL;
02565 long debug;
02566 char tmp[256];
02567
02568 if (!vms) {
02569 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02570 return -1;
02571 }
02572 if (option_debug > 2)
02573 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02574 if (vms->mailstream == NIL || !vms->mailstream) {
02575 if (option_debug)
02576 ast_log(LOG_DEBUG, "mailstream not set.\n");
02577 } else {
02578 stream = vms->mailstream;
02579 }
02580
02581 debug = NIL;
02582
02583 if (delimiter == '\0') {
02584 char *cp;
02585 #ifdef USE_SYSTEM_IMAP
02586 #include <imap/linkage.c>
02587 #elif defined(USE_SYSTEM_CCLIENT)
02588 #include <c-client/linkage.c>
02589 #else
02590 #include "linkage.c"
02591 #endif
02592
02593 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02594 ast_mutex_lock(&vms->lock);
02595 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02596 ast_mutex_unlock(&vms->lock);
02597 if (stream == NIL) {
02598 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02599 return -1;
02600 }
02601 get_mailbox_delimiter(stream);
02602
02603 for (cp = vms->imapfolder; *cp; cp++)
02604 if (*cp == '/')
02605 *cp = delimiter;
02606 }
02607
02608 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02609 if (option_debug > 2)
02610 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02611 ast_mutex_lock(&vms->lock);
02612 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02613 ast_mutex_unlock(&vms->lock);
02614 if (vms->mailstream == NIL) {
02615 return -1;
02616 } else {
02617 return 0;
02618 }
02619 }
02620
02621 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02622 {
02623 SEARCHPGM *pgm;
02624 SEARCHHEADER *hdr;
02625 int ret, urgent = 0;
02626
02627
02628 if (box == 11) {
02629 box = NEW_FOLDER;
02630 urgent = 1;
02631 }
02632
02633 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02634 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02635 vms->imapversion = vmu->imapversion;
02636 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02637
02638 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02639 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02640 return -1;
02641 }
02642
02643 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02644
02645
02646 if (box == 0) {
02647 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02648 check_quota(vms, (char *) mbox(vmu, box));
02649 }
02650
02651 ast_mutex_lock(&vms->lock);
02652 pgm = mail_newsearchpgm();
02653
02654
02655 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02656 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02657 pgm->header = hdr;
02658 pgm->deleted = 0;
02659 pgm->undeleted = 1;
02660
02661
02662 if (box == NEW_FOLDER && urgent == 1) {
02663 pgm->unseen = 1;
02664 pgm->seen = 0;
02665 pgm->flagged = 1;
02666 pgm->unflagged = 0;
02667 } else if (box == NEW_FOLDER && urgent == 0) {
02668 pgm->unseen = 1;
02669 pgm->seen = 0;
02670 pgm->flagged = 0;
02671 pgm->unflagged = 1;
02672 } else if (box == OLD_FOLDER) {
02673 pgm->seen = 1;
02674 pgm->unseen = 0;
02675 }
02676
02677 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02678
02679 vms->vmArrayIndex = 0;
02680 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02681 vms->lastmsg = vms->vmArrayIndex - 1;
02682 mail_free_searchpgm(&pgm);
02683
02684
02685
02686
02687 if (box == 0 && !vms->dh_arraysize) {
02688 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02689 }
02690 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02691 ast_mutex_unlock(&vms->lock);
02692 return -1;
02693 }
02694
02695 ast_mutex_unlock(&vms->lock);
02696 return 0;
02697 }
02698
02699 static void write_file(char *filename, char *buffer, unsigned long len)
02700 {
02701 FILE *output;
02702
02703 output = fopen (filename, "w");
02704 if (fwrite(buffer, len, 1, output) != 1) {
02705 if (ferror(output)) {
02706 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02707 }
02708 }
02709 fclose (output);
02710 }
02711
02712 static void update_messages_by_imapuser(const char *user, unsigned long number)
02713 {
02714 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02715
02716 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02717 return;
02718 }
02719
02720 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02721 vms->msgArray[vms->vmArrayIndex++] = number;
02722 }
02723
02724 void mm_searched(MAILSTREAM *stream, unsigned long number)
02725 {
02726 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02727
02728 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02729 return;
02730
02731 update_messages_by_imapuser(user, number);
02732 }
02733
02734 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02735 {
02736 struct ast_variable *var;
02737 struct ast_vm_user *vmu;
02738
02739 vmu = ast_calloc(1, sizeof *vmu);
02740 if (!vmu)
02741 return NULL;
02742
02743 populate_defaults(vmu);
02744 ast_set_flag(vmu, VM_ALLOCED);
02745
02746 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02747 if (var) {
02748 apply_options_full(vmu, var);
02749 ast_variables_destroy(var);
02750 return vmu;
02751 } else {
02752 ast_free(vmu);
02753 return NULL;
02754 }
02755 }
02756
02757
02758
02759 void mm_exists(MAILSTREAM * stream, unsigned long number)
02760 {
02761
02762 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02763 if (number == 0) return;
02764 set_update(stream);
02765 }
02766
02767
02768 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02769 {
02770
02771 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02772 if (number == 0) return;
02773 set_update(stream);
02774 }
02775
02776
02777 void mm_flags(MAILSTREAM * stream, unsigned long number)
02778 {
02779
02780 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02781 if (number == 0) return;
02782 set_update(stream);
02783 }
02784
02785
02786 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02787 {
02788 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02789 mm_log (string, errflg);
02790 }
02791
02792
02793 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02794 {
02795 if (delimiter == '\0') {
02796 delimiter = delim;
02797 }
02798
02799 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02800 if (attributes & LATT_NOINFERIORS)
02801 ast_debug(5, "no inferiors\n");
02802 if (attributes & LATT_NOSELECT)
02803 ast_debug(5, "no select\n");
02804 if (attributes & LATT_MARKED)
02805 ast_debug(5, "marked\n");
02806 if (attributes & LATT_UNMARKED)
02807 ast_debug(5, "unmarked\n");
02808 }
02809
02810
02811 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02812 {
02813 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02814 if (attributes & LATT_NOINFERIORS)
02815 ast_debug(5, "no inferiors\n");
02816 if (attributes & LATT_NOSELECT)
02817 ast_debug(5, "no select\n");
02818 if (attributes & LATT_MARKED)
02819 ast_debug(5, "marked\n");
02820 if (attributes & LATT_UNMARKED)
02821 ast_debug(5, "unmarked\n");
02822 }
02823
02824
02825 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02826 {
02827 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02828 if (status->flags & SA_MESSAGES)
02829 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02830 if (status->flags & SA_RECENT)
02831 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02832 if (status->flags & SA_UNSEEN)
02833 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02834 if (status->flags & SA_UIDVALIDITY)
02835 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02836 if (status->flags & SA_UIDNEXT)
02837 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02838 ast_log(AST_LOG_NOTICE, "\n");
02839 }
02840
02841
02842 void mm_log(char *string, long errflg)
02843 {
02844 switch ((short) errflg) {
02845 case NIL:
02846 ast_debug(1, "IMAP Info: %s\n", string);
02847 break;
02848 case PARSE:
02849 case WARN:
02850 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02851 break;
02852 case ERROR:
02853 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02854 break;
02855 }
02856 }
02857
02858
02859 void mm_dlog(char *string)
02860 {
02861 ast_log(AST_LOG_NOTICE, "%s\n", string);
02862 }
02863
02864
02865 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02866 {
02867 struct ast_vm_user *vmu;
02868
02869 ast_debug(4, "Entering callback mm_login\n");
02870
02871 ast_copy_string(user, mb->user, MAILTMPLEN);
02872
02873
02874 if (!ast_strlen_zero(authpassword)) {
02875 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02876 } else {
02877 AST_LIST_TRAVERSE(&users, vmu, list) {
02878 if (!strcasecmp(mb->user, vmu->imapuser)) {
02879 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02880 break;
02881 }
02882 }
02883 if (!vmu) {
02884 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02885 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02886 free_user(vmu);
02887 }
02888 }
02889 }
02890 }
02891
02892
02893 void mm_critical(MAILSTREAM * stream)
02894 {
02895 }
02896
02897
02898 void mm_nocritical(MAILSTREAM * stream)
02899 {
02900 }
02901
02902
02903 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02904 {
02905 kill (getpid (), SIGSTOP);
02906 return NIL;
02907 }
02908
02909
02910 void mm_fatal(char *string)
02911 {
02912 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02913 }
02914
02915
02916 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02917 {
02918 struct vm_state *vms;
02919 char *mailbox = stream->mailbox, *user;
02920 char buf[1024] = "";
02921 unsigned long usage = 0, limit = 0;
02922
02923 while (pquota) {
02924 usage = pquota->usage;
02925 limit = pquota->limit;
02926 pquota = pquota->next;
02927 }
02928
02929 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)))) {
02930 ast_log(AST_LOG_ERROR, "No state found.\n");
02931 return;
02932 }
02933
02934 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02935
02936 vms->quota_usage = usage;
02937 vms->quota_limit = limit;
02938 }
02939
02940 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02941 {
02942 char *start, *eol_pnt;
02943 int taglen;
02944
02945 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02946 return NULL;
02947
02948 taglen = strlen(tag) + 1;
02949 if (taglen < 1)
02950 return NULL;
02951
02952 if (!(start = strstr(header, tag)))
02953 return NULL;
02954
02955
02956 memset(buf, 0, len);
02957
02958 ast_copy_string(buf, start+taglen, len);
02959 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02960 *eol_pnt = '\0';
02961 return buf;
02962 }
02963
02964 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02965 {
02966 char *start, *quote, *eol_pnt;
02967
02968 if (ast_strlen_zero(mailbox))
02969 return NULL;
02970
02971 if (!(start = strstr(mailbox, "/user=")))
02972 return NULL;
02973
02974 ast_copy_string(buf, start+6, len);
02975
02976 if (!(quote = strchr(buf, '\"'))) {
02977 if (!(eol_pnt = strchr(buf, '/')))
02978 eol_pnt = strchr(buf,'}');
02979 *eol_pnt = '\0';
02980 return buf;
02981 } else {
02982 eol_pnt = strchr(buf+1,'\"');
02983 *eol_pnt = '\0';
02984 return buf+1;
02985 }
02986 }
02987
02988 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02989 {
02990 struct vm_state *vms_p;
02991
02992 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02993 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02994 return vms_p;
02995 }
02996 if (option_debug > 4)
02997 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02998 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02999 return NULL;
03000 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03001 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03002 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03003 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03004 vms_p->mailstream = NIL;
03005 vms_p->imapversion = vmu->imapversion;
03006 if (option_debug > 4)
03007 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03008 vms_p->updated = 1;
03009
03010 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03011 init_vm_state(vms_p);
03012 vmstate_insert(vms_p);
03013 return vms_p;
03014 }
03015
03016 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03017 {
03018 struct vmstate *vlist = NULL;
03019
03020 if (interactive) {
03021 struct vm_state *vms;
03022 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03023 vms = pthread_getspecific(ts_vmstate.key);
03024 return vms;
03025 }
03026
03027 AST_LIST_LOCK(&vmstates);
03028 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03029 if (!vlist->vms) {
03030 ast_debug(3, "error: vms is NULL for %s\n", user);
03031 continue;
03032 }
03033 if (vlist->vms->imapversion != imapversion) {
03034 continue;
03035 }
03036 if (!vlist->vms->imapuser) {
03037 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03038 continue;
03039 }
03040
03041 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03042 AST_LIST_UNLOCK(&vmstates);
03043 return vlist->vms;
03044 }
03045 }
03046 AST_LIST_UNLOCK(&vmstates);
03047
03048 ast_debug(3, "%s not found in vmstates\n", user);
03049
03050 return NULL;
03051 }
03052
03053 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03054 {
03055
03056 struct vmstate *vlist = NULL;
03057 const char *local_context = S_OR(context, "default");
03058
03059 if (interactive) {
03060 struct vm_state *vms;
03061 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03062 vms = pthread_getspecific(ts_vmstate.key);
03063 return vms;
03064 }
03065
03066 AST_LIST_LOCK(&vmstates);
03067 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03068 if (!vlist->vms) {
03069 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03070 continue;
03071 }
03072 if (vlist->vms->imapversion != imapversion) {
03073 continue;
03074 }
03075 if (!vlist->vms->username || !vlist->vms->context) {
03076 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03077 continue;
03078 }
03079
03080 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);
03081
03082 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03083 ast_debug(3, "Found it!\n");
03084 AST_LIST_UNLOCK(&vmstates);
03085 return vlist->vms;
03086 }
03087 }
03088 AST_LIST_UNLOCK(&vmstates);
03089
03090 ast_debug(3, "%s not found in vmstates\n", mailbox);
03091
03092 return NULL;
03093 }
03094
03095 static void vmstate_insert(struct vm_state *vms)
03096 {
03097 struct vmstate *v;
03098 struct vm_state *altvms;
03099
03100
03101
03102
03103 if (vms->interactive == 1) {
03104 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03105 if (altvms) {
03106 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03107 vms->newmessages = altvms->newmessages;
03108 vms->oldmessages = altvms->oldmessages;
03109 vms->vmArrayIndex = altvms->vmArrayIndex;
03110 vms->lastmsg = altvms->lastmsg;
03111 vms->curmsg = altvms->curmsg;
03112
03113 vms->persist_vms = altvms;
03114
03115 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03116 vms->mailstream = altvms->mailstream;
03117 #else
03118 vms->mailstream = NIL;
03119 #endif
03120 }
03121 return;
03122 }
03123
03124 if (!(v = ast_calloc(1, sizeof(*v))))
03125 return;
03126
03127 v->vms = vms;
03128
03129 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03130
03131 AST_LIST_LOCK(&vmstates);
03132 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03133 AST_LIST_UNLOCK(&vmstates);
03134 }
03135
03136 static void vmstate_delete(struct vm_state *vms)
03137 {
03138 struct vmstate *vc = NULL;
03139 struct vm_state *altvms = NULL;
03140
03141
03142
03143 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03144 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03145 altvms->newmessages = vms->newmessages;
03146 altvms->oldmessages = vms->oldmessages;
03147 altvms->updated = 1;
03148 vms->mailstream = mail_close(vms->mailstream);
03149
03150
03151 return;
03152 }
03153
03154 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03155
03156 AST_LIST_LOCK(&vmstates);
03157 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03158 if (vc->vms == vms) {
03159 AST_LIST_REMOVE_CURRENT(list);
03160 break;
03161 }
03162 }
03163 AST_LIST_TRAVERSE_SAFE_END
03164 AST_LIST_UNLOCK(&vmstates);
03165
03166 if (vc) {
03167 ast_mutex_destroy(&vc->vms->lock);
03168 ast_free(vc);
03169 }
03170 else
03171 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03172 }
03173
03174 static void set_update(MAILSTREAM * stream)
03175 {
03176 struct vm_state *vms;
03177 char *mailbox = stream->mailbox, *user;
03178 char buf[1024] = "";
03179
03180 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03181 if (user && option_debug > 2)
03182 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03183 return;
03184 }
03185
03186 ast_debug(3, "User %s mailbox set for update.\n", user);
03187
03188 vms->updated = 1;
03189 }
03190
03191 static void init_vm_state(struct vm_state *vms)
03192 {
03193 int x;
03194 vms->vmArrayIndex = 0;
03195 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03196 vms->msgArray[x] = 0;
03197 }
03198 ast_mutex_init(&vms->lock);
03199 }
03200
03201 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03202 {
03203 char *body_content;
03204 char *body_decoded;
03205 char *fn = is_intro ? vms->introfn : vms->fn;
03206 unsigned long len;
03207 unsigned long newlen;
03208 char filename[256];
03209
03210 if (!body || body == NIL)
03211 return -1;
03212
03213 ast_mutex_lock(&vms->lock);
03214 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03215 ast_mutex_unlock(&vms->lock);
03216 if (body_content != NIL) {
03217 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03218
03219 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03220
03221 if (!newlen) {
03222 return -1;
03223 }
03224 write_file(filename, (char *) body_decoded, newlen);
03225 } else {
03226 ast_debug(5, "Body of message is NULL.\n");
03227 return -1;
03228 }
03229 return 0;
03230 }
03231
03232
03233
03234
03235
03236
03237
03238
03239 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03240 char tmp[50];
03241 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03242 mail_list(stream, tmp, "*");
03243 }
03244
03245
03246
03247
03248
03249
03250
03251
03252 static void check_quota(struct vm_state *vms, char *mailbox) {
03253 ast_mutex_lock(&vms->lock);
03254 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03255 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03256 if (vms && vms->mailstream != NULL) {
03257 imap_getquotaroot(vms->mailstream, mailbox);
03258 } else {
03259 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03260 }
03261 ast_mutex_unlock(&vms->lock);
03262 }
03263
03264 #endif
03265
03266
03267
03268
03269
03270 static int vm_lock_path(const char *path)
03271 {
03272 switch (ast_lock_path(path)) {
03273 case AST_LOCK_TIMEOUT:
03274 return -1;
03275 default:
03276 return 0;
03277 }
03278 }
03279
03280
03281 #ifdef ODBC_STORAGE
03282 struct generic_prepare_struct {
03283 char *sql;
03284 int argc;
03285 char **argv;
03286 };
03287
03288 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03289 {
03290 struct generic_prepare_struct *gps = data;
03291 int res, i;
03292 SQLHSTMT stmt;
03293
03294 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03295 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03296 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03297 return NULL;
03298 }
03299 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03300 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03301 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03302 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03303 return NULL;
03304 }
03305 for (i = 0; i < gps->argc; i++)
03306 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03307
03308 return stmt;
03309 }
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325 static int retrieve_file(char *dir, int msgnum)
03326 {
03327 int x = 0;
03328 int res;
03329 int fd = -1;
03330 size_t fdlen = 0;
03331 void *fdm = MAP_FAILED;
03332 SQLSMALLINT colcount = 0;
03333 SQLHSTMT stmt;
03334 char sql[PATH_MAX];
03335 char fmt[80]="";
03336 char *c;
03337 char coltitle[256];
03338 SQLSMALLINT collen;
03339 SQLSMALLINT datatype;
03340 SQLSMALLINT decimaldigits;
03341 SQLSMALLINT nullable;
03342 SQLULEN colsize;
03343 SQLLEN colsize2;
03344 FILE *f = NULL;
03345 char rowdata[80];
03346 char fn[PATH_MAX];
03347 char full_fn[PATH_MAX];
03348 char msgnums[80];
03349 char *argv[] = { dir, msgnums };
03350 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03351
03352 struct odbc_obj *obj;
03353 obj = ast_odbc_request_obj(odbc_database, 0);
03354 if (obj) {
03355 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03356 c = strchr(fmt, '|');
03357 if (c)
03358 *c = '\0';
03359 if (!strcasecmp(fmt, "wav49"))
03360 strcpy(fmt, "WAV");
03361 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03362 if (msgnum > -1)
03363 make_file(fn, sizeof(fn), dir, msgnum);
03364 else
03365 ast_copy_string(fn, dir, sizeof(fn));
03366
03367
03368 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03369
03370 if (!(f = fopen(full_fn, "w+"))) {
03371 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03372 goto yuck;
03373 }
03374
03375 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03376 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03377 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03378 if (!stmt) {
03379 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03380 ast_odbc_release_obj(obj);
03381 goto yuck;
03382 }
03383 res = SQLFetch(stmt);
03384 if (res == SQL_NO_DATA) {
03385 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03386 ast_odbc_release_obj(obj);
03387 goto yuck;
03388 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03389 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03390 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03391 ast_odbc_release_obj(obj);
03392 goto yuck;
03393 }
03394 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03395 if (fd < 0) {
03396 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03397 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03398 ast_odbc_release_obj(obj);
03399 goto yuck;
03400 }
03401 res = SQLNumResultCols(stmt, &colcount);
03402 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03403 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03404 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03405 ast_odbc_release_obj(obj);
03406 goto yuck;
03407 }
03408 if (f)
03409 fprintf(f, "[message]\n");
03410 for (x = 0; x < colcount; x++) {
03411 rowdata[0] = '\0';
03412 colsize = 0;
03413 collen = sizeof(coltitle);
03414 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03415 &datatype, &colsize, &decimaldigits, &nullable);
03416 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03417 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03418 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03419 ast_odbc_release_obj(obj);
03420 goto yuck;
03421 }
03422 if (!strcasecmp(coltitle, "recording")) {
03423 off_t offset;
03424 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03425 fdlen = colsize2;
03426 if (fd > -1) {
03427 char tmp[1]="";
03428 lseek(fd, fdlen - 1, SEEK_SET);
03429 if (write(fd, tmp, 1) != 1) {
03430 close(fd);
03431 fd = -1;
03432 continue;
03433 }
03434
03435 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03436 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03437 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03438 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03439 ast_odbc_release_obj(obj);
03440 goto yuck;
03441 } else {
03442 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03443 munmap(fdm, CHUNKSIZE);
03444 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03445 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03446 unlink(full_fn);
03447 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03448 ast_odbc_release_obj(obj);
03449 goto yuck;
03450 }
03451 }
03452 }
03453 if (truncate(full_fn, fdlen) < 0) {
03454 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03455 }
03456 }
03457 } else {
03458 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03459 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03460 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03461 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03462 ast_odbc_release_obj(obj);
03463 goto yuck;
03464 }
03465 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03466 fprintf(f, "%s=%s\n", coltitle, rowdata);
03467 }
03468 }
03469 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03470 ast_odbc_release_obj(obj);
03471 } else
03472 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03473 yuck:
03474 if (f)
03475 fclose(f);
03476 if (fd > -1)
03477 close(fd);
03478 return x - 1;
03479 }
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03493 {
03494 int x = 0;
03495 int res;
03496 SQLHSTMT stmt;
03497 char sql[PATH_MAX];
03498 char rowdata[20];
03499 char *argv[] = { dir };
03500 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03501
03502 struct odbc_obj *obj;
03503 obj = ast_odbc_request_obj(odbc_database, 0);
03504 if (obj) {
03505 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03506
03507 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03508 if (!stmt) {
03509 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03510 ast_odbc_release_obj(obj);
03511 goto yuck;
03512 }
03513 res = SQLFetch(stmt);
03514 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03515 if (res == SQL_NO_DATA) {
03516 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03517 } else {
03518 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03519 }
03520
03521 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03522 ast_odbc_release_obj(obj);
03523 goto yuck;
03524 }
03525 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03526 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03527 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03528 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03529 ast_odbc_release_obj(obj);
03530 goto yuck;
03531 }
03532 if (sscanf(rowdata, "%30d", &x) != 1)
03533 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03534 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03535 ast_odbc_release_obj(obj);
03536 return x;
03537 } else
03538 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03539 yuck:
03540 return x - 1;
03541 }
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552 static int message_exists(char *dir, int msgnum)
03553 {
03554 int x = 0;
03555 int res;
03556 SQLHSTMT stmt;
03557 char sql[PATH_MAX];
03558 char rowdata[20];
03559 char msgnums[20];
03560 char *argv[] = { dir, msgnums };
03561 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03562
03563 struct odbc_obj *obj;
03564 obj = ast_odbc_request_obj(odbc_database, 0);
03565 if (obj) {
03566 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03567 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03568 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03569 if (!stmt) {
03570 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03571 ast_odbc_release_obj(obj);
03572 goto yuck;
03573 }
03574 res = SQLFetch(stmt);
03575 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03576 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03577 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03578 ast_odbc_release_obj(obj);
03579 goto yuck;
03580 }
03581 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03582 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03583 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03584 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03585 ast_odbc_release_obj(obj);
03586 goto yuck;
03587 }
03588 if (sscanf(rowdata, "%30d", &x) != 1)
03589 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03590 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03591 ast_odbc_release_obj(obj);
03592 } else
03593 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03594 yuck:
03595 return x;
03596 }
03597
03598
03599
03600
03601
03602
03603
03604
03605
03606
03607 static int count_messages(struct ast_vm_user *vmu, char *dir)
03608 {
03609 int x = 0;
03610 int res;
03611 SQLHSTMT stmt;
03612 char sql[PATH_MAX];
03613 char rowdata[20];
03614 char *argv[] = { dir };
03615 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03616
03617 struct odbc_obj *obj;
03618 obj = ast_odbc_request_obj(odbc_database, 0);
03619 if (obj) {
03620 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03621 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03622 if (!stmt) {
03623 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03624 ast_odbc_release_obj(obj);
03625 goto yuck;
03626 }
03627 res = SQLFetch(stmt);
03628 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03629 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03630 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03631 ast_odbc_release_obj(obj);
03632 goto yuck;
03633 }
03634 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03635 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03636 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03637 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03638 ast_odbc_release_obj(obj);
03639 goto yuck;
03640 }
03641 if (sscanf(rowdata, "%30d", &x) != 1)
03642 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03643 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03644 ast_odbc_release_obj(obj);
03645 return x;
03646 } else
03647 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03648 yuck:
03649 return x - 1;
03650
03651 }
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663 static void delete_file(const char *sdir, int smsg)
03664 {
03665 SQLHSTMT stmt;
03666 char sql[PATH_MAX];
03667 char msgnums[20];
03668 char *argv[] = { NULL, msgnums };
03669 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03670 struct odbc_obj *obj;
03671
03672 argv[0] = ast_strdupa(sdir);
03673
03674 obj = ast_odbc_request_obj(odbc_database, 0);
03675 if (obj) {
03676 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03677 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03678 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03679 if (!stmt)
03680 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03681 else
03682 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03683 ast_odbc_release_obj(obj);
03684 } else
03685 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03686 return;
03687 }
03688
03689
03690
03691
03692
03693
03694
03695
03696
03697
03698
03699
03700 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03701 {
03702 SQLHSTMT stmt;
03703 char sql[512];
03704 char msgnums[20];
03705 char msgnumd[20];
03706 struct odbc_obj *obj;
03707 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03708 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03709
03710 delete_file(ddir, dmsg);
03711 obj = ast_odbc_request_obj(odbc_database, 0);
03712 if (obj) {
03713 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03714 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03715 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);
03716 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03717 if (!stmt)
03718 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03719 else
03720 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03721 ast_odbc_release_obj(obj);
03722 } else
03723 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03724 return;
03725 }
03726
03727 struct insert_data {
03728 char *sql;
03729 const char *dir;
03730 const char *msgnums;
03731 void *data;
03732 SQLLEN datalen;
03733 SQLLEN indlen;
03734 const char *context;
03735 const char *macrocontext;
03736 const char *callerid;
03737 const char *origtime;
03738 const char *duration;
03739 const char *mailboxuser;
03740 const char *mailboxcontext;
03741 const char *category;
03742 const char *flag;
03743 };
03744
03745 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03746 {
03747 struct insert_data *data = vdata;
03748 int res;
03749 SQLHSTMT stmt;
03750
03751 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03752 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03753 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03754 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03755 return NULL;
03756 }
03757
03758 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03759 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03760 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03761 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03762 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03763 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03764 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03765 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03766 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03767 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03768 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03769 if (!ast_strlen_zero(data->category)) {
03770 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03771 }
03772 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03773 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03774 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03775 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03776 return NULL;
03777 }
03778
03779 return stmt;
03780 }
03781
03782
03783
03784
03785
03786
03787
03788
03789
03790
03791
03792
03793
03794
03795 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03796 {
03797 int res = 0;
03798 int fd = -1;
03799 void *fdm = MAP_FAILED;
03800 off_t fdlen = -1;
03801 SQLHSTMT stmt;
03802 char sql[PATH_MAX];
03803 char msgnums[20];
03804 char fn[PATH_MAX];
03805 char full_fn[PATH_MAX];
03806 char fmt[80]="";
03807 char *c;
03808 struct ast_config *cfg = NULL;
03809 struct odbc_obj *obj;
03810 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03811 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03812 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03813
03814 delete_file(dir, msgnum);
03815 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03816 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03817 return -1;
03818 }
03819
03820 do {
03821 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03822 c = strchr(fmt, '|');
03823 if (c)
03824 *c = '\0';
03825 if (!strcasecmp(fmt, "wav49"))
03826 strcpy(fmt, "WAV");
03827 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03828 if (msgnum > -1)
03829 make_file(fn, sizeof(fn), dir, msgnum);
03830 else
03831 ast_copy_string(fn, dir, sizeof(fn));
03832 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03833 cfg = ast_config_load(full_fn, config_flags);
03834 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03835 fd = open(full_fn, O_RDWR);
03836 if (fd < 0) {
03837 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03838 res = -1;
03839 break;
03840 }
03841 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03842 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03843 idata.context = "";
03844 }
03845 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03846 idata.macrocontext = "";
03847 }
03848 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03849 idata.callerid = "";
03850 }
03851 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03852 idata.origtime = "";
03853 }
03854 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03855 idata.duration = "";
03856 }
03857 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03858 idata.category = "";
03859 }
03860 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03861 idata.flag = "";
03862 }
03863 }
03864 fdlen = lseek(fd, 0, SEEK_END);
03865 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03866 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03867 res = -1;
03868 break;
03869 }
03870 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03871 if (fdm == MAP_FAILED) {
03872 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03873 res = -1;
03874 break;
03875 }
03876 idata.data = fdm;
03877 idata.datalen = idata.indlen = fdlen;
03878
03879 if (!ast_strlen_zero(idata.category))
03880 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03881 else
03882 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03883
03884 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03885 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03886 } else {
03887 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03888 res = -1;
03889 }
03890 } while (0);
03891 if (obj) {
03892 ast_odbc_release_obj(obj);
03893 }
03894 if (cfg)
03895 ast_config_destroy(cfg);
03896 if (fdm != MAP_FAILED)
03897 munmap(fdm, fdlen);
03898 if (fd > -1)
03899 close(fd);
03900 return res;
03901 }
03902
03903
03904
03905
03906
03907
03908
03909
03910
03911
03912
03913
03914
03915
03916 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03917 {
03918 SQLHSTMT stmt;
03919 char sql[PATH_MAX];
03920 char msgnums[20];
03921 char msgnumd[20];
03922 struct odbc_obj *obj;
03923 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03924 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03925
03926 delete_file(ddir, dmsg);
03927 obj = ast_odbc_request_obj(odbc_database, 0);
03928 if (obj) {
03929 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03930 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03931 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03932 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03933 if (!stmt)
03934 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03935 else
03936 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03937 ast_odbc_release_obj(obj);
03938 } else
03939 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03940 return;
03941 }
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954 static int remove_file(char *dir, int msgnum)
03955 {
03956 char fn[PATH_MAX];
03957 char full_fn[PATH_MAX];
03958 char msgnums[80];
03959
03960 if (msgnum > -1) {
03961 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03962 make_file(fn, sizeof(fn), dir, msgnum);
03963 } else
03964 ast_copy_string(fn, dir, sizeof(fn));
03965 ast_filedelete(fn, NULL);
03966 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03967 unlink(full_fn);
03968 return 0;
03969 }
03970 #else
03971 #ifndef IMAP_STORAGE
03972
03973
03974
03975
03976
03977
03978
03979
03980
03981 static int count_messages(struct ast_vm_user *vmu, char *dir)
03982 {
03983
03984 int vmcount = 0;
03985 DIR *vmdir = NULL;
03986 struct dirent *vment = NULL;
03987
03988 if (vm_lock_path(dir))
03989 return ERROR_LOCK_PATH;
03990
03991 if ((vmdir = opendir(dir))) {
03992 while ((vment = readdir(vmdir))) {
03993 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03994 vmcount++;
03995 }
03996 }
03997 closedir(vmdir);
03998 }
03999 ast_unlock_path(dir);
04000
04001 return vmcount;
04002 }
04003
04004
04005
04006
04007
04008
04009
04010
04011 static void rename_file(char *sfn, char *dfn)
04012 {
04013 char stxt[PATH_MAX];
04014 char dtxt[PATH_MAX];
04015 ast_filerename(sfn, dfn, NULL);
04016 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04017 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04018 if (ast_check_realtime("voicemail_data")) {
04019 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04020 }
04021 rename(stxt, dtxt);
04022 }
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04036 {
04037 int x;
04038 unsigned char map[MAXMSGLIMIT] = "";
04039 DIR *msgdir;
04040 struct dirent *msgdirent;
04041 int msgdirint;
04042 char extension[4];
04043 int stopcount = 0;
04044
04045
04046
04047
04048
04049 if (!(msgdir = opendir(dir))) {
04050 return -1;
04051 }
04052
04053 while ((msgdirent = readdir(msgdir))) {
04054 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04055 map[msgdirint] = 1;
04056 stopcount++;
04057 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04058 }
04059 }
04060 closedir(msgdir);
04061
04062 for (x = 0; x < vmu->maxmsg; x++) {
04063 if (map[x] == 1) {
04064 stopcount--;
04065 } else if (map[x] == 0 && !stopcount) {
04066 break;
04067 }
04068 }
04069
04070 return x - 1;
04071 }
04072
04073 #endif
04074 #endif
04075 #ifndef IMAP_STORAGE
04076
04077
04078
04079
04080
04081
04082
04083
04084
04085
04086 static int copy(char *infile, char *outfile)
04087 {
04088 int ifd;
04089 int ofd;
04090 int res;
04091 int len;
04092 char buf[4096];
04093
04094 #ifdef HARDLINK_WHEN_POSSIBLE
04095
04096 if (link(infile, outfile)) {
04097 #endif
04098 if ((ifd = open(infile, O_RDONLY)) < 0) {
04099 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04100 return -1;
04101 }
04102 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04103 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04104 close(ifd);
04105 return -1;
04106 }
04107 do {
04108 len = read(ifd, buf, sizeof(buf));
04109 if (len < 0) {
04110 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04111 close(ifd);
04112 close(ofd);
04113 unlink(outfile);
04114 } else if (len) {
04115 res = write(ofd, buf, len);
04116 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04117 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04118 close(ifd);
04119 close(ofd);
04120 unlink(outfile);
04121 }
04122 }
04123 } while (len);
04124 close(ifd);
04125 close(ofd);
04126 return 0;
04127 #ifdef HARDLINK_WHEN_POSSIBLE
04128 } else {
04129
04130 return 0;
04131 }
04132 #endif
04133 }
04134
04135
04136
04137
04138
04139
04140
04141
04142
04143
04144 static void copy_plain_file(char *frompath, char *topath)
04145 {
04146 char frompath2[PATH_MAX], topath2[PATH_MAX];
04147 struct ast_variable *tmp,*var = NULL;
04148 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04149 ast_filecopy(frompath, topath, NULL);
04150 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04151 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04152 if (ast_check_realtime("voicemail_data")) {
04153 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04154
04155 for (tmp = var; tmp; tmp = tmp->next) {
04156 if (!strcasecmp(tmp->name, "origmailbox")) {
04157 origmailbox = tmp->value;
04158 } else if (!strcasecmp(tmp->name, "context")) {
04159 context = tmp->value;
04160 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04161 macrocontext = tmp->value;
04162 } else if (!strcasecmp(tmp->name, "exten")) {
04163 exten = tmp->value;
04164 } else if (!strcasecmp(tmp->name, "priority")) {
04165 priority = tmp->value;
04166 } else if (!strcasecmp(tmp->name, "callerchan")) {
04167 callerchan = tmp->value;
04168 } else if (!strcasecmp(tmp->name, "callerid")) {
04169 callerid = tmp->value;
04170 } else if (!strcasecmp(tmp->name, "origdate")) {
04171 origdate = tmp->value;
04172 } else if (!strcasecmp(tmp->name, "origtime")) {
04173 origtime = tmp->value;
04174 } else if (!strcasecmp(tmp->name, "category")) {
04175 category = tmp->value;
04176 } else if (!strcasecmp(tmp->name, "duration")) {
04177 duration = tmp->value;
04178 }
04179 }
04180 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);
04181 }
04182 copy(frompath2, topath2);
04183 ast_variables_destroy(var);
04184 }
04185 #endif
04186
04187
04188
04189
04190
04191
04192
04193
04194
04195 static int vm_delete(char *file)
04196 {
04197 char *txt;
04198 int txtsize = 0;
04199
04200 txtsize = (strlen(file) + 5)*sizeof(char);
04201 txt = ast_alloca(txtsize);
04202
04203
04204
04205 if (ast_check_realtime("voicemail_data")) {
04206 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04207 }
04208 snprintf(txt, txtsize, "%s.txt", file);
04209 unlink(txt);
04210 return ast_filedelete(file, NULL);
04211 }
04212
04213
04214
04215
04216 static int inbuf(struct baseio *bio, FILE *fi)
04217 {
04218 int l;
04219
04220 if (bio->ateof)
04221 return 0;
04222
04223 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04224 if (ferror(fi))
04225 return -1;
04226
04227 bio->ateof = 1;
04228 return 0;
04229 }
04230
04231 bio->iolen = l;
04232 bio->iocp = 0;
04233
04234 return 1;
04235 }
04236
04237
04238
04239
04240 static int inchar(struct baseio *bio, FILE *fi)
04241 {
04242 if (bio->iocp>=bio->iolen) {
04243 if (!inbuf(bio, fi))
04244 return EOF;
04245 }
04246
04247 return bio->iobuf[bio->iocp++];
04248 }
04249
04250
04251
04252
04253 static int ochar(struct baseio *bio, int c, FILE *so)
04254 {
04255 if (bio->linelength >= BASELINELEN) {
04256 if (fputs(ENDL, so) == EOF) {
04257 return -1;
04258 }
04259
04260 bio->linelength = 0;
04261 }
04262
04263 if (putc(((unsigned char) c), so) == EOF) {
04264 return -1;
04265 }
04266
04267 bio->linelength++;
04268
04269 return 1;
04270 }
04271
04272
04273
04274
04275
04276
04277
04278
04279
04280
04281 static int base_encode(char *filename, FILE *so)
04282 {
04283 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04284 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04285 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04286 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04287 int i, hiteof = 0;
04288 FILE *fi;
04289 struct baseio bio;
04290
04291 memset(&bio, 0, sizeof(bio));
04292 bio.iocp = BASEMAXINLINE;
04293
04294 if (!(fi = fopen(filename, "rb"))) {
04295 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04296 return -1;
04297 }
04298
04299 while (!hiteof){
04300 unsigned char igroup[3], ogroup[4];
04301 int c, n;
04302
04303 memset(igroup, 0, sizeof(igroup));
04304
04305 for (n = 0; n < 3; n++) {
04306 if ((c = inchar(&bio, fi)) == EOF) {
04307 hiteof = 1;
04308 break;
04309 }
04310
04311 igroup[n] = (unsigned char) c;
04312 }
04313
04314 if (n > 0) {
04315 ogroup[0]= dtable[igroup[0] >> 2];
04316 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04317 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04318 ogroup[3]= dtable[igroup[2] & 0x3F];
04319
04320 if (n < 3) {
04321 ogroup[3] = '=';
04322
04323 if (n < 2)
04324 ogroup[2] = '=';
04325 }
04326
04327 for (i = 0; i < 4; i++)
04328 ochar(&bio, ogroup[i], so);
04329 }
04330 }
04331
04332 fclose(fi);
04333
04334 if (fputs(ENDL, so) == EOF) {
04335 return 0;
04336 }
04337
04338 return 1;
04339 }
04340
04341 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)
04342 {
04343 char callerid[256];
04344 char num[12];
04345 char fromdir[256], fromfile[256];
04346 struct ast_config *msg_cfg;
04347 const char *origcallerid, *origtime;
04348 char origcidname[80], origcidnum[80], origdate[80];
04349 int inttime;
04350 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04351
04352
04353 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04354 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04355 snprintf(num, sizeof(num), "%d", msgnum);
04356 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04357 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04358 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04359 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04360 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04361 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04362 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04363 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04364 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04365 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04366
04367
04368 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04369 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04370 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04371 strcat(fromfile, ".txt");
04372 }
04373 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04374 if (option_debug > 0) {
04375 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04376 }
04377 return;
04378 }
04379
04380 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04381 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04382 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04383 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04384 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04385 }
04386
04387 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04388 struct timeval tv = { inttime, };
04389 struct ast_tm tm;
04390 ast_localtime(&tv, &tm, NULL);
04391 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04392 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04393 }
04394 ast_config_destroy(msg_cfg);
04395 }
04396
04397
04398
04399
04400
04401
04402
04403
04404
04405 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04406 {
04407 const char *ptr;
04408
04409
04410 ast_str_set(buf, maxlen, "\"");
04411 for (ptr = from; *ptr; ptr++) {
04412 if (*ptr == '"' || *ptr == '\\') {
04413 ast_str_append(buf, maxlen, "\\%c", *ptr);
04414 } else {
04415 ast_str_append(buf, maxlen, "%c", *ptr);
04416 }
04417 }
04418 ast_str_append(buf, maxlen, "\"");
04419
04420 return ast_str_buffer(*buf);
04421 }
04422
04423
04424
04425
04426
04427 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04428 {
04429 const struct vm_zone *z = NULL;
04430 struct timeval t = ast_tvnow();
04431
04432
04433 if (!ast_strlen_zero(vmu->zonetag)) {
04434
04435 AST_LIST_LOCK(&zones);
04436 AST_LIST_TRAVERSE(&zones, z, list) {
04437 if (!strcmp(z->name, vmu->zonetag))
04438 break;
04439 }
04440 AST_LIST_UNLOCK(&zones);
04441 }
04442 ast_localtime(&t, tm, z ? z->timezone : NULL);
04443 return tm;
04444 }
04445
04446
04447
04448
04449
04450 static int check_mime(const char *str)
04451 {
04452 for (; *str; str++) {
04453 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04454 return 1;
04455 }
04456 }
04457 return 0;
04458 }
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04478 {
04479 struct ast_str *tmp = ast_str_alloca(80);
04480 int first_section = 1;
04481
04482 ast_str_reset(*end);
04483 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04484 for (; *start; start++) {
04485 int need_encoding = 0;
04486 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04487 need_encoding = 1;
04488 }
04489 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04490 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04491 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04492 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04493
04494 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04495 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04496 first_section = 0;
04497 }
04498 if (need_encoding && *start == ' ') {
04499 ast_str_append(&tmp, -1, "_");
04500 } else if (need_encoding) {
04501 ast_str_append(&tmp, -1, "=%hhX", *start);
04502 } else {
04503 ast_str_append(&tmp, -1, "%c", *start);
04504 }
04505 }
04506 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04507 return ast_str_buffer(*end);
04508 }
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533 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)
04534 {
04535 char date[256];
04536 char host[MAXHOSTNAMELEN] = "";
04537 char who[256];
04538 char bound[256];
04539 char dur[256];
04540 struct ast_tm tm;
04541 char enc_cidnum[256] = "", enc_cidname[256] = "";
04542 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04543 char *greeting_attachment;
04544 char filename[256];
04545
04546 if (!str1 || !str2) {
04547 ast_free(str1);
04548 ast_free(str2);
04549 return;
04550 }
04551
04552 if (cidnum) {
04553 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04554 }
04555 if (cidname) {
04556 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04557 }
04558 gethostname(host, sizeof(host) - 1);
04559
04560 if (strchr(srcemail, '@')) {
04561 ast_copy_string(who, srcemail, sizeof(who));
04562 } else {
04563 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04564 }
04565
04566 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04567 if (greeting_attachment) {
04568 *greeting_attachment++ = '\0';
04569 }
04570
04571 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04572 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04573 fprintf(p, "Date: %s" ENDL, date);
04574
04575
04576 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04577
04578 if (!ast_strlen_zero(fromstring)) {
04579 struct ast_channel *ast;
04580 if ((ast = ast_dummy_channel_alloc())) {
04581 char *ptr;
04582 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04583 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04584
04585 if (check_mime(ast_str_buffer(str1))) {
04586 int first_line = 1;
04587 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04588 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04589 *ptr = '\0';
04590 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04591 first_line = 0;
04592
04593 ast_str_set(&str2, 0, "%s", ptr + 1);
04594 }
04595 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04596 } else {
04597 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04598 }
04599 ast = ast_channel_unref(ast);
04600 } else {
04601 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04602 }
04603 } else {
04604 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04605 }
04606
04607 if (check_mime(vmu->fullname)) {
04608 int first_line = 1;
04609 char *ptr;
04610 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04611 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04612 *ptr = '\0';
04613 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04614 first_line = 0;
04615
04616 ast_str_set(&str2, 0, "%s", ptr + 1);
04617 }
04618 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04619 } else {
04620 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04621 }
04622
04623 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04624 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04625 struct ast_channel *ast;
04626 if ((ast = ast_dummy_channel_alloc())) {
04627 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04628 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04629 if (check_mime(ast_str_buffer(str1))) {
04630 int first_line = 1;
04631 char *ptr;
04632 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04633 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04634 *ptr = '\0';
04635 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04636 first_line = 0;
04637
04638 ast_str_set(&str2, 0, "%s", ptr + 1);
04639 }
04640 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04641 } else {
04642 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04643 }
04644 ast = ast_channel_unref(ast);
04645 } else {
04646 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04647 }
04648 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04649 if (ast_strlen_zero(flag)) {
04650 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04651 } else {
04652 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04653 }
04654 } else {
04655 if (ast_strlen_zero(flag)) {
04656 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04657 } else {
04658 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04659 }
04660 }
04661
04662 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04663 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04664 if (imap) {
04665
04666 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04667
04668 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04669 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04670 #ifdef IMAP_STORAGE
04671 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04672 #else
04673 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04674 #endif
04675
04676 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04677 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04678 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04679 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04680 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04681 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04682 if (!ast_strlen_zero(category)) {
04683 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04684 } else {
04685 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04686 }
04687 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04688 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04689 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04690 }
04691 if (!ast_strlen_zero(cidnum)) {
04692 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04693 }
04694 if (!ast_strlen_zero(cidname)) {
04695 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04696 }
04697 fprintf(p, "MIME-Version: 1.0" ENDL);
04698 if (attach_user_voicemail) {
04699
04700 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04701 (int) getpid(), (unsigned int) ast_random());
04702
04703 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04704 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04705 fprintf(p, "--%s" ENDL, bound);
04706 }
04707 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04708 if (emailbody || vmu->emailbody) {
04709 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04710 struct ast_channel *ast;
04711 if ((ast = ast_dummy_channel_alloc())) {
04712 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04713 ast_str_substitute_variables(&str1, 0, ast, e_body);
04714 #ifdef IMAP_STORAGE
04715 {
04716
04717 char *line = ast_str_buffer(str1), *next;
04718 do {
04719
04720 if ((next = strchr(line, '\n'))) {
04721 *next++ = '\0';
04722 }
04723 fprintf(p, "%s" ENDL, line);
04724 line = next;
04725 } while (!ast_strlen_zero(line));
04726 }
04727 #else
04728 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04729 #endif
04730 ast = ast_channel_unref(ast);
04731 } else {
04732 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04733 }
04734 } else if (msgnum > -1) {
04735 if (strcmp(vmu->mailbox, mailbox)) {
04736
04737 struct ast_config *msg_cfg;
04738 const char *v;
04739 int inttime;
04740 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04741 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04742
04743 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04744 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04745 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04746 strcat(fromfile, ".txt");
04747 }
04748 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04749 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04750 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04751 }
04752
04753
04754
04755 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04756 struct timeval tv = { inttime, };
04757 struct ast_tm tm;
04758 ast_localtime(&tv, &tm, NULL);
04759 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04760 }
04761 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04762 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04763 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04764 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04765 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04766 date, origcallerid, origdate);
04767 ast_config_destroy(msg_cfg);
04768 } else {
04769 goto plain_message;
04770 }
04771 } else {
04772 plain_message:
04773 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04774 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04775 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04776 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04777 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04778 }
04779 } else {
04780 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04781 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04782 }
04783
04784 if (imap || attach_user_voicemail) {
04785 if (!ast_strlen_zero(attach2)) {
04786 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04787 ast_debug(5, "creating second attachment filename %s\n", filename);
04788 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04789 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04790 ast_debug(5, "creating attachment filename %s\n", filename);
04791 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04792 } else {
04793 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04794 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04795 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04796 }
04797 }
04798 ast_free(str1);
04799 ast_free(str2);
04800 }
04801
04802 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)
04803 {
04804 char tmpdir[256], newtmp[256];
04805 char fname[256];
04806 char tmpcmd[256];
04807 int tmpfd = -1;
04808 int soxstatus = 0;
04809
04810
04811 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04812
04813 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04814 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04815 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04816 tmpfd = mkstemp(newtmp);
04817 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04818 ast_debug(3, "newtmp: %s\n", newtmp);
04819 if (tmpfd > -1) {
04820 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04821 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04822 attach = newtmp;
04823 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04824 } else {
04825 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04826 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04827 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04828 }
04829 }
04830 }
04831 fprintf(p, "--%s" ENDL, bound);
04832 if (msgnum > -1)
04833 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04834 else
04835 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04836 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04837 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04838 if (msgnum > -1)
04839 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04840 else
04841 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04842 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04843 base_encode(fname, p);
04844 if (last)
04845 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04846 if (tmpfd > -1) {
04847 if (soxstatus == 0) {
04848 unlink(fname);
04849 }
04850 close(tmpfd);
04851 unlink(newtmp);
04852 }
04853 return 0;
04854 }
04855
04856 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)
04857 {
04858 FILE *p = NULL;
04859 char tmp[80] = "/tmp/astmail-XXXXXX";
04860 char tmp2[256];
04861 char *stringp;
04862
04863 if (vmu && ast_strlen_zero(vmu->email)) {
04864 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04865 return(0);
04866 }
04867
04868
04869 format = ast_strdupa(format);
04870 stringp = format;
04871 strsep(&stringp, "|");
04872
04873 if (!strcmp(format, "wav49"))
04874 format = "WAV";
04875 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04876
04877
04878 if ((p = vm_mkftemp(tmp)) == NULL) {
04879 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04880 return -1;
04881 } else {
04882 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04883 fclose(p);
04884 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04885 ast_safe_system(tmp2);
04886 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04887 }
04888 return 0;
04889 }
04890
04891 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)
04892 {
04893 char enc_cidnum[256], enc_cidname[256];
04894 char date[256];
04895 char host[MAXHOSTNAMELEN] = "";
04896 char who[256];
04897 char dur[PATH_MAX];
04898 char tmp[80] = "/tmp/astmail-XXXXXX";
04899 char tmp2[PATH_MAX];
04900 struct ast_tm tm;
04901 FILE *p;
04902 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04903
04904 if (!str1 || !str2) {
04905 ast_free(str1);
04906 ast_free(str2);
04907 return -1;
04908 }
04909
04910 if (cidnum) {
04911 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04912 }
04913 if (cidname) {
04914 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04915 }
04916
04917 if ((p = vm_mkftemp(tmp)) == NULL) {
04918 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04919 ast_free(str1);
04920 ast_free(str2);
04921 return -1;
04922 }
04923 gethostname(host, sizeof(host)-1);
04924 if (strchr(srcemail, '@')) {
04925 ast_copy_string(who, srcemail, sizeof(who));
04926 } else {
04927 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04928 }
04929 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04930 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04931 fprintf(p, "Date: %s\n", date);
04932
04933
04934 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04935
04936 if (!ast_strlen_zero(pagerfromstring)) {
04937 struct ast_channel *ast;
04938 if ((ast = ast_dummy_channel_alloc())) {
04939 char *ptr;
04940 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04941 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04942
04943 if (check_mime(ast_str_buffer(str1))) {
04944 int first_line = 1;
04945 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04946 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04947 *ptr = '\0';
04948 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04949 first_line = 0;
04950
04951 ast_str_set(&str2, 0, "%s", ptr + 1);
04952 }
04953 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04954 } else {
04955 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04956 }
04957 ast = ast_channel_unref(ast);
04958 } else {
04959 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04960 }
04961 } else {
04962 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04963 }
04964
04965 if (check_mime(vmu->fullname)) {
04966 int first_line = 1;
04967 char *ptr;
04968 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04969 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04970 *ptr = '\0';
04971 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04972 first_line = 0;
04973
04974 ast_str_set(&str2, 0, "%s", ptr + 1);
04975 }
04976 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04977 } else {
04978 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04979 }
04980
04981 if (!ast_strlen_zero(pagersubject)) {
04982 struct ast_channel *ast;
04983 if ((ast = ast_dummy_channel_alloc())) {
04984 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04985 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04986 if (check_mime(ast_str_buffer(str1))) {
04987 int first_line = 1;
04988 char *ptr;
04989 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04990 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04991 *ptr = '\0';
04992 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04993 first_line = 0;
04994
04995 ast_str_set(&str2, 0, "%s", ptr + 1);
04996 }
04997 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04998 } else {
04999 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05000 }
05001 ast = ast_channel_unref(ast);
05002 } else {
05003 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05004 }
05005 } else {
05006 if (ast_strlen_zero(flag)) {
05007 fprintf(p, "Subject: New VM\n\n");
05008 } else {
05009 fprintf(p, "Subject: New %s VM\n\n", flag);
05010 }
05011 }
05012
05013 if (pagerbody) {
05014 struct ast_channel *ast;
05015 if ((ast = ast_dummy_channel_alloc())) {
05016 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05017 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05018 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05019 ast = ast_channel_unref(ast);
05020 } else {
05021 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05022 }
05023 } else {
05024 fprintf(p, "New %s long %s msg in box %s\n"
05025 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05026 }
05027
05028 fclose(p);
05029 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05030 ast_safe_system(tmp2);
05031 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05032 ast_free(str1);
05033 ast_free(str2);
05034 return 0;
05035 }
05036
05037
05038
05039
05040
05041
05042
05043
05044
05045
05046 static int get_date(char *s, int len)
05047 {
05048 struct ast_tm tm;
05049 struct timeval t = ast_tvnow();
05050
05051 ast_localtime(&t, &tm, "UTC");
05052
05053 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05054 }
05055
05056 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05057 {
05058 int res;
05059 char fn[PATH_MAX];
05060 char dest[PATH_MAX];
05061
05062 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05063
05064 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05065 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05066 return -1;
05067 }
05068
05069 RETRIEVE(fn, -1, ext, context);
05070 if (ast_fileexists(fn, NULL, NULL) > 0) {
05071 res = ast_stream_and_wait(chan, fn, ecodes);
05072 if (res) {
05073 DISPOSE(fn, -1);
05074 return res;
05075 }
05076 } else {
05077
05078 DISPOSE(fn, -1);
05079 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05080 if (res)
05081 return res;
05082 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05083 if (res)
05084 return res;
05085 }
05086 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05087 return res;
05088 }
05089
05090 static void free_zone(struct vm_zone *z)
05091 {
05092 ast_free(z);
05093 }
05094
05095 #ifdef ODBC_STORAGE
05096 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05097 {
05098 int x = -1;
05099 int res;
05100 SQLHSTMT stmt = NULL;
05101 char sql[PATH_MAX];
05102 char rowdata[20];
05103 char tmp[PATH_MAX] = "";
05104 struct odbc_obj *obj = NULL;
05105 char *context;
05106 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05107
05108 if (newmsgs)
05109 *newmsgs = 0;
05110 if (oldmsgs)
05111 *oldmsgs = 0;
05112 if (urgentmsgs)
05113 *urgentmsgs = 0;
05114
05115
05116 if (ast_strlen_zero(mailbox))
05117 return 0;
05118
05119 ast_copy_string(tmp, mailbox, sizeof(tmp));
05120
05121 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05122 int u, n, o;
05123 char *next, *remaining = tmp;
05124 while ((next = strsep(&remaining, " ,"))) {
05125 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05126 return -1;
05127 }
05128 if (urgentmsgs) {
05129 *urgentmsgs += u;
05130 }
05131 if (newmsgs) {
05132 *newmsgs += n;
05133 }
05134 if (oldmsgs) {
05135 *oldmsgs += o;
05136 }
05137 }
05138 return 0;
05139 }
05140
05141 context = strchr(tmp, '@');
05142 if (context) {
05143 *context = '\0';
05144 context++;
05145 } else
05146 context = "default";
05147
05148 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05149 do {
05150 if (newmsgs) {
05151 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05152 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05153 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05154 break;
05155 }
05156 res = SQLFetch(stmt);
05157 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05158 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05159 break;
05160 }
05161 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05162 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05163 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05164 break;
05165 }
05166 *newmsgs = atoi(rowdata);
05167 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05168 }
05169
05170 if (oldmsgs) {
05171 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05172 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05173 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05174 break;
05175 }
05176 res = SQLFetch(stmt);
05177 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05178 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05179 break;
05180 }
05181 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05182 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05183 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05184 break;
05185 }
05186 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05187 *oldmsgs = atoi(rowdata);
05188 }
05189
05190 if (urgentmsgs) {
05191 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05192 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05193 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05194 break;
05195 }
05196 res = SQLFetch(stmt);
05197 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05198 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05199 break;
05200 }
05201 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05202 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05203 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05204 break;
05205 }
05206 *urgentmsgs = atoi(rowdata);
05207 }
05208
05209 x = 0;
05210 } while (0);
05211 } else {
05212 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05213 }
05214
05215 if (stmt) {
05216 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05217 }
05218 if (obj) {
05219 ast_odbc_release_obj(obj);
05220 }
05221 return x;
05222 }
05223
05224
05225
05226
05227
05228
05229
05230
05231
05232
05233 static int messagecount(const char *context, const char *mailbox, const char *folder)
05234 {
05235 struct odbc_obj *obj = NULL;
05236 int nummsgs = 0;
05237 int res;
05238 SQLHSTMT stmt = NULL;
05239 char sql[PATH_MAX];
05240 char rowdata[20];
05241 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05242 if (!folder)
05243 folder = "INBOX";
05244
05245 if (ast_strlen_zero(mailbox))
05246 return 0;
05247
05248 obj = ast_odbc_request_obj(odbc_database, 0);
05249 if (obj) {
05250 if (!strcmp(folder, "INBOX")) {
05251 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);
05252 } else {
05253 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05254 }
05255 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05256 if (!stmt) {
05257 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05258 goto yuck;
05259 }
05260 res = SQLFetch(stmt);
05261 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05262 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05263 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05264 goto yuck;
05265 }
05266 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05267 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05268 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05269 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05270 goto yuck;
05271 }
05272 nummsgs = atoi(rowdata);
05273 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05274 } else
05275 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05276
05277 yuck:
05278 if (obj)
05279 ast_odbc_release_obj(obj);
05280 return nummsgs;
05281 }
05282
05283
05284
05285
05286
05287
05288
05289
05290
05291 static int has_voicemail(const char *mailbox, const char *folder)
05292 {
05293 char tmp[256], *tmp2 = tmp, *box, *context;
05294 ast_copy_string(tmp, mailbox, sizeof(tmp));
05295 while ((context = box = strsep(&tmp2, ",&"))) {
05296 strsep(&context, "@");
05297 if (ast_strlen_zero(context))
05298 context = "default";
05299 if (messagecount(context, box, folder))
05300 return 1;
05301 }
05302 return 0;
05303 }
05304 #endif
05305 #ifndef IMAP_STORAGE
05306
05307
05308
05309
05310
05311
05312
05313
05314
05315
05316
05317
05318
05319
05320
05321
05322 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)
05323 {
05324 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05325 const char *frombox = mbox(vmu, imbox);
05326 const char *userfolder;
05327 int recipmsgnum;
05328 int res = 0;
05329
05330 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05331
05332 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05333 userfolder = "Urgent";
05334 } else {
05335 userfolder = "INBOX";
05336 }
05337
05338 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05339
05340 if (!dir)
05341 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05342 else
05343 ast_copy_string(fromdir, dir, sizeof(fromdir));
05344
05345 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05346 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05347
05348 if (vm_lock_path(todir))
05349 return ERROR_LOCK_PATH;
05350
05351 recipmsgnum = last_message_index(recip, todir) + 1;
05352 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05353 make_file(topath, sizeof(topath), todir, recipmsgnum);
05354 #ifndef ODBC_STORAGE
05355 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05356 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05357 } else {
05358 #endif
05359
05360
05361
05362 copy_plain_file(frompath, topath);
05363 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05364 vm_delete(topath);
05365 #ifndef ODBC_STORAGE
05366 }
05367 #endif
05368 } else {
05369 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05370 res = -1;
05371 }
05372 ast_unlock_path(todir);
05373 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05374 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05375 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05376 flag);
05377
05378 return res;
05379 }
05380 #endif
05381 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05382
05383 static int messagecount(const char *context, const char *mailbox, const char *folder)
05384 {
05385 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05386 }
05387
05388 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05389 {
05390 DIR *dir;
05391 struct dirent *de;
05392 char fn[256];
05393 int ret = 0;
05394
05395
05396 if (ast_strlen_zero(mailbox))
05397 return 0;
05398
05399 if (ast_strlen_zero(folder))
05400 folder = "INBOX";
05401 if (ast_strlen_zero(context))
05402 context = "default";
05403
05404 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05405
05406 if (!(dir = opendir(fn)))
05407 return 0;
05408
05409 while ((de = readdir(dir))) {
05410 if (!strncasecmp(de->d_name, "msg", 3)) {
05411 if (shortcircuit) {
05412 ret = 1;
05413 break;
05414 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05415 ret++;
05416 }
05417 }
05418 }
05419
05420 closedir(dir);
05421
05422 return ret;
05423 }
05424
05425
05426
05427
05428
05429
05430
05431
05432
05433
05434 static int has_voicemail(const char *mailbox, const char *folder)
05435 {
05436 char tmp[256], *tmp2 = tmp, *box, *context;
05437 ast_copy_string(tmp, mailbox, sizeof(tmp));
05438 if (ast_strlen_zero(folder)) {
05439 folder = "INBOX";
05440 }
05441 while ((box = strsep(&tmp2, ",&"))) {
05442 if ((context = strchr(box, '@')))
05443 *context++ = '\0';
05444 else
05445 context = "default";
05446 if (__has_voicemail(context, box, folder, 1))
05447 return 1;
05448
05449 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05450 return 1;
05451 }
05452 }
05453 return 0;
05454 }
05455
05456
05457 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05458 {
05459 char tmp[256];
05460 char *context;
05461
05462
05463 if (ast_strlen_zero(mailbox))
05464 return 0;
05465
05466 if (newmsgs)
05467 *newmsgs = 0;
05468 if (oldmsgs)
05469 *oldmsgs = 0;
05470 if (urgentmsgs)
05471 *urgentmsgs = 0;
05472
05473 if (strchr(mailbox, ',')) {
05474 int tmpnew, tmpold, tmpurgent;
05475 char *mb, *cur;
05476
05477 ast_copy_string(tmp, mailbox, sizeof(tmp));
05478 mb = tmp;
05479 while ((cur = strsep(&mb, ", "))) {
05480 if (!ast_strlen_zero(cur)) {
05481 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05482 return -1;
05483 else {
05484 if (newmsgs)
05485 *newmsgs += tmpnew;
05486 if (oldmsgs)
05487 *oldmsgs += tmpold;
05488 if (urgentmsgs)
05489 *urgentmsgs += tmpurgent;
05490 }
05491 }
05492 }
05493 return 0;
05494 }
05495
05496 ast_copy_string(tmp, mailbox, sizeof(tmp));
05497
05498 if ((context = strchr(tmp, '@')))
05499 *context++ = '\0';
05500 else
05501 context = "default";
05502
05503 if (newmsgs)
05504 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05505 if (oldmsgs)
05506 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05507 if (urgentmsgs)
05508 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05509
05510 return 0;
05511 }
05512
05513 #endif
05514
05515
05516 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05517 {
05518 int urgentmsgs = 0;
05519 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05520 if (newmsgs) {
05521 *newmsgs += urgentmsgs;
05522 }
05523 return res;
05524 }
05525
05526 static void run_externnotify(char *context, char *extension, const char *flag)
05527 {
05528 char arguments[255];
05529 char ext_context[256] = "";
05530 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05531 struct ast_smdi_mwi_message *mwi_msg;
05532
05533 if (!ast_strlen_zero(context))
05534 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05535 else
05536 ast_copy_string(ext_context, extension, sizeof(ext_context));
05537
05538 if (smdi_iface) {
05539 if (ast_app_has_voicemail(ext_context, NULL))
05540 ast_smdi_mwi_set(smdi_iface, extension);
05541 else
05542 ast_smdi_mwi_unset(smdi_iface, extension);
05543
05544 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05545 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05546 if (!strncmp(mwi_msg->cause, "INV", 3))
05547 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05548 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05549 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05550 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05551 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05552 } else {
05553 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05554 }
05555 }
05556
05557 if (!ast_strlen_zero(externnotify)) {
05558 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05559 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05560 } else {
05561 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05562 ast_debug(1, "Executing %s\n", arguments);
05563 ast_safe_system(arguments);
05564 }
05565 }
05566 }
05567
05568
05569
05570
05571
05572
05573 struct leave_vm_options {
05574 unsigned int flags;
05575 signed char record_gain;
05576 char *exitcontext;
05577 };
05578
05579
05580
05581
05582
05583
05584
05585
05586
05587
05588
05589 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05590 {
05591 #ifdef IMAP_STORAGE
05592 int newmsgs, oldmsgs;
05593 #else
05594 char urgdir[PATH_MAX];
05595 #endif
05596 char txtfile[PATH_MAX];
05597 char tmptxtfile[PATH_MAX];
05598 struct vm_state *vms = NULL;
05599 char callerid[256];
05600 FILE *txt;
05601 char date[256];
05602 int txtdes;
05603 int res = 0;
05604 int msgnum;
05605 int duration = 0;
05606 int sound_duration = 0;
05607 int ausemacro = 0;
05608 int ousemacro = 0;
05609 int ouseexten = 0;
05610 char tmpdur[16];
05611 char priority[16];
05612 char origtime[16];
05613 char dir[PATH_MAX];
05614 char tmpdir[PATH_MAX];
05615 char fn[PATH_MAX];
05616 char prefile[PATH_MAX] = "";
05617 char tempfile[PATH_MAX] = "";
05618 char ext_context[256] = "";
05619 char fmt[80];
05620 char *context;
05621 char ecodes[17] = "#";
05622 struct ast_str *tmp = ast_str_create(16);
05623 char *tmpptr;
05624 struct ast_vm_user *vmu;
05625 struct ast_vm_user svm;
05626 const char *category = NULL;
05627 const char *code;
05628 const char *alldtmf = "0123456789ABCD*#";
05629 char flag[80];
05630
05631 if (!tmp) {
05632 return -1;
05633 }
05634
05635 ast_str_set(&tmp, 0, "%s", ext);
05636 ext = ast_str_buffer(tmp);
05637 if ((context = strchr(ext, '@'))) {
05638 *context++ = '\0';
05639 tmpptr = strchr(context, '&');
05640 } else {
05641 tmpptr = strchr(ext, '&');
05642 }
05643
05644 if (tmpptr)
05645 *tmpptr++ = '\0';
05646
05647 ast_channel_lock(chan);
05648 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05649 category = ast_strdupa(category);
05650 }
05651 ast_channel_unlock(chan);
05652
05653 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05654 ast_copy_string(flag, "Urgent", sizeof(flag));
05655 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05656 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05657 } else {
05658 flag[0] = '\0';
05659 }
05660
05661 ast_debug(3, "Before find_user\n");
05662 if (!(vmu = find_user(&svm, context, ext))) {
05663 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05664 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05665 ast_free(tmp);
05666 return res;
05667 }
05668
05669 if (strcmp(vmu->context, "default"))
05670 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05671 else
05672 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05673
05674
05675
05676
05677
05678
05679 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05680 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05681 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05682 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05683 }
05684
05685
05686
05687
05688 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05689 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05690 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05691 ast_free(tmp);
05692 return -1;
05693 }
05694 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05695 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05696 ast_copy_string(prefile, tempfile, sizeof(prefile));
05697
05698 DISPOSE(tempfile, -1);
05699
05700 #ifndef IMAP_STORAGE
05701 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05702 #else
05703 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05704 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05705 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05706 }
05707 #endif
05708
05709
05710 if (ast_test_flag(vmu, VM_OPERATOR)) {
05711 if (!ast_strlen_zero(vmu->exit)) {
05712 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05713 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05714 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05715 ouseexten = 1;
05716 }
05717 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05718 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05719 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05720 ouseexten = 1;
05721 } else if (!ast_strlen_zero(chan->macrocontext)
05722 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05723 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05724 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05725 ousemacro = 1;
05726 }
05727 }
05728
05729 if (!ast_strlen_zero(vmu->exit)) {
05730 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05731 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05732 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05733 }
05734 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05735 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05736 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05737 } else if (!ast_strlen_zero(chan->macrocontext)
05738 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05739 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05740 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05741 ausemacro = 1;
05742 }
05743
05744 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05745 for (code = alldtmf; *code; code++) {
05746 char e[2] = "";
05747 e[0] = *code;
05748 if (strchr(ecodes, e[0]) == NULL
05749 && ast_canmatch_extension(chan,
05750 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05751 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05752 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05753 }
05754 }
05755 }
05756
05757
05758 if (!ast_strlen_zero(prefile)) {
05759 #ifdef ODBC_STORAGE
05760 int success =
05761 #endif
05762 RETRIEVE(prefile, -1, ext, context);
05763 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05764 if (ast_streamfile(chan, prefile, chan->language) > -1)
05765 res = ast_waitstream(chan, ecodes);
05766 #ifdef ODBC_STORAGE
05767 if (success == -1) {
05768
05769 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05770 store_file(prefile, vmu->mailbox, vmu->context, -1);
05771 }
05772 #endif
05773 } else {
05774 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05775 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05776 }
05777 DISPOSE(prefile, -1);
05778 if (res < 0) {
05779 ast_debug(1, "Hang up during prefile playback\n");
05780 free_user(vmu);
05781 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05782 ast_free(tmp);
05783 return -1;
05784 }
05785 }
05786 if (res == '#') {
05787
05788 ast_set_flag(options, OPT_SILENT);
05789 res = 0;
05790 }
05791
05792 if (vmu->maxmsg == 0) {
05793 if (option_debug > 2)
05794 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05795 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05796 goto leave_vm_out;
05797 }
05798 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05799 res = ast_stream_and_wait(chan, INTRO, ecodes);
05800 if (res == '#') {
05801 ast_set_flag(options, OPT_SILENT);
05802 res = 0;
05803 }
05804 }
05805 if (res > 0)
05806 ast_stopstream(chan);
05807
05808
05809 if (res == '*') {
05810 chan->exten[0] = 'a';
05811 chan->exten[1] = '\0';
05812 if (!ast_strlen_zero(vmu->exit)) {
05813 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05814 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05815 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05816 }
05817 chan->priority = 0;
05818 free_user(vmu);
05819 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05820 ast_free(tmp);
05821 return 0;
05822 }
05823
05824
05825 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05826 transfer:
05827 if (ouseexten || ousemacro) {
05828 chan->exten[0] = 'o';
05829 chan->exten[1] = '\0';
05830 if (!ast_strlen_zero(vmu->exit)) {
05831 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05832 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05833 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05834 }
05835 ast_play_and_wait(chan, "transfer");
05836 chan->priority = 0;
05837 free_user(vmu);
05838 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05839 }
05840 ast_free(tmp);
05841 return OPERATOR_EXIT;
05842 }
05843
05844
05845 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05846 if (!ast_strlen_zero(options->exitcontext)) {
05847 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05848 }
05849 free_user(vmu);
05850 ast_free(tmp);
05851 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05852 return res;
05853 }
05854
05855 if (res < 0) {
05856 free_user(vmu);
05857 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05858 ast_free(tmp);
05859 return -1;
05860 }
05861
05862 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05863 if (!ast_strlen_zero(fmt)) {
05864 msgnum = 0;
05865
05866 #ifdef IMAP_STORAGE
05867
05868
05869 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05870 if (res < 0) {
05871 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05872 ast_free(tmp);
05873 return -1;
05874 }
05875 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05876
05877
05878
05879
05880 if (!(vms = create_vm_state_from_user(vmu))) {
05881 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05882 ast_free(tmp);
05883 return -1;
05884 }
05885 }
05886 vms->newmessages++;
05887
05888
05889 msgnum = newmsgs + oldmsgs;
05890 ast_debug(3, "Messagecount set to %d\n", msgnum);
05891 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05892
05893 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05894
05895 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05896 goto leave_vm_out;
05897 }
05898 #else
05899 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05900 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05901 if (!res)
05902 res = ast_waitstream(chan, "");
05903 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05904 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05905 inprocess_count(vmu->mailbox, vmu->context, -1);
05906 goto leave_vm_out;
05907 }
05908
05909 #endif
05910 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05911 txtdes = mkstemp(tmptxtfile);
05912 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05913 if (txtdes < 0) {
05914 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05915 if (!res)
05916 res = ast_waitstream(chan, "");
05917 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05918 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05919 inprocess_count(vmu->mailbox, vmu->context, -1);
05920 goto leave_vm_out;
05921 }
05922
05923
05924 if (res >= 0) {
05925
05926 res = ast_stream_and_wait(chan, "beep", "");
05927 }
05928
05929
05930 if (ast_check_realtime("voicemail_data")) {
05931 snprintf(priority, sizeof(priority), "%d", chan->priority);
05932 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05933 get_date(date, sizeof(date));
05934 ast_callerid_merge(callerid, sizeof(callerid),
05935 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05936 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05937 "Unknown");
05938 ast_store_realtime("voicemail_data",
05939 "origmailbox", ext,
05940 "context", chan->context,
05941 "macrocontext", chan->macrocontext,
05942 "exten", chan->exten,
05943 "priority", priority,
05944 "callerchan", chan->name,
05945 "callerid", callerid,
05946 "origdate", date,
05947 "origtime", origtime,
05948 "category", S_OR(category, ""),
05949 "filename", tmptxtfile,
05950 SENTINEL);
05951 }
05952
05953
05954 txt = fdopen(txtdes, "w+");
05955 if (txt) {
05956 get_date(date, sizeof(date));
05957 ast_callerid_merge(callerid, sizeof(callerid),
05958 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05959 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05960 "Unknown");
05961 fprintf(txt,
05962 ";\n"
05963 "; Message Information file\n"
05964 ";\n"
05965 "[message]\n"
05966 "origmailbox=%s\n"
05967 "context=%s\n"
05968 "macrocontext=%s\n"
05969 "exten=%s\n"
05970 "rdnis=%s\n"
05971 "priority=%d\n"
05972 "callerchan=%s\n"
05973 "callerid=%s\n"
05974 "origdate=%s\n"
05975 "origtime=%ld\n"
05976 "category=%s\n",
05977 ext,
05978 chan->context,
05979 chan->macrocontext,
05980 chan->exten,
05981 S_COR(chan->redirecting.from.number.valid,
05982 chan->redirecting.from.number.str, "unknown"),
05983 chan->priority,
05984 chan->name,
05985 callerid,
05986 date, (long) time(NULL),
05987 category ? category : "");
05988 } else {
05989 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05990 inprocess_count(vmu->mailbox, vmu->context, -1);
05991 if (ast_check_realtime("voicemail_data")) {
05992 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05993 }
05994 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05995 goto leave_vm_out;
05996 }
05997 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05998
05999 if (txt) {
06000 fprintf(txt, "flag=%s\n", flag);
06001 if (sound_duration < vmu->minsecs) {
06002 fclose(txt);
06003 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06004 ast_filedelete(tmptxtfile, NULL);
06005 unlink(tmptxtfile);
06006 if (ast_check_realtime("voicemail_data")) {
06007 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06008 }
06009 inprocess_count(vmu->mailbox, vmu->context, -1);
06010 } else {
06011 fprintf(txt, "duration=%d\n", duration);
06012 fclose(txt);
06013 if (vm_lock_path(dir)) {
06014 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06015
06016 ast_filedelete(tmptxtfile, NULL);
06017 unlink(tmptxtfile);
06018 inprocess_count(vmu->mailbox, vmu->context, -1);
06019 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06020 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06021 unlink(tmptxtfile);
06022 ast_unlock_path(dir);
06023 inprocess_count(vmu->mailbox, vmu->context, -1);
06024 if (ast_check_realtime("voicemail_data")) {
06025 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06026 }
06027 } else {
06028 #ifndef IMAP_STORAGE
06029 msgnum = last_message_index(vmu, dir) + 1;
06030 #endif
06031 make_file(fn, sizeof(fn), dir, msgnum);
06032
06033
06034 #ifndef IMAP_STORAGE
06035 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06036 #else
06037 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06038 #endif
06039
06040 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06041 ast_filerename(tmptxtfile, fn, NULL);
06042 rename(tmptxtfile, txtfile);
06043 inprocess_count(vmu->mailbox, vmu->context, -1);
06044
06045
06046
06047 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06048 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06049
06050 ast_unlock_path(dir);
06051 if (ast_check_realtime("voicemail_data")) {
06052 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06053 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06054 }
06055
06056
06057
06058 if (ast_fileexists(fn, NULL, NULL) > 0) {
06059 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06060 }
06061
06062
06063 while (tmpptr) {
06064 struct ast_vm_user recipu, *recip;
06065 char *exten, *cntx;
06066
06067 exten = strsep(&tmpptr, "&");
06068 cntx = strchr(exten, '@');
06069 if (cntx) {
06070 *cntx = '\0';
06071 cntx++;
06072 }
06073 if ((recip = find_user(&recipu, cntx, exten))) {
06074 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06075 free_user(recip);
06076 }
06077 }
06078 #ifndef IMAP_STORAGE
06079 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06080
06081 char sfn[PATH_MAX];
06082 char dfn[PATH_MAX];
06083 int x;
06084
06085 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06086 x = last_message_index(vmu, urgdir) + 1;
06087 make_file(sfn, sizeof(sfn), dir, msgnum);
06088 make_file(dfn, sizeof(dfn), urgdir, x);
06089 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06090 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06091
06092 ast_copy_string(fn, dfn, sizeof(fn));
06093 msgnum = x;
06094 }
06095 #endif
06096
06097 if (ast_fileexists(fn, NULL, NULL)) {
06098 #ifdef IMAP_STORAGE
06099 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06100 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06101 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06102 flag);
06103 #else
06104 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06105 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06106 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06107 flag);
06108 #endif
06109 }
06110
06111
06112 if (ast_fileexists(fn, NULL, NULL)) {
06113 DISPOSE(dir, msgnum);
06114 }
06115 }
06116 }
06117 } else {
06118 inprocess_count(vmu->mailbox, vmu->context, -1);
06119 }
06120 if (res == '0') {
06121 goto transfer;
06122 } else if (res > 0 && res != 't')
06123 res = 0;
06124
06125 if (sound_duration < vmu->minsecs)
06126
06127 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06128 else
06129 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06130 } else
06131 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06132 leave_vm_out:
06133 free_user(vmu);
06134
06135 #ifdef IMAP_STORAGE
06136
06137 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06138 if (expungeonhangup == 1) {
06139 ast_mutex_lock(&vms->lock);
06140 #ifdef HAVE_IMAP_TK2006
06141 if (LEVELUIDPLUS (vms->mailstream)) {
06142 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06143 } else
06144 #endif
06145 mail_expunge(vms->mailstream);
06146 ast_mutex_unlock(&vms->lock);
06147 }
06148 #endif
06149
06150 ast_free(tmp);
06151 return res;
06152 }
06153
06154 #if !defined(IMAP_STORAGE)
06155 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06156 {
06157
06158
06159 int x, dest;
06160 char sfn[PATH_MAX];
06161 char dfn[PATH_MAX];
06162
06163 if (vm_lock_path(dir)) {
06164 return ERROR_LOCK_PATH;
06165 }
06166
06167 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06168 make_file(sfn, sizeof(sfn), dir, x);
06169 if (EXISTS(dir, x, sfn, NULL)) {
06170
06171 if (x != dest) {
06172 make_file(dfn, sizeof(dfn), dir, dest);
06173 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06174 }
06175
06176 dest++;
06177 }
06178 }
06179 ast_unlock_path(dir);
06180
06181 return dest;
06182 }
06183 #endif
06184
06185 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06186 {
06187 int d;
06188 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06189 return d;
06190 }
06191
06192 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06193 {
06194 #ifdef IMAP_STORAGE
06195
06196
06197 char sequence[10];
06198 char mailbox[256];
06199 int res;
06200
06201
06202 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06203
06204 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06205 ast_mutex_lock(&vms->lock);
06206
06207 if (box == OLD_FOLDER) {
06208 mail_setflag(vms->mailstream, sequence, "\\Seen");
06209 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06210 } else if (box == NEW_FOLDER) {
06211 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06212 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06213 }
06214 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06215 ast_mutex_unlock(&vms->lock);
06216 return 0;
06217 }
06218
06219 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06220 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06221 if (mail_create(vms->mailstream, mailbox) == NIL)
06222 ast_debug(5, "Folder exists.\n");
06223 else
06224 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06225 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06226 ast_mutex_unlock(&vms->lock);
06227 return res;
06228 #else
06229 char *dir = vms->curdir;
06230 char *username = vms->username;
06231 char *context = vmu->context;
06232 char sfn[PATH_MAX];
06233 char dfn[PATH_MAX];
06234 char ddir[PATH_MAX];
06235 const char *dbox = mbox(vmu, box);
06236 int x, i;
06237 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06238
06239 if (vm_lock_path(ddir))
06240 return ERROR_LOCK_PATH;
06241
06242 x = last_message_index(vmu, ddir) + 1;
06243
06244 if (box == 10 && x >= vmu->maxdeletedmsg) {
06245 x--;
06246 for (i = 1; i <= x; i++) {
06247
06248 make_file(sfn, sizeof(sfn), ddir, i);
06249 make_file(dfn, sizeof(dfn), ddir, i - 1);
06250 if (EXISTS(ddir, i, sfn, NULL)) {
06251 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06252 } else
06253 break;
06254 }
06255 } else {
06256 if (x >= vmu->maxmsg) {
06257 ast_unlock_path(ddir);
06258 return -1;
06259 }
06260 }
06261 make_file(sfn, sizeof(sfn), dir, msg);
06262 make_file(dfn, sizeof(dfn), ddir, x);
06263 if (strcmp(sfn, dfn)) {
06264 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06265 }
06266 ast_unlock_path(ddir);
06267 #endif
06268 return 0;
06269 }
06270
06271 static int adsi_logo(unsigned char *buf)
06272 {
06273 int bytes = 0;
06274 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06275 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06276 return bytes;
06277 }
06278
06279 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06280 {
06281 unsigned char buf[256];
06282 int bytes = 0;
06283 int x;
06284 char num[5];
06285
06286 *useadsi = 0;
06287 bytes += ast_adsi_data_mode(buf + bytes);
06288 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06289
06290 bytes = 0;
06291 bytes += adsi_logo(buf);
06292 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06293 #ifdef DISPLAY
06294 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06295 #endif
06296 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06297 bytes += ast_adsi_data_mode(buf + bytes);
06298 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06299
06300 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06301 bytes = 0;
06302 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06303 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06304 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06305 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06306 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06307 return 0;
06308 }
06309
06310 #ifdef DISPLAY
06311
06312 bytes = 0;
06313 bytes += ast_adsi_logo(buf);
06314 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06315 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06316 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06317 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06318 #endif
06319 bytes = 0;
06320 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06321 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06322 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06323 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06324 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06325 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06326 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06327
06328 #ifdef DISPLAY
06329
06330 bytes = 0;
06331 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06332 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06333
06334 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06335 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06336 #endif
06337
06338 bytes = 0;
06339
06340 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06341 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06342 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06343 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06344 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06345 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06346 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06347
06348 #ifdef DISPLAY
06349
06350 bytes = 0;
06351 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06352 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06353 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06354 #endif
06355
06356 bytes = 0;
06357 for (x = 0; x < 5; x++) {
06358 snprintf(num, sizeof(num), "%d", x);
06359 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06360 }
06361 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06362 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06363
06364 #ifdef DISPLAY
06365
06366 bytes = 0;
06367 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06368 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06369 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06370 #endif
06371
06372 if (ast_adsi_end_download(chan)) {
06373 bytes = 0;
06374 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06375 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06376 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06377 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06378 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06379 return 0;
06380 }
06381 bytes = 0;
06382 bytes += ast_adsi_download_disconnect(buf + bytes);
06383 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06384 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06385
06386 ast_debug(1, "Done downloading scripts...\n");
06387
06388 #ifdef DISPLAY
06389
06390 bytes = 0;
06391 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06392 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06393 #endif
06394 ast_debug(1, "Restarting session...\n");
06395
06396 bytes = 0;
06397
06398 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06399 *useadsi = 1;
06400 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06401 } else
06402 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06403
06404 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06405 return 0;
06406 }
06407
06408 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06409 {
06410 int x;
06411 if (!ast_adsi_available(chan))
06412 return;
06413 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06414 if (x < 0)
06415 return;
06416 if (!x) {
06417 if (adsi_load_vmail(chan, useadsi)) {
06418 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06419 return;
06420 }
06421 } else
06422 *useadsi = 1;
06423 }
06424
06425 static void adsi_login(struct ast_channel *chan)
06426 {
06427 unsigned char buf[256];
06428 int bytes = 0;
06429 unsigned char keys[8];
06430 int x;
06431 if (!ast_adsi_available(chan))
06432 return;
06433
06434 for (x = 0; x < 8; x++)
06435 keys[x] = 0;
06436
06437 keys[3] = ADSI_KEY_APPS + 3;
06438
06439 bytes += adsi_logo(buf + bytes);
06440 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06441 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06442 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06443 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06444 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06445 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06446 bytes += ast_adsi_set_keys(buf + bytes, keys);
06447 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06448 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06449 }
06450
06451 static void adsi_password(struct ast_channel *chan)
06452 {
06453 unsigned char buf[256];
06454 int bytes = 0;
06455 unsigned char keys[8];
06456 int x;
06457 if (!ast_adsi_available(chan))
06458 return;
06459
06460 for (x = 0; x < 8; x++)
06461 keys[x] = 0;
06462
06463 keys[3] = ADSI_KEY_APPS + 3;
06464
06465 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06466 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06467 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06468 bytes += ast_adsi_set_keys(buf + bytes, keys);
06469 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06470 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06471 }
06472
06473 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06474 {
06475 unsigned char buf[256];
06476 int bytes = 0;
06477 unsigned char keys[8];
06478 int x, y;
06479
06480 if (!ast_adsi_available(chan))
06481 return;
06482
06483 for (x = 0; x < 5; x++) {
06484 y = ADSI_KEY_APPS + 12 + start + x;
06485 if (y > ADSI_KEY_APPS + 12 + 4)
06486 y = 0;
06487 keys[x] = ADSI_KEY_SKT | y;
06488 }
06489 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06490 keys[6] = 0;
06491 keys[7] = 0;
06492
06493 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06494 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06495 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06496 bytes += ast_adsi_set_keys(buf + bytes, keys);
06497 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06498
06499 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06500 }
06501
06502 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06503 {
06504 int bytes = 0;
06505 unsigned char buf[256];
06506 char buf1[256], buf2[256];
06507 char fn2[PATH_MAX];
06508
06509 char cid[256] = "";
06510 char *val;
06511 char *name, *num;
06512 char datetime[21] = "";
06513 FILE *f;
06514
06515 unsigned char keys[8];
06516
06517 int x;
06518
06519 if (!ast_adsi_available(chan))
06520 return;
06521
06522
06523 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06524 f = fopen(fn2, "r");
06525 if (f) {
06526 while (!feof(f)) {
06527 if (!fgets((char *) buf, sizeof(buf), f)) {
06528 continue;
06529 }
06530 if (!feof(f)) {
06531 char *stringp = NULL;
06532 stringp = (char *) buf;
06533 strsep(&stringp, "=");
06534 val = strsep(&stringp, "=");
06535 if (!ast_strlen_zero(val)) {
06536 if (!strcmp((char *) buf, "callerid"))
06537 ast_copy_string(cid, val, sizeof(cid));
06538 if (!strcmp((char *) buf, "origdate"))
06539 ast_copy_string(datetime, val, sizeof(datetime));
06540 }
06541 }
06542 }
06543 fclose(f);
06544 }
06545
06546 for (x = 0; x < 5; x++)
06547 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06548 keys[6] = 0x0;
06549 keys[7] = 0x0;
06550
06551 if (!vms->curmsg) {
06552
06553 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06554 }
06555 if (vms->curmsg >= vms->lastmsg) {
06556
06557 if (vms->curmsg) {
06558
06559 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06560 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06561
06562 } else {
06563
06564 keys[3] = 1;
06565 }
06566 }
06567
06568 if (!ast_strlen_zero(cid)) {
06569 ast_callerid_parse(cid, &name, &num);
06570 if (!name)
06571 name = num;
06572 } else
06573 name = "Unknown Caller";
06574
06575
06576 #ifdef IMAP_STORAGE
06577 ast_mutex_lock(&vms->lock);
06578 #endif
06579 if (vms->deleted[vms->curmsg]) {
06580 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06581 }
06582 #ifdef IMAP_STORAGE
06583 ast_mutex_unlock(&vms->lock);
06584 #endif
06585
06586
06587 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06588 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06589 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06590 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06591
06592 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06593 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06594 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06595 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06596 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06597 bytes += ast_adsi_set_keys(buf + bytes, keys);
06598 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06599
06600 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06601 }
06602
06603 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06604 {
06605 int bytes = 0;
06606 unsigned char buf[256];
06607 unsigned char keys[8];
06608
06609 int x;
06610
06611 if (!ast_adsi_available(chan))
06612 return;
06613
06614
06615 for (x = 0; x < 5; x++)
06616 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06617
06618 keys[6] = 0x0;
06619 keys[7] = 0x0;
06620
06621 if (!vms->curmsg) {
06622
06623 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06624 }
06625 if (vms->curmsg >= vms->lastmsg) {
06626
06627 if (vms->curmsg) {
06628
06629 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06630 } else {
06631
06632 keys[3] = 1;
06633 }
06634 }
06635
06636
06637 #ifdef IMAP_STORAGE
06638 ast_mutex_lock(&vms->lock);
06639 #endif
06640 if (vms->deleted[vms->curmsg]) {
06641 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06642 }
06643 #ifdef IMAP_STORAGE
06644 ast_mutex_unlock(&vms->lock);
06645 #endif
06646
06647
06648 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06649 bytes += ast_adsi_set_keys(buf + bytes, keys);
06650 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06651
06652 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06653 }
06654
06655 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06656 {
06657 unsigned char buf[256] = "";
06658 char buf1[256] = "", buf2[256] = "";
06659 int bytes = 0;
06660 unsigned char keys[8];
06661 int x;
06662
06663 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06664 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06665 if (!ast_adsi_available(chan))
06666 return;
06667 if (vms->newmessages) {
06668 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06669 if (vms->oldmessages) {
06670 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06671 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06672 } else {
06673 snprintf(buf2, sizeof(buf2), "%s.", newm);
06674 }
06675 } else if (vms->oldmessages) {
06676 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06677 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06678 } else {
06679 strcpy(buf1, "You have no messages.");
06680 buf2[0] = ' ';
06681 buf2[1] = '\0';
06682 }
06683 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06684 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06685 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06686
06687 for (x = 0; x < 6; x++)
06688 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06689 keys[6] = 0;
06690 keys[7] = 0;
06691
06692
06693 if (vms->lastmsg < 0)
06694 keys[0] = 1;
06695 bytes += ast_adsi_set_keys(buf + bytes, keys);
06696
06697 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06698
06699 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06700 }
06701
06702 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06703 {
06704 unsigned char buf[256] = "";
06705 char buf1[256] = "", buf2[256] = "";
06706 int bytes = 0;
06707 unsigned char keys[8];
06708 int x;
06709
06710 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06711
06712 if (!ast_adsi_available(chan))
06713 return;
06714
06715
06716 for (x = 0; x < 6; x++)
06717 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06718
06719 keys[6] = 0;
06720 keys[7] = 0;
06721
06722 if ((vms->lastmsg + 1) < 1)
06723 keys[0] = 0;
06724
06725 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06726 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06727
06728 if (vms->lastmsg + 1)
06729 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06730 else
06731 strcpy(buf2, "no messages.");
06732 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06733 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06734 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06735 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06736 bytes += ast_adsi_set_keys(buf + bytes, keys);
06737
06738 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06739
06740 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06741
06742 }
06743
06744
06745
06746
06747
06748
06749
06750
06751
06752
06753
06754
06755
06756
06757
06758 static void adsi_goodbye(struct ast_channel *chan)
06759 {
06760 unsigned char buf[256];
06761 int bytes = 0;
06762
06763 if (!ast_adsi_available(chan))
06764 return;
06765 bytes += adsi_logo(buf + bytes);
06766 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06767 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06768 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06769 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06770
06771 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06772 }
06773
06774
06775
06776
06777
06778 static int get_folder(struct ast_channel *chan, int start)
06779 {
06780 int x;
06781 int d;
06782 char fn[PATH_MAX];
06783 d = ast_play_and_wait(chan, "vm-press");
06784 if (d)
06785 return d;
06786 for (x = start; x < 5; x++) {
06787 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06788 return d;
06789 d = ast_play_and_wait(chan, "vm-for");
06790 if (d)
06791 return d;
06792 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06793
06794
06795
06796
06797 if (x == 0) {
06798 if (ast_fileexists(fn, NULL, NULL)) {
06799 d = vm_play_folder_name(chan, fn);
06800 } else {
06801 ast_verb(1, "failed to find %s\n", fn);
06802 d = vm_play_folder_name(chan, "vm-INBOX");
06803 }
06804 } else {
06805 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06806 d = vm_play_folder_name(chan, fn);
06807 }
06808
06809 if (d)
06810 return d;
06811 d = ast_waitfordigit(chan, 500);
06812 if (d)
06813 return d;
06814 }
06815
06816 d = ast_play_and_wait(chan, "vm-tocancel");
06817 if (d)
06818 return d;
06819 d = ast_waitfordigit(chan, 4000);
06820 return d;
06821 }
06822
06823
06824
06825
06826
06827
06828
06829
06830
06831
06832
06833
06834
06835 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06836 {
06837 int res = 0;
06838 int loops = 0;
06839
06840 res = ast_play_and_wait(chan, fn);
06841 while (((res < '0') || (res > '9')) &&
06842 (res != '#') && (res >= 0) &&
06843 loops < 4) {
06844 res = get_folder(chan, 0);
06845 loops++;
06846 }
06847 if (loops == 4) {
06848 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06849 return '#';
06850 }
06851 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06852 return res;
06853 }
06854
06855
06856
06857
06858
06859
06860
06861
06862
06863
06864
06865
06866
06867
06868
06869
06870
06871
06872
06873 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06874 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06875 {
06876 int cmd = 0;
06877 int retries = 0, prepend_duration = 0, already_recorded = 0;
06878 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06879 char textfile[PATH_MAX];
06880 struct ast_config *msg_cfg;
06881 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06882 #ifndef IMAP_STORAGE
06883 signed char zero_gain = 0;
06884 #endif
06885 const char *duration_str;
06886
06887
06888 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06889 strcpy(textfile, msgfile);
06890 strcpy(backup, msgfile);
06891 strcpy(backup_textfile, msgfile);
06892 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06893 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06894 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06895
06896 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06897 *duration = atoi(duration_str);
06898 } else {
06899 *duration = 0;
06900 }
06901
06902 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06903 if (cmd)
06904 retries = 0;
06905 switch (cmd) {
06906 case '1':
06907
06908 #ifdef IMAP_STORAGE
06909
06910 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06911 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06912 ast_play_and_wait(chan, INTRO);
06913 ast_play_and_wait(chan, "beep");
06914 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06915 if (cmd == -1) {
06916 break;
06917 }
06918 cmd = 't';
06919 #else
06920
06921
06922
06923 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06924 strcpy(textfile, msgfile);
06925 strncat(textfile, ".txt", sizeof(textfile) - 1);
06926 *duration = 0;
06927
06928
06929 if (!msg_cfg) {
06930 cmd = 0;
06931 break;
06932 }
06933
06934
06935 #ifndef IMAP_STORAGE
06936 if (already_recorded) {
06937 ast_filecopy(backup, msgfile, NULL);
06938 copy(backup_textfile, textfile);
06939 }
06940 else {
06941 ast_filecopy(msgfile, backup, NULL);
06942 copy(textfile, backup_textfile);
06943 }
06944 #endif
06945 already_recorded = 1;
06946
06947 if (record_gain)
06948 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06949
06950 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06951
06952 if (cmd == 'S') {
06953 ast_stream_and_wait(chan, vm_pls_try_again, "");
06954 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06955 ast_filerename(backup, msgfile, NULL);
06956 }
06957
06958 if (record_gain)
06959 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06960
06961
06962 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06963 *duration = atoi(duration_str);
06964
06965 if (prepend_duration) {
06966 struct ast_category *msg_cat;
06967
06968 char duration_buf[12];
06969
06970 *duration += prepend_duration;
06971 msg_cat = ast_category_get(msg_cfg, "message");
06972 snprintf(duration_buf, 11, "%ld", *duration);
06973 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06974 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06975 }
06976 }
06977
06978 #endif
06979 break;
06980 case '2':
06981
06982 #ifdef IMAP_STORAGE
06983 *vms->introfn = '\0';
06984 #endif
06985 cmd = 't';
06986 break;
06987 case '*':
06988 cmd = '*';
06989 break;
06990 default:
06991
06992 already_recorded = 0;
06993
06994 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06995
06996 if (!cmd) {
06997 cmd = ast_play_and_wait(chan, "vm-starmain");
06998
06999 }
07000 if (!cmd) {
07001 cmd = ast_waitfordigit(chan, 6000);
07002 }
07003 if (!cmd) {
07004 retries++;
07005 }
07006 if (retries > 3) {
07007 cmd = '*';
07008 }
07009 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07010 }
07011 }
07012
07013 if (msg_cfg)
07014 ast_config_destroy(msg_cfg);
07015 if (prepend_duration)
07016 *duration = prepend_duration;
07017
07018 if (already_recorded && cmd == -1) {
07019
07020 ast_filerename(backup, msgfile, NULL);
07021 rename(backup_textfile, textfile);
07022 }
07023
07024 if (cmd == 't' || cmd == 'S')
07025 cmd = 0;
07026 return cmd;
07027 }
07028
07029 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07030 {
07031 struct ast_event *event;
07032 char *mailbox, *context;
07033
07034
07035 context = mailbox = ast_strdupa(box);
07036 strsep(&context, "@");
07037 if (ast_strlen_zero(context))
07038 context = "default";
07039
07040 if (!(event = ast_event_new(AST_EVENT_MWI,
07041 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07042 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07043 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07044 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07045 AST_EVENT_IE_END))) {
07046 return;
07047 }
07048
07049 ast_event_queue_and_cache(event);
07050 }
07051
07052
07053
07054
07055
07056
07057
07058
07059
07060
07061
07062
07063
07064
07065
07066 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)
07067 {
07068 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07069 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07070 const char *category;
07071 char *myserveremail = serveremail;
07072
07073 ast_channel_lock(chan);
07074 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07075 category = ast_strdupa(category);
07076 }
07077 ast_channel_unlock(chan);
07078
07079 #ifndef IMAP_STORAGE
07080 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07081 #else
07082 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07083 #endif
07084 make_file(fn, sizeof(fn), todir, msgnum);
07085 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07086
07087 if (!ast_strlen_zero(vmu->attachfmt)) {
07088 if (strstr(fmt, vmu->attachfmt))
07089 fmt = vmu->attachfmt;
07090 else
07091 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);
07092 }
07093
07094
07095 fmt = ast_strdupa(fmt);
07096 stringp = fmt;
07097 strsep(&stringp, "|");
07098
07099 if (!ast_strlen_zero(vmu->serveremail))
07100 myserveremail = vmu->serveremail;
07101
07102 if (!ast_strlen_zero(vmu->email)) {
07103 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07104
07105 if (attach_user_voicemail)
07106 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07107
07108
07109 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07110
07111 if (attach_user_voicemail)
07112 DISPOSE(todir, msgnum);
07113 }
07114
07115 if (!ast_strlen_zero(vmu->pager)) {
07116 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07117 }
07118
07119 if (ast_test_flag(vmu, VM_DELETE))
07120 DELETE(todir, msgnum, fn, vmu);
07121
07122
07123 if (ast_app_has_voicemail(ext_context, NULL))
07124 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07125
07126 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07127
07128 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);
07129 run_externnotify(vmu->context, vmu->mailbox, flag);
07130
07131 #ifdef IMAP_STORAGE
07132 vm_delete(fn);
07133 if (ast_test_flag(vmu, VM_DELETE)) {
07134 vm_imap_delete(NULL, vms->curmsg, vmu);
07135 vms->newmessages--;
07136 }
07137 #endif
07138
07139 return 0;
07140 }
07141
07142
07143
07144
07145
07146
07147
07148
07149
07150
07151
07152
07153
07154
07155
07156
07157
07158
07159
07160
07161
07162
07163
07164
07165
07166
07167
07168
07169 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)
07170 {
07171 #ifdef IMAP_STORAGE
07172 int todircount = 0;
07173 struct vm_state *dstvms;
07174 #endif
07175 char username[70]="";
07176 char fn[PATH_MAX];
07177 char ecodes[16] = "#";
07178 int res = 0, cmd = 0;
07179 struct ast_vm_user *receiver = NULL, *vmtmp;
07180 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07181 char *stringp;
07182 const char *s;
07183 int saved_messages = 0;
07184 int valid_extensions = 0;
07185 char *dir;
07186 int curmsg;
07187 char urgent_str[7] = "";
07188 int prompt_played = 0;
07189 #ifndef IMAP_STORAGE
07190 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07191 #endif
07192 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07193 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07194 }
07195
07196 if (vms == NULL) return -1;
07197 dir = vms->curdir;
07198 curmsg = vms->curmsg;
07199
07200 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07201 while (!res && !valid_extensions) {
07202 int use_directory = 0;
07203 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07204 int done = 0;
07205 int retries = 0;
07206 cmd = 0;
07207 while ((cmd >= 0) && !done ){
07208 if (cmd)
07209 retries = 0;
07210 switch (cmd) {
07211 case '1':
07212 use_directory = 0;
07213 done = 1;
07214 break;
07215 case '2':
07216 use_directory = 1;
07217 done = 1;
07218 break;
07219 case '*':
07220 cmd = 't';
07221 done = 1;
07222 break;
07223 default:
07224
07225 cmd = ast_play_and_wait(chan, "vm-forward");
07226 if (!cmd) {
07227 cmd = ast_waitfordigit(chan, 3000);
07228 }
07229 if (!cmd) {
07230 retries++;
07231 }
07232 if (retries > 3) {
07233 cmd = 't';
07234 done = 1;
07235 }
07236 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07237 }
07238 }
07239 if (cmd < 0 || cmd == 't')
07240 break;
07241 }
07242
07243 if (use_directory) {
07244
07245
07246 char old_context[sizeof(chan->context)];
07247 char old_exten[sizeof(chan->exten)];
07248 int old_priority;
07249 struct ast_app* directory_app;
07250
07251 directory_app = pbx_findapp("Directory");
07252 if (directory_app) {
07253 char vmcontext[256];
07254
07255 memcpy(old_context, chan->context, sizeof(chan->context));
07256 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07257 old_priority = chan->priority;
07258
07259
07260 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07261 res = pbx_exec(chan, directory_app, vmcontext);
07262
07263 ast_copy_string(username, chan->exten, sizeof(username));
07264
07265
07266 memcpy(chan->context, old_context, sizeof(chan->context));
07267 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07268 chan->priority = old_priority;
07269 } else {
07270 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07271 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07272 }
07273 } else {
07274
07275 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07276 res = ast_streamfile(chan, "vm-extension", chan->language);
07277 prompt_played++;
07278 if (res || prompt_played > 4)
07279 break;
07280 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07281 break;
07282 }
07283
07284
07285 if (ast_strlen_zero(username))
07286 continue;
07287 stringp = username;
07288 s = strsep(&stringp, "*");
07289
07290 valid_extensions = 1;
07291 while (s) {
07292 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07293 int oldmsgs;
07294 int newmsgs;
07295 int capacity;
07296 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07297 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07298
07299 res = ast_play_and_wait(chan, "pbx-invalid");
07300 valid_extensions = 0;
07301 break;
07302 }
07303 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07304 if ((newmsgs + oldmsgs) >= capacity) {
07305 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07306 res = ast_play_and_wait(chan, "vm-mailboxfull");
07307 valid_extensions = 0;
07308 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07309 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07310 free_user(vmtmp);
07311 }
07312 inprocess_count(receiver->mailbox, receiver->context, -1);
07313 break;
07314 }
07315 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07316 } else {
07317
07318
07319
07320
07321
07322 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07323 free_user(receiver);
07324 }
07325 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07326
07327 res = ast_play_and_wait(chan, "pbx-invalid");
07328 valid_extensions = 0;
07329 break;
07330 }
07331
07332
07333 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07334 RETRIEVE(fn, -1, s, receiver->context);
07335 if (ast_fileexists(fn, NULL, NULL) > 0) {
07336 res = ast_stream_and_wait(chan, fn, ecodes);
07337 if (res) {
07338 DISPOSE(fn, -1);
07339 return res;
07340 }
07341 } else {
07342 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07343 }
07344 DISPOSE(fn, -1);
07345
07346 s = strsep(&stringp, "*");
07347 }
07348
07349 if (valid_extensions)
07350 break;
07351 }
07352
07353 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07354 return res;
07355 if (is_new_message == 1) {
07356 struct leave_vm_options leave_options;
07357 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07358 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07359
07360
07361 memset(&leave_options, 0, sizeof(leave_options));
07362 leave_options.record_gain = record_gain;
07363 cmd = leave_voicemail(chan, mailbox, &leave_options);
07364 } else {
07365
07366 long duration = 0;
07367 struct vm_state vmstmp;
07368 int copy_msg_result = 0;
07369 memcpy(&vmstmp, vms, sizeof(vmstmp));
07370
07371 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07372
07373 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07374 if (!cmd) {
07375 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07376 #ifdef IMAP_STORAGE
07377 int attach_user_voicemail;
07378 char *myserveremail = serveremail;
07379
07380
07381 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07382 if (!dstvms) {
07383 dstvms = create_vm_state_from_user(vmtmp);
07384 }
07385 if (dstvms) {
07386 init_mailstream(dstvms, 0);
07387 if (!dstvms->mailstream) {
07388 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07389 } else {
07390 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07391 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07392 }
07393 } else {
07394 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07395 }
07396 if (!ast_strlen_zero(vmtmp->serveremail))
07397 myserveremail = vmtmp->serveremail;
07398 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07399
07400 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07401 dstvms->curbox,
07402 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07403 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07404 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07405 NULL, urgent_str);
07406 #else
07407 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07408 #endif
07409 saved_messages++;
07410 AST_LIST_REMOVE_CURRENT(list);
07411 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07412 free_user(vmtmp);
07413 if (res)
07414 break;
07415 }
07416 AST_LIST_TRAVERSE_SAFE_END;
07417 if (saved_messages > 0 && !copy_msg_result) {
07418
07419
07420
07421
07422
07423
07424
07425
07426 #ifdef IMAP_STORAGE
07427
07428 if (ast_strlen_zero(vmstmp.introfn))
07429 #endif
07430 res = ast_play_and_wait(chan, "vm-msgsaved");
07431 }
07432 #ifndef IMAP_STORAGE
07433 else {
07434
07435 res = ast_play_and_wait(chan, "vm-mailboxfull");
07436 }
07437
07438 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07439 strcpy(textfile, msgfile);
07440 strcpy(backup, msgfile);
07441 strcpy(backup_textfile, msgfile);
07442 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07443 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07444 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07445 if (ast_fileexists(backup, NULL, NULL) > 0) {
07446 ast_filerename(backup, msgfile, NULL);
07447 rename(backup_textfile, textfile);
07448 }
07449 #endif
07450 }
07451 DISPOSE(dir, curmsg);
07452 #ifndef IMAP_STORAGE
07453 if (cmd) {
07454 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07455 strcpy(textfile, msgfile);
07456 strcpy(backup_textfile, msgfile);
07457 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07458 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07459 rename(backup_textfile, textfile);
07460 }
07461 #endif
07462 }
07463
07464
07465 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07466 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07467 free_user(vmtmp);
07468 }
07469 return res ? res : cmd;
07470 }
07471
07472 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07473 {
07474 int res;
07475 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07476 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07477 return res;
07478 }
07479
07480 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07481 {
07482 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07483 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);
07484 }
07485
07486 static int play_message_category(struct ast_channel *chan, const char *category)
07487 {
07488 int res = 0;
07489
07490 if (!ast_strlen_zero(category))
07491 res = ast_play_and_wait(chan, category);
07492
07493 if (res) {
07494 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07495 res = 0;
07496 }
07497
07498 return res;
07499 }
07500
07501 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07502 {
07503 int res = 0;
07504 struct vm_zone *the_zone = NULL;
07505 time_t t;
07506
07507 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07508 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07509 return 0;
07510 }
07511
07512
07513 if (!ast_strlen_zero(vmu->zonetag)) {
07514
07515 struct vm_zone *z;
07516 AST_LIST_LOCK(&zones);
07517 AST_LIST_TRAVERSE(&zones, z, list) {
07518 if (!strcmp(z->name, vmu->zonetag)) {
07519 the_zone = z;
07520 break;
07521 }
07522 }
07523 AST_LIST_UNLOCK(&zones);
07524 }
07525
07526
07527 #if 0
07528
07529 ast_localtime(&t, &time_now, NULL);
07530 tv_now = ast_tvnow();
07531 ast_localtime(&tv_now, &time_then, NULL);
07532
07533
07534 if (time_now.tm_year == time_then.tm_year)
07535 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07536 else
07537 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07538 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07539
07540
07541 #endif
07542 if (the_zone) {
07543 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07544 } else if (!strncasecmp(chan->language, "de", 2)) {
07545 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07546 } else if (!strncasecmp(chan->language, "gr", 2)) {
07547 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07548 } else if (!strncasecmp(chan->language, "it", 2)) {
07549 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);
07550 } else if (!strncasecmp(chan->language, "nl", 2)) {
07551 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07552 } else if (!strncasecmp(chan->language, "no", 2)) {
07553 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07554 } else if (!strncasecmp(chan->language, "pl", 2)) {
07555 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07556 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07557 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);
07558 } else if (!strncasecmp(chan->language, "se", 2)) {
07559 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07560 } else if (!strncasecmp(chan->language, "zh", 2)) {
07561 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07562 } else if (!strncasecmp(chan->language, "vi", 2)) {
07563 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);
07564 } else {
07565 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07566 }
07567 #if 0
07568 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07569 #endif
07570 return res;
07571 }
07572
07573
07574
07575 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07576 {
07577 int res = 0;
07578 int i;
07579 char *callerid, *name;
07580 char prefile[PATH_MAX] = "";
07581
07582
07583
07584
07585
07586
07587
07588
07589
07590 if ((cid == NULL)||(context == NULL))
07591 return res;
07592
07593
07594 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07595 ast_callerid_parse(cid, &name, &callerid);
07596 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07597
07598
07599 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07600 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07601 if ((strcmp(cidinternalcontexts[i], context) == 0))
07602 break;
07603 }
07604 if (i != MAX_NUM_CID_CONTEXTS){
07605 if (!res) {
07606 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07607 if (!ast_strlen_zero(prefile)) {
07608
07609 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07610 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07611 if (!callback)
07612 res = wait_file2(chan, vms, "vm-from");
07613 res = ast_stream_and_wait(chan, prefile, "");
07614 } else {
07615 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07616
07617 if (!callback)
07618 res = wait_file2(chan, vms, "vm-from-extension");
07619 res = ast_say_digit_str(chan, callerid, "", chan->language);
07620 }
07621 }
07622 }
07623 } else if (!res) {
07624 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07625
07626 if (!callback)
07627 res = wait_file2(chan, vms, "vm-from-phonenumber");
07628 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07629 }
07630 } else {
07631
07632 ast_debug(1, "VM-CID: From an unknown number\n");
07633
07634 res = wait_file2(chan, vms, "vm-unknown-caller");
07635 }
07636 return res;
07637 }
07638
07639 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07640 {
07641 int res = 0;
07642 int durationm;
07643 int durations;
07644
07645 if (duration == NULL)
07646 return res;
07647
07648
07649 durations = atoi(duration);
07650 durationm = (durations / 60);
07651
07652 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07653
07654 if ((!res) && (durationm >= minduration)) {
07655 res = wait_file2(chan, vms, "vm-duration");
07656
07657
07658 if (!strncasecmp(chan->language, "pl", 2)) {
07659 div_t num = div(durationm, 10);
07660
07661 if (durationm == 1) {
07662 res = ast_play_and_wait(chan, "digits/1z");
07663 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07664 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07665 if (num.rem == 2) {
07666 if (!num.quot) {
07667 res = ast_play_and_wait(chan, "digits/2-ie");
07668 } else {
07669 res = say_and_wait(chan, durationm - 2 , chan->language);
07670 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07671 }
07672 } else {
07673 res = say_and_wait(chan, durationm, chan->language);
07674 }
07675 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07676 } else {
07677 res = say_and_wait(chan, durationm, chan->language);
07678 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07679 }
07680
07681 } else {
07682 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07683 res = wait_file2(chan, vms, "vm-minutes");
07684 }
07685 }
07686 return res;
07687 }
07688
07689 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07690 {
07691 int res = 0;
07692 char filename[256], *cid;
07693 const char *origtime, *context, *category, *duration, *flag;
07694 struct ast_config *msg_cfg;
07695 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07696
07697 vms->starting = 0;
07698 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07699 adsi_message(chan, vms);
07700 if (!vms->curmsg) {
07701 res = wait_file2(chan, vms, "vm-first");
07702 } else if (vms->curmsg == vms->lastmsg) {
07703 res = wait_file2(chan, vms, "vm-last");
07704 }
07705
07706 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07707 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07708 msg_cfg = ast_config_load(filename, config_flags);
07709 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07710 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07711 return 0;
07712 }
07713 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07714
07715
07716 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07717 res = wait_file2(chan, vms, "vm-Urgent");
07718 }
07719
07720 if (!res) {
07721
07722
07723 if (!strncasecmp(chan->language, "pl", 2)) {
07724 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07725 int ten, one;
07726 char nextmsg[256];
07727 ten = (vms->curmsg + 1) / 10;
07728 one = (vms->curmsg + 1) % 10;
07729
07730 if (vms->curmsg < 20) {
07731 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07732 res = wait_file2(chan, vms, nextmsg);
07733 } else {
07734 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07735 res = wait_file2(chan, vms, nextmsg);
07736 if (one > 0) {
07737 if (!res) {
07738 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07739 res = wait_file2(chan, vms, nextmsg);
07740 }
07741 }
07742 }
07743 }
07744 if (!res)
07745 res = wait_file2(chan, vms, "vm-message");
07746
07747 } else if (!strncasecmp(chan->language, "he", 2)) {
07748 if (!vms->curmsg) {
07749 res = wait_file2(chan, vms, "vm-message");
07750 res = wait_file2(chan, vms, "vm-first");
07751 } else if (vms->curmsg == vms->lastmsg) {
07752 res = wait_file2(chan, vms, "vm-message");
07753 res = wait_file2(chan, vms, "vm-last");
07754 } else {
07755 res = wait_file2(chan, vms, "vm-message");
07756 res = wait_file2(chan, vms, "vm-number");
07757 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07758 }
07759
07760 } else if (!strncasecmp(chan->language, "vi", 2)) {
07761 if (!vms->curmsg) {
07762 res = wait_file2(chan, vms, "vm-message");
07763 res = wait_file2(chan, vms, "vm-first");
07764 } else if (vms->curmsg == vms->lastmsg) {
07765 res = wait_file2(chan, vms, "vm-message");
07766 res = wait_file2(chan, vms, "vm-last");
07767 } else {
07768 res = wait_file2(chan, vms, "vm-message");
07769 res = wait_file2(chan, vms, "vm-number");
07770 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07771 }
07772 } else {
07773 if (!strncasecmp(chan->language, "se", 2)) {
07774 res = wait_file2(chan, vms, "vm-meddelandet");
07775 } else {
07776 res = wait_file2(chan, vms, "vm-message");
07777 }
07778 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07779 if (!res) {
07780 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07781 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07782 }
07783 }
07784 }
07785 }
07786
07787 if (!msg_cfg) {
07788 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07789 return 0;
07790 }
07791
07792 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07793 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07794 DISPOSE(vms->curdir, vms->curmsg);
07795 ast_config_destroy(msg_cfg);
07796 return 0;
07797 }
07798
07799 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07800 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07801 category = ast_variable_retrieve(msg_cfg, "message", "category");
07802
07803 context = ast_variable_retrieve(msg_cfg, "message", "context");
07804 if (!strncasecmp("macro", context, 5))
07805 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07806 if (!res) {
07807 res = play_message_category(chan, category);
07808 }
07809 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07810 res = play_message_datetime(chan, vmu, origtime, filename);
07811 }
07812 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07813 res = play_message_callerid(chan, vms, cid, context, 0);
07814 }
07815 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07816 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07817 }
07818
07819 if (res == '1') {
07820 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07821 res = 0;
07822 }
07823 ast_config_destroy(msg_cfg);
07824
07825 if (!res) {
07826 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07827 #ifdef IMAP_STORAGE
07828 ast_mutex_lock(&vms->lock);
07829 #endif
07830 vms->heard[vms->curmsg] = 1;
07831 #ifdef IMAP_STORAGE
07832 ast_mutex_unlock(&vms->lock);
07833
07834
07835
07836 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07837 wait_file(chan, vms, vms->introfn);
07838 }
07839 #endif
07840 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07841 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07842 res = 0;
07843 }
07844 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07845 }
07846 DISPOSE(vms->curdir, vms->curmsg);
07847 return res;
07848 }
07849
07850 #ifdef IMAP_STORAGE
07851 static int imap_remove_file(char *dir, int msgnum)
07852 {
07853 char fn[PATH_MAX];
07854 char full_fn[PATH_MAX];
07855 char intro[PATH_MAX] = {0,};
07856
07857 if (msgnum > -1) {
07858 make_file(fn, sizeof(fn), dir, msgnum);
07859 snprintf(intro, sizeof(intro), "%sintro", fn);
07860 } else
07861 ast_copy_string(fn, dir, sizeof(fn));
07862
07863 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07864 ast_filedelete(fn, NULL);
07865 if (!ast_strlen_zero(intro)) {
07866 ast_filedelete(intro, NULL);
07867 }
07868 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07869 unlink(full_fn);
07870 }
07871 return 0;
07872 }
07873
07874
07875
07876 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07877 {
07878 char *file, *filename;
07879 char *attachment;
07880 char arg[10];
07881 int i;
07882 BODY* body;
07883
07884 file = strrchr(ast_strdupa(dir), '/');
07885 if (file) {
07886 *file++ = '\0';
07887 } else {
07888 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07889 return -1;
07890 }
07891
07892 ast_mutex_lock(&vms->lock);
07893 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07894 mail_fetchstructure(vms->mailstream, i + 1, &body);
07895
07896 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07897 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07898 } else {
07899 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07900 ast_mutex_unlock(&vms->lock);
07901 return -1;
07902 }
07903 filename = strsep(&attachment, ".");
07904 if (!strcmp(filename, file)) {
07905 sprintf(arg, "%d", i + 1);
07906 mail_setflag(vms->mailstream, arg, "\\DELETED");
07907 }
07908 }
07909 mail_expunge(vms->mailstream);
07910 ast_mutex_unlock(&vms->lock);
07911 return 0;
07912 }
07913
07914 #elif !defined(IMAP_STORAGE)
07915 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07916 {
07917 int count_msg, last_msg;
07918
07919 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07920
07921
07922
07923
07924 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07925
07926
07927 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07928
07929
07930 count_msg = count_messages(vmu, vms->curdir);
07931 if (count_msg < 0) {
07932 return count_msg;
07933 } else {
07934 vms->lastmsg = count_msg - 1;
07935 }
07936
07937 if (vm_allocate_dh(vms, vmu, count_msg)) {
07938 return -1;
07939 }
07940
07941
07942
07943
07944
07945
07946
07947
07948 if (vm_lock_path(vms->curdir)) {
07949 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07950 return ERROR_LOCK_PATH;
07951 }
07952
07953
07954 last_msg = last_message_index(vmu, vms->curdir);
07955 ast_unlock_path(vms->curdir);
07956
07957 if (last_msg < -1) {
07958 return last_msg;
07959 } else if (vms->lastmsg != last_msg) {
07960 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);
07961 resequence_mailbox(vmu, vms->curdir, count_msg);
07962 }
07963
07964 return 0;
07965 }
07966 #endif
07967
07968 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07969 {
07970 int x = 0;
07971 int last_msg_idx = 0;
07972
07973 #ifndef IMAP_STORAGE
07974 int res = 0, nummsg;
07975 char fn2[PATH_MAX];
07976 #endif
07977
07978 if (vms->lastmsg <= -1) {
07979 goto done;
07980 }
07981
07982 vms->curmsg = -1;
07983 #ifndef IMAP_STORAGE
07984
07985 if (vm_lock_path(vms->curdir)) {
07986 return ERROR_LOCK_PATH;
07987 }
07988
07989
07990 last_msg_idx = last_message_index(vmu, vms->curdir);
07991 if (last_msg_idx != vms->lastmsg) {
07992 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07993 }
07994
07995
07996 for (x = 0; x < last_msg_idx + 1; x++) {
07997 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07998
07999 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08000 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08001 break;
08002 }
08003 vms->curmsg++;
08004 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08005 if (strcmp(vms->fn, fn2)) {
08006 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08007 }
08008 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08009
08010 res = save_to_folder(vmu, vms, x, 1);
08011 if (res == ERROR_LOCK_PATH) {
08012
08013 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08014 vms->deleted[x] = 0;
08015 vms->heard[x] = 0;
08016 --x;
08017 }
08018 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08019
08020 res = save_to_folder(vmu, vms, x, 10);
08021 if (res == ERROR_LOCK_PATH) {
08022
08023 vms->deleted[x] = 0;
08024 vms->heard[x] = 0;
08025 --x;
08026 }
08027 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08028
08029
08030 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08031 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08032 DELETE(vms->curdir, x, vms->fn, vmu);
08033 }
08034 }
08035 }
08036
08037
08038 nummsg = x - 1;
08039 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08040 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08041 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08042 DELETE(vms->curdir, x, vms->fn, vmu);
08043 }
08044 }
08045 ast_unlock_path(vms->curdir);
08046 #else
08047 ast_mutex_lock(&vms->lock);
08048 if (vms->deleted) {
08049
08050
08051 last_msg_idx = vms->dh_arraysize;
08052 for (x = last_msg_idx - 1; x >= 0; x--) {
08053 if (vms->deleted[x]) {
08054 ast_debug(3, "IMAP delete of %d\n", x);
08055 DELETE(vms->curdir, x, vms->fn, vmu);
08056 }
08057 }
08058 }
08059 #endif
08060
08061 done:
08062 if (vms->deleted) {
08063 ast_free(vms->deleted);
08064 vms->deleted = NULL;
08065 }
08066 if (vms->heard) {
08067 ast_free(vms->heard);
08068 vms->heard = NULL;
08069 }
08070 vms->dh_arraysize = 0;
08071 #ifdef IMAP_STORAGE
08072 ast_mutex_unlock(&vms->lock);
08073 #endif
08074
08075 return 0;
08076 }
08077
08078
08079
08080
08081
08082
08083
08084 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08085 {
08086 int cmd;
08087 char *buf;
08088
08089 buf = ast_alloca(strlen(box) + 2);
08090 strcpy(buf, box);
08091 strcat(buf, "s");
08092
08093 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08094 cmd = ast_play_and_wait(chan, buf);
08095 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08096 } else {
08097 cmd = ast_play_and_wait(chan, "vm-messages");
08098 return cmd ? cmd : ast_play_and_wait(chan, box);
08099 }
08100 }
08101
08102 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08103 {
08104 int cmd;
08105
08106 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08107 if (!strcasecmp(box, "vm-INBOX"))
08108 cmd = ast_play_and_wait(chan, "vm-new-e");
08109 else
08110 cmd = ast_play_and_wait(chan, "vm-old-e");
08111 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08112 } else {
08113 cmd = ast_play_and_wait(chan, "vm-messages");
08114 return cmd ? cmd : ast_play_and_wait(chan, box);
08115 }
08116 }
08117
08118 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08119 {
08120 int cmd;
08121
08122 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08123 cmd = ast_play_and_wait(chan, "vm-messages");
08124 return cmd ? cmd : ast_play_and_wait(chan, box);
08125 } else {
08126 cmd = ast_play_and_wait(chan, box);
08127 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08128 }
08129 }
08130
08131 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08132 {
08133 int cmd;
08134
08135 if ( !strncasecmp(chan->language, "it", 2) ||
08136 !strncasecmp(chan->language, "es", 2) ||
08137 !strncasecmp(chan->language, "pt", 2)) {
08138 cmd = ast_play_and_wait(chan, "vm-messages");
08139 return cmd ? cmd : ast_play_and_wait(chan, box);
08140 } else if (!strncasecmp(chan->language, "gr", 2)) {
08141 return vm_play_folder_name_gr(chan, box);
08142 } else if (!strncasecmp(chan->language, "he", 2)) {
08143 return ast_play_and_wait(chan, box);
08144 } else if (!strncasecmp(chan->language, "pl", 2)) {
08145 return vm_play_folder_name_pl(chan, box);
08146 } else if (!strncasecmp(chan->language, "ua", 2)) {
08147 return vm_play_folder_name_ua(chan, box);
08148 } else if (!strncasecmp(chan->language, "vi", 2)) {
08149 return ast_play_and_wait(chan, box);
08150 } else {
08151 cmd = ast_play_and_wait(chan, box);
08152 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08153 }
08154 }
08155
08156
08157
08158
08159
08160
08161
08162
08163
08164
08165
08166
08167
08168 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08169 {
08170 int res = 0;
08171
08172 if (vms->newmessages) {
08173 res = ast_play_and_wait(chan, "vm-youhave");
08174 if (!res)
08175 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08176 if (!res) {
08177 if ((vms->newmessages == 1)) {
08178 res = ast_play_and_wait(chan, "vm-INBOX");
08179 if (!res)
08180 res = ast_play_and_wait(chan, "vm-message");
08181 } else {
08182 res = ast_play_and_wait(chan, "vm-INBOXs");
08183 if (!res)
08184 res = ast_play_and_wait(chan, "vm-messages");
08185 }
08186 }
08187 } else if (vms->oldmessages){
08188 res = ast_play_and_wait(chan, "vm-youhave");
08189 if (!res)
08190 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08191 if ((vms->oldmessages == 1)){
08192 res = ast_play_and_wait(chan, "vm-Old");
08193 if (!res)
08194 res = ast_play_and_wait(chan, "vm-message");
08195 } else {
08196 res = ast_play_and_wait(chan, "vm-Olds");
08197 if (!res)
08198 res = ast_play_and_wait(chan, "vm-messages");
08199 }
08200 } else if (!vms->oldmessages && !vms->newmessages)
08201 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08202 return res;
08203 }
08204
08205
08206
08207
08208
08209
08210
08211
08212
08213
08214
08215
08216
08217
08218
08219
08220
08221
08222
08223
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236
08237
08238
08239
08240
08241
08242
08243
08244
08245
08246
08247
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257
08258
08259
08260
08261
08262 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08263 {
08264 int res;
08265 int lastnum = 0;
08266
08267 res = ast_play_and_wait(chan, "vm-youhave");
08268
08269 if (!res && vms->newmessages) {
08270 lastnum = vms->newmessages;
08271
08272 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08273 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08274 }
08275
08276 if (!res && vms->oldmessages) {
08277 res = ast_play_and_wait(chan, "vm-and");
08278 }
08279 }
08280
08281 if (!res && vms->oldmessages) {
08282 lastnum = vms->oldmessages;
08283
08284 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08285 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08286 }
08287 }
08288
08289 if (!res) {
08290 if (lastnum == 0) {
08291 res = ast_play_and_wait(chan, "vm-no");
08292 }
08293 if (!res) {
08294 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08295 }
08296 }
08297
08298 return res;
08299 }
08300
08301
08302 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08303 {
08304 int res = 0;
08305
08306
08307 if (!res) {
08308 if ((vms->newmessages) || (vms->oldmessages)) {
08309 res = ast_play_and_wait(chan, "vm-youhave");
08310 }
08311
08312
08313
08314
08315
08316 if (vms->newmessages) {
08317 if (!res) {
08318 if (vms->newmessages == 1) {
08319 res = ast_play_and_wait(chan, "vm-INBOX1");
08320 } else {
08321 if (vms->newmessages == 2) {
08322 res = ast_play_and_wait(chan, "vm-shtei");
08323 } else {
08324 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08325 }
08326 res = ast_play_and_wait(chan, "vm-INBOX");
08327 }
08328 }
08329 if (vms->oldmessages && !res) {
08330 res = ast_play_and_wait(chan, "vm-and");
08331 if (vms->oldmessages == 1) {
08332 res = ast_play_and_wait(chan, "vm-Old1");
08333 } else {
08334 if (vms->oldmessages == 2) {
08335 res = ast_play_and_wait(chan, "vm-shtei");
08336 } else {
08337 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08338 }
08339 res = ast_play_and_wait(chan, "vm-Old");
08340 }
08341 }
08342 }
08343 if (!res && vms->oldmessages && !vms->newmessages) {
08344 if (!res) {
08345 if (vms->oldmessages == 1) {
08346 res = ast_play_and_wait(chan, "vm-Old1");
08347 } else {
08348 if (vms->oldmessages == 2) {
08349 res = ast_play_and_wait(chan, "vm-shtei");
08350 } else {
08351 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08352 }
08353 res = ast_play_and_wait(chan, "vm-Old");
08354 }
08355 }
08356 }
08357 if (!res) {
08358 if (!vms->oldmessages && !vms->newmessages) {
08359 if (!res) {
08360 res = ast_play_and_wait(chan, "vm-nomessages");
08361 }
08362 }
08363 }
08364 }
08365 return res;
08366 }
08367
08368
08369 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08370 {
08371 int res;
08372
08373
08374 res = ast_play_and_wait(chan, "vm-youhave");
08375 if (!res) {
08376 if (vms->urgentmessages) {
08377 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08378 if (!res)
08379 res = ast_play_and_wait(chan, "vm-Urgent");
08380 if ((vms->oldmessages || vms->newmessages) && !res) {
08381 res = ast_play_and_wait(chan, "vm-and");
08382 } else if (!res) {
08383 if ((vms->urgentmessages == 1))
08384 res = ast_play_and_wait(chan, "vm-message");
08385 else
08386 res = ast_play_and_wait(chan, "vm-messages");
08387 }
08388 }
08389 if (vms->newmessages) {
08390 res = say_and_wait(chan, vms->newmessages, chan->language);
08391 if (!res)
08392 res = ast_play_and_wait(chan, "vm-INBOX");
08393 if (vms->oldmessages && !res)
08394 res = ast_play_and_wait(chan, "vm-and");
08395 else if (!res) {
08396 if ((vms->newmessages == 1))
08397 res = ast_play_and_wait(chan, "vm-message");
08398 else
08399 res = ast_play_and_wait(chan, "vm-messages");
08400 }
08401
08402 }
08403 if (!res && vms->oldmessages) {
08404 res = say_and_wait(chan, vms->oldmessages, chan->language);
08405 if (!res)
08406 res = ast_play_and_wait(chan, "vm-Old");
08407 if (!res) {
08408 if (vms->oldmessages == 1)
08409 res = ast_play_and_wait(chan, "vm-message");
08410 else
08411 res = ast_play_and_wait(chan, "vm-messages");
08412 }
08413 }
08414 if (!res) {
08415 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08416 res = ast_play_and_wait(chan, "vm-no");
08417 if (!res)
08418 res = ast_play_and_wait(chan, "vm-messages");
08419 }
08420 }
08421 }
08422 return res;
08423 }
08424
08425
08426 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08427 {
08428
08429 int res;
08430 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08431 res = ast_play_and_wait(chan, "vm-no") ||
08432 ast_play_and_wait(chan, "vm-message");
08433 else
08434 res = ast_play_and_wait(chan, "vm-youhave");
08435 if (!res && vms->newmessages) {
08436 res = (vms->newmessages == 1) ?
08437 ast_play_and_wait(chan, "digits/un") ||
08438 ast_play_and_wait(chan, "vm-nuovo") ||
08439 ast_play_and_wait(chan, "vm-message") :
08440
08441 say_and_wait(chan, vms->newmessages, chan->language) ||
08442 ast_play_and_wait(chan, "vm-nuovi") ||
08443 ast_play_and_wait(chan, "vm-messages");
08444 if (!res && vms->oldmessages)
08445 res = ast_play_and_wait(chan, "vm-and");
08446 }
08447 if (!res && vms->oldmessages) {
08448 res = (vms->oldmessages == 1) ?
08449 ast_play_and_wait(chan, "digits/un") ||
08450 ast_play_and_wait(chan, "vm-vecchio") ||
08451 ast_play_and_wait(chan, "vm-message") :
08452
08453 say_and_wait(chan, vms->oldmessages, chan->language) ||
08454 ast_play_and_wait(chan, "vm-vecchi") ||
08455 ast_play_and_wait(chan, "vm-messages");
08456 }
08457 return res;
08458 }
08459
08460
08461 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08462 {
08463
08464 int res;
08465 div_t num;
08466
08467 if (!vms->oldmessages && !vms->newmessages) {
08468 res = ast_play_and_wait(chan, "vm-no");
08469 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08470 return res;
08471 } else {
08472 res = ast_play_and_wait(chan, "vm-youhave");
08473 }
08474
08475 if (vms->newmessages) {
08476 num = div(vms->newmessages, 10);
08477 if (vms->newmessages == 1) {
08478 res = ast_play_and_wait(chan, "digits/1-a");
08479 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08480 res = res ? res : ast_play_and_wait(chan, "vm-message");
08481 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08482 if (num.rem == 2) {
08483 if (!num.quot) {
08484 res = ast_play_and_wait(chan, "digits/2-ie");
08485 } else {
08486 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08487 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08488 }
08489 } else {
08490 res = say_and_wait(chan, vms->newmessages, chan->language);
08491 }
08492 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08493 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08494 } else {
08495 res = say_and_wait(chan, vms->newmessages, chan->language);
08496 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08497 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08498 }
08499 if (!res && vms->oldmessages)
08500 res = ast_play_and_wait(chan, "vm-and");
08501 }
08502 if (!res && vms->oldmessages) {
08503 num = div(vms->oldmessages, 10);
08504 if (vms->oldmessages == 1) {
08505 res = ast_play_and_wait(chan, "digits/1-a");
08506 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08507 res = res ? res : ast_play_and_wait(chan, "vm-message");
08508 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08509 if (num.rem == 2) {
08510 if (!num.quot) {
08511 res = ast_play_and_wait(chan, "digits/2-ie");
08512 } else {
08513 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08514 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08515 }
08516 } else {
08517 res = say_and_wait(chan, vms->oldmessages, chan->language);
08518 }
08519 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08520 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08521 } else {
08522 res = say_and_wait(chan, vms->oldmessages, chan->language);
08523 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08524 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08525 }
08526 }
08527
08528 return res;
08529 }
08530
08531
08532 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08533 {
08534
08535 int res;
08536
08537 res = ast_play_and_wait(chan, "vm-youhave");
08538 if (res)
08539 return res;
08540
08541 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08542 res = ast_play_and_wait(chan, "vm-no");
08543 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08544 return res;
08545 }
08546
08547 if (vms->newmessages) {
08548 if ((vms->newmessages == 1)) {
08549 res = ast_play_and_wait(chan, "digits/ett");
08550 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08551 res = res ? res : ast_play_and_wait(chan, "vm-message");
08552 } else {
08553 res = say_and_wait(chan, vms->newmessages, chan->language);
08554 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08555 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08556 }
08557 if (!res && vms->oldmessages)
08558 res = ast_play_and_wait(chan, "vm-and");
08559 }
08560 if (!res && vms->oldmessages) {
08561 if (vms->oldmessages == 1) {
08562 res = ast_play_and_wait(chan, "digits/ett");
08563 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08564 res = res ? res : ast_play_and_wait(chan, "vm-message");
08565 } else {
08566 res = say_and_wait(chan, vms->oldmessages, chan->language);
08567 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08568 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08569 }
08570 }
08571
08572 return res;
08573 }
08574
08575
08576 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08577 {
08578
08579 int res;
08580
08581 res = ast_play_and_wait(chan, "vm-youhave");
08582 if (res)
08583 return res;
08584
08585 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08586 res = ast_play_and_wait(chan, "vm-no");
08587 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08588 return res;
08589 }
08590
08591 if (vms->newmessages) {
08592 if ((vms->newmessages == 1)) {
08593 res = ast_play_and_wait(chan, "digits/1");
08594 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08595 res = res ? res : ast_play_and_wait(chan, "vm-message");
08596 } else {
08597 res = say_and_wait(chan, vms->newmessages, chan->language);
08598 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08599 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08600 }
08601 if (!res && vms->oldmessages)
08602 res = ast_play_and_wait(chan, "vm-and");
08603 }
08604 if (!res && vms->oldmessages) {
08605 if (vms->oldmessages == 1) {
08606 res = ast_play_and_wait(chan, "digits/1");
08607 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08608 res = res ? res : ast_play_and_wait(chan, "vm-message");
08609 } else {
08610 res = say_and_wait(chan, vms->oldmessages, chan->language);
08611 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08612 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08613 }
08614 }
08615
08616 return res;
08617 }
08618
08619
08620 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08621 {
08622
08623 int res;
08624 res = ast_play_and_wait(chan, "vm-youhave");
08625 if (!res) {
08626 if (vms->newmessages) {
08627 if ((vms->newmessages == 1))
08628 res = ast_play_and_wait(chan, "digits/1F");
08629 else
08630 res = say_and_wait(chan, vms->newmessages, chan->language);
08631 if (!res)
08632 res = ast_play_and_wait(chan, "vm-INBOX");
08633 if (vms->oldmessages && !res)
08634 res = ast_play_and_wait(chan, "vm-and");
08635 else if (!res) {
08636 if ((vms->newmessages == 1))
08637 res = ast_play_and_wait(chan, "vm-message");
08638 else
08639 res = ast_play_and_wait(chan, "vm-messages");
08640 }
08641
08642 }
08643 if (!res && vms->oldmessages) {
08644 if (vms->oldmessages == 1)
08645 res = ast_play_and_wait(chan, "digits/1F");
08646 else
08647 res = say_and_wait(chan, vms->oldmessages, chan->language);
08648 if (!res)
08649 res = ast_play_and_wait(chan, "vm-Old");
08650 if (!res) {
08651 if (vms->oldmessages == 1)
08652 res = ast_play_and_wait(chan, "vm-message");
08653 else
08654 res = ast_play_and_wait(chan, "vm-messages");
08655 }
08656 }
08657 if (!res) {
08658 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08659 res = ast_play_and_wait(chan, "vm-no");
08660 if (!res)
08661 res = ast_play_and_wait(chan, "vm-messages");
08662 }
08663 }
08664 }
08665 return res;
08666 }
08667
08668
08669 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08670 {
08671
08672 int res;
08673 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08674 res = ast_play_and_wait(chan, "vm-youhaveno");
08675 if (!res)
08676 res = ast_play_and_wait(chan, "vm-messages");
08677 } else {
08678 res = ast_play_and_wait(chan, "vm-youhave");
08679 }
08680 if (!res) {
08681 if (vms->newmessages) {
08682 if (!res) {
08683 if ((vms->newmessages == 1)) {
08684 res = ast_play_and_wait(chan, "digits/1M");
08685 if (!res)
08686 res = ast_play_and_wait(chan, "vm-message");
08687 if (!res)
08688 res = ast_play_and_wait(chan, "vm-INBOXs");
08689 } else {
08690 res = say_and_wait(chan, vms->newmessages, chan->language);
08691 if (!res)
08692 res = ast_play_and_wait(chan, "vm-messages");
08693 if (!res)
08694 res = ast_play_and_wait(chan, "vm-INBOX");
08695 }
08696 }
08697 if (vms->oldmessages && !res)
08698 res = ast_play_and_wait(chan, "vm-and");
08699 }
08700 if (vms->oldmessages) {
08701 if (!res) {
08702 if (vms->oldmessages == 1) {
08703 res = ast_play_and_wait(chan, "digits/1M");
08704 if (!res)
08705 res = ast_play_and_wait(chan, "vm-message");
08706 if (!res)
08707 res = ast_play_and_wait(chan, "vm-Olds");
08708 } else {
08709 res = say_and_wait(chan, vms->oldmessages, chan->language);
08710 if (!res)
08711 res = ast_play_and_wait(chan, "vm-messages");
08712 if (!res)
08713 res = ast_play_and_wait(chan, "vm-Old");
08714 }
08715 }
08716 }
08717 }
08718 return res;
08719 }
08720
08721
08722 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08723
08724 int res;
08725 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08726 res = ast_play_and_wait(chan, "vm-nomessages");
08727 return res;
08728 } else {
08729 res = ast_play_and_wait(chan, "vm-youhave");
08730 }
08731 if (vms->newmessages) {
08732 if (!res)
08733 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08734 if ((vms->newmessages == 1)) {
08735 if (!res)
08736 res = ast_play_and_wait(chan, "vm-message");
08737 if (!res)
08738 res = ast_play_and_wait(chan, "vm-INBOXs");
08739 } else {
08740 if (!res)
08741 res = ast_play_and_wait(chan, "vm-messages");
08742 if (!res)
08743 res = ast_play_and_wait(chan, "vm-INBOX");
08744 }
08745 if (vms->oldmessages && !res)
08746 res = ast_play_and_wait(chan, "vm-and");
08747 }
08748 if (vms->oldmessages) {
08749 if (!res)
08750 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08751 if (vms->oldmessages == 1) {
08752 if (!res)
08753 res = ast_play_and_wait(chan, "vm-message");
08754 if (!res)
08755 res = ast_play_and_wait(chan, "vm-Olds");
08756 } else {
08757 if (!res)
08758 res = ast_play_and_wait(chan, "vm-messages");
08759 if (!res)
08760 res = ast_play_and_wait(chan, "vm-Old");
08761 }
08762 }
08763 return res;
08764 }
08765
08766
08767 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08768 {
08769
08770 int res;
08771 res = ast_play_and_wait(chan, "vm-youhave");
08772 if (!res) {
08773 if (vms->newmessages) {
08774 res = say_and_wait(chan, vms->newmessages, chan->language);
08775 if (!res)
08776 res = ast_play_and_wait(chan, "vm-INBOX");
08777 if (vms->oldmessages && !res)
08778 res = ast_play_and_wait(chan, "vm-and");
08779 else if (!res) {
08780 if ((vms->newmessages == 1))
08781 res = ast_play_and_wait(chan, "vm-message");
08782 else
08783 res = ast_play_and_wait(chan, "vm-messages");
08784 }
08785
08786 }
08787 if (!res && vms->oldmessages) {
08788 res = say_and_wait(chan, vms->oldmessages, chan->language);
08789 if (!res)
08790 res = ast_play_and_wait(chan, "vm-Old");
08791 if (!res) {
08792 if (vms->oldmessages == 1)
08793 res = ast_play_and_wait(chan, "vm-message");
08794 else
08795 res = ast_play_and_wait(chan, "vm-messages");
08796 }
08797 }
08798 if (!res) {
08799 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08800 res = ast_play_and_wait(chan, "vm-no");
08801 if (!res)
08802 res = ast_play_and_wait(chan, "vm-messages");
08803 }
08804 }
08805 }
08806 return res;
08807 }
08808
08809
08810 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08811 {
08812
08813 int res;
08814 res = ast_play_and_wait(chan, "vm-youhave");
08815 if (!res) {
08816 if (vms->newmessages) {
08817 res = say_and_wait(chan, vms->newmessages, chan->language);
08818 if (!res) {
08819 if (vms->newmessages == 1)
08820 res = ast_play_and_wait(chan, "vm-INBOXs");
08821 else
08822 res = ast_play_and_wait(chan, "vm-INBOX");
08823 }
08824 if (vms->oldmessages && !res)
08825 res = ast_play_and_wait(chan, "vm-and");
08826 else if (!res) {
08827 if ((vms->newmessages == 1))
08828 res = ast_play_and_wait(chan, "vm-message");
08829 else
08830 res = ast_play_and_wait(chan, "vm-messages");
08831 }
08832
08833 }
08834 if (!res && vms->oldmessages) {
08835 res = say_and_wait(chan, vms->oldmessages, chan->language);
08836 if (!res) {
08837 if (vms->oldmessages == 1)
08838 res = ast_play_and_wait(chan, "vm-Olds");
08839 else
08840 res = ast_play_and_wait(chan, "vm-Old");
08841 }
08842 if (!res) {
08843 if (vms->oldmessages == 1)
08844 res = ast_play_and_wait(chan, "vm-message");
08845 else
08846 res = ast_play_and_wait(chan, "vm-messages");
08847 }
08848 }
08849 if (!res) {
08850 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08851 res = ast_play_and_wait(chan, "vm-no");
08852 if (!res)
08853 res = ast_play_and_wait(chan, "vm-messages");
08854 }
08855 }
08856 }
08857 return res;
08858 }
08859
08860
08861 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08862 {
08863
08864 int res;
08865 res = ast_play_and_wait(chan, "vm-youhave");
08866 if (!res) {
08867 if (vms->newmessages) {
08868 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08869 if (!res) {
08870 if ((vms->newmessages == 1)) {
08871 res = ast_play_and_wait(chan, "vm-message");
08872 if (!res)
08873 res = ast_play_and_wait(chan, "vm-INBOXs");
08874 } else {
08875 res = ast_play_and_wait(chan, "vm-messages");
08876 if (!res)
08877 res = ast_play_and_wait(chan, "vm-INBOX");
08878 }
08879 }
08880 if (vms->oldmessages && !res)
08881 res = ast_play_and_wait(chan, "vm-and");
08882 }
08883 if (!res && vms->oldmessages) {
08884 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08885 if (!res) {
08886 if (vms->oldmessages == 1) {
08887 res = ast_play_and_wait(chan, "vm-message");
08888 if (!res)
08889 res = ast_play_and_wait(chan, "vm-Olds");
08890 } else {
08891 res = ast_play_and_wait(chan, "vm-messages");
08892 if (!res)
08893 res = ast_play_and_wait(chan, "vm-Old");
08894 }
08895 }
08896 }
08897 if (!res) {
08898 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08899 res = ast_play_and_wait(chan, "vm-no");
08900 if (!res)
08901 res = ast_play_and_wait(chan, "vm-messages");
08902 }
08903 }
08904 }
08905 return res;
08906 }
08907
08908
08909
08910
08911
08912
08913
08914
08915
08916
08917
08918
08919
08920
08921
08922
08923
08924 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08925 {
08926 int res;
08927 res = ast_play_and_wait(chan, "vm-youhave");
08928 if (!res) {
08929 if (vms->newmessages) {
08930 if (vms->newmessages == 1) {
08931 res = ast_play_and_wait(chan, "digits/jednu");
08932 } else {
08933 res = say_and_wait(chan, vms->newmessages, chan->language);
08934 }
08935 if (!res) {
08936 if ((vms->newmessages == 1))
08937 res = ast_play_and_wait(chan, "vm-novou");
08938 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08939 res = ast_play_and_wait(chan, "vm-nove");
08940 if (vms->newmessages > 4)
08941 res = ast_play_and_wait(chan, "vm-novych");
08942 }
08943 if (vms->oldmessages && !res)
08944 res = ast_play_and_wait(chan, "vm-and");
08945 else if (!res) {
08946 if ((vms->newmessages == 1))
08947 res = ast_play_and_wait(chan, "vm-zpravu");
08948 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08949 res = ast_play_and_wait(chan, "vm-zpravy");
08950 if (vms->newmessages > 4)
08951 res = ast_play_and_wait(chan, "vm-zprav");
08952 }
08953 }
08954 if (!res && vms->oldmessages) {
08955 res = say_and_wait(chan, vms->oldmessages, chan->language);
08956 if (!res) {
08957 if ((vms->oldmessages == 1))
08958 res = ast_play_and_wait(chan, "vm-starou");
08959 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08960 res = ast_play_and_wait(chan, "vm-stare");
08961 if (vms->oldmessages > 4)
08962 res = ast_play_and_wait(chan, "vm-starych");
08963 }
08964 if (!res) {
08965 if ((vms->oldmessages == 1))
08966 res = ast_play_and_wait(chan, "vm-zpravu");
08967 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08968 res = ast_play_and_wait(chan, "vm-zpravy");
08969 if (vms->oldmessages > 4)
08970 res = ast_play_and_wait(chan, "vm-zprav");
08971 }
08972 }
08973 if (!res) {
08974 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08975 res = ast_play_and_wait(chan, "vm-no");
08976 if (!res)
08977 res = ast_play_and_wait(chan, "vm-zpravy");
08978 }
08979 }
08980 }
08981 return res;
08982 }
08983
08984
08985 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08986 {
08987 int res;
08988
08989 res = ast_play_and_wait(chan, "vm-you");
08990
08991 if (!res && vms->newmessages) {
08992 res = ast_play_and_wait(chan, "vm-have");
08993 if (!res)
08994 res = say_and_wait(chan, vms->newmessages, chan->language);
08995 if (!res)
08996 res = ast_play_and_wait(chan, "vm-tong");
08997 if (!res)
08998 res = ast_play_and_wait(chan, "vm-INBOX");
08999 if (vms->oldmessages && !res)
09000 res = ast_play_and_wait(chan, "vm-and");
09001 else if (!res)
09002 res = ast_play_and_wait(chan, "vm-messages");
09003 }
09004 if (!res && vms->oldmessages) {
09005 res = ast_play_and_wait(chan, "vm-have");
09006 if (!res)
09007 res = say_and_wait(chan, vms->oldmessages, chan->language);
09008 if (!res)
09009 res = ast_play_and_wait(chan, "vm-tong");
09010 if (!res)
09011 res = ast_play_and_wait(chan, "vm-Old");
09012 if (!res)
09013 res = ast_play_and_wait(chan, "vm-messages");
09014 }
09015 if (!res && !vms->oldmessages && !vms->newmessages) {
09016 res = ast_play_and_wait(chan, "vm-haveno");
09017 if (!res)
09018 res = ast_play_and_wait(chan, "vm-messages");
09019 }
09020 return res;
09021 }
09022
09023
09024 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09025 {
09026 int res;
09027
09028
09029 res = ast_play_and_wait(chan, "vm-youhave");
09030 if (!res) {
09031 if (vms->newmessages) {
09032 res = say_and_wait(chan, vms->newmessages, chan->language);
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 }
09038 if (!res && vms->oldmessages) {
09039 res = say_and_wait(chan, vms->oldmessages, chan->language);
09040 if (!res)
09041 res = ast_play_and_wait(chan, "vm-Old");
09042 }
09043 if (!res) {
09044 if (!vms->oldmessages && !vms->newmessages) {
09045 res = ast_play_and_wait(chan, "vm-no");
09046 if (!res)
09047 res = ast_play_and_wait(chan, "vm-message");
09048 }
09049 }
09050 }
09051 return res;
09052 }
09053
09054 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09055 {
09056 char prefile[256];
09057
09058
09059 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09060 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09061 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09062 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09063 ast_play_and_wait(chan, "vm-tempgreetactive");
09064 }
09065 DISPOSE(prefile, -1);
09066 }
09067
09068
09069 if (0) {
09070 return 0;
09071 } else if (!strncasecmp(chan->language, "cs", 2)) {
09072 return vm_intro_cs(chan, vms);
09073 } else if (!strncasecmp(chan->language, "cz", 2)) {
09074 static int deprecation_warning = 0;
09075 if (deprecation_warning++ % 10 == 0) {
09076 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09077 }
09078 return vm_intro_cs(chan, vms);
09079 } else if (!strncasecmp(chan->language, "de", 2)) {
09080 return vm_intro_de(chan, vms);
09081 } else if (!strncasecmp(chan->language, "es", 2)) {
09082 return vm_intro_es(chan, vms);
09083 } else if (!strncasecmp(chan->language, "fr", 2)) {
09084 return vm_intro_fr(chan, vms);
09085 } else if (!strncasecmp(chan->language, "gr", 2)) {
09086 return vm_intro_gr(chan, vms);
09087 } else if (!strncasecmp(chan->language, "he", 2)) {
09088 return vm_intro_he(chan, vms);
09089 } else if (!strncasecmp(chan->language, "it", 2)) {
09090 return vm_intro_it(chan, vms);
09091 } else if (!strncasecmp(chan->language, "nl", 2)) {
09092 return vm_intro_nl(chan, vms);
09093 } else if (!strncasecmp(chan->language, "no", 2)) {
09094 return vm_intro_no(chan, vms);
09095 } else if (!strncasecmp(chan->language, "pl", 2)) {
09096 return vm_intro_pl(chan, vms);
09097 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09098 return vm_intro_pt_BR(chan, vms);
09099 } else if (!strncasecmp(chan->language, "pt", 2)) {
09100 return vm_intro_pt(chan, vms);
09101 } else if (!strncasecmp(chan->language, "ru", 2)) {
09102 return vm_intro_multilang(chan, vms, "n");
09103 } else if (!strncasecmp(chan->language, "se", 2)) {
09104 return vm_intro_se(chan, vms);
09105 } else if (!strncasecmp(chan->language, "ua", 2)) {
09106 return vm_intro_multilang(chan, vms, "n");
09107 } else if (!strncasecmp(chan->language, "vi", 2)) {
09108 return vm_intro_vi(chan, vms);
09109 } else if (!strncasecmp(chan->language, "zh", 2)) {
09110 return vm_intro_zh(chan, vms);
09111 } else {
09112 return vm_intro_en(chan, vms);
09113 }
09114 }
09115
09116 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09117 {
09118 int res = 0;
09119
09120 while (!res) {
09121 if (vms->starting) {
09122 if (vms->lastmsg > -1) {
09123 if (skipadvanced)
09124 res = ast_play_and_wait(chan, "vm-onefor-full");
09125 else
09126 res = ast_play_and_wait(chan, "vm-onefor");
09127 if (!res)
09128 res = vm_play_folder_name(chan, vms->vmbox);
09129 }
09130 if (!res) {
09131 if (skipadvanced)
09132 res = ast_play_and_wait(chan, "vm-opts-full");
09133 else
09134 res = ast_play_and_wait(chan, "vm-opts");
09135 }
09136 } else {
09137
09138 if (skipadvanced) {
09139 res = ast_play_and_wait(chan, "vm-onefor-full");
09140 if (!res)
09141 res = vm_play_folder_name(chan, vms->vmbox);
09142 res = ast_play_and_wait(chan, "vm-opts-full");
09143 }
09144
09145
09146
09147
09148
09149
09150 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09151 res = ast_play_and_wait(chan, "vm-prev");
09152 }
09153 if (!res && !skipadvanced)
09154 res = ast_play_and_wait(chan, "vm-advopts");
09155 if (!res)
09156 res = ast_play_and_wait(chan, "vm-repeat");
09157
09158
09159
09160
09161
09162
09163 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09164 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09165 res = ast_play_and_wait(chan, "vm-next");
09166 }
09167 if (!res) {
09168 int curmsg_deleted;
09169 #ifdef IMAP_STORAGE
09170 ast_mutex_lock(&vms->lock);
09171 #endif
09172 curmsg_deleted = vms->deleted[vms->curmsg];
09173 #ifdef IMAP_STORAGE
09174 ast_mutex_unlock(&vms->lock);
09175 #endif
09176 if (!curmsg_deleted) {
09177 res = ast_play_and_wait(chan, "vm-delete");
09178 } else {
09179 res = ast_play_and_wait(chan, "vm-undelete");
09180 }
09181 if (!res) {
09182 res = ast_play_and_wait(chan, "vm-toforward");
09183 }
09184 if (!res) {
09185 res = ast_play_and_wait(chan, "vm-savemessage");
09186 }
09187 }
09188 }
09189 if (!res) {
09190 res = ast_play_and_wait(chan, "vm-helpexit");
09191 }
09192 if (!res)
09193 res = ast_waitfordigit(chan, 6000);
09194 if (!res) {
09195 vms->repeats++;
09196 if (vms->repeats > 2) {
09197 res = 't';
09198 }
09199 }
09200 }
09201 return res;
09202 }
09203
09204 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09205 {
09206 int res = 0;
09207
09208 while (!res) {
09209 if (vms->lastmsg > -1) {
09210 res = ast_play_and_wait(chan, "vm-listen");
09211 if (!res)
09212 res = vm_play_folder_name(chan, vms->vmbox);
09213 if (!res)
09214 res = ast_play_and_wait(chan, "press");
09215 if (!res)
09216 res = ast_play_and_wait(chan, "digits/1");
09217 }
09218 if (!res)
09219 res = ast_play_and_wait(chan, "vm-opts");
09220 if (!res) {
09221 vms->starting = 0;
09222 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09223 }
09224 }
09225 return res;
09226 }
09227
09228 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09229 {
09230 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09231 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09232 } else {
09233 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09234 }
09235 }
09236
09237
09238 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09239 {
09240 int cmd = 0;
09241 int duration = 0;
09242 int tries = 0;
09243 char newpassword[80] = "";
09244 char newpassword2[80] = "";
09245 char prefile[PATH_MAX] = "";
09246 unsigned char buf[256];
09247 int bytes = 0;
09248
09249 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09250 if (ast_adsi_available(chan)) {
09251 bytes += adsi_logo(buf + bytes);
09252 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09253 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09254 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09255 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09256 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09257 }
09258
09259
09260 if (ast_test_flag(vmu, VM_FORCENAME)) {
09261 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09262 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09263 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09264 if (cmd < 0 || cmd == 't' || cmd == '#')
09265 return cmd;
09266 }
09267 }
09268
09269
09270 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09271 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09272 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09273 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09274 if (cmd < 0 || cmd == 't' || cmd == '#')
09275 return cmd;
09276 }
09277
09278 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09279 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09280 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09281 if (cmd < 0 || cmd == 't' || cmd == '#')
09282 return cmd;
09283 }
09284 }
09285
09286
09287
09288
09289
09290 for (;;) {
09291 newpassword[1] = '\0';
09292 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09293 if (cmd == '#')
09294 newpassword[0] = '\0';
09295 if (cmd < 0 || cmd == 't' || cmd == '#')
09296 return cmd;
09297 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09298 if (cmd < 0 || cmd == 't' || cmd == '#')
09299 return cmd;
09300 cmd = check_password(vmu, newpassword);
09301 if (cmd != 0) {
09302 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09303 cmd = ast_play_and_wait(chan, vm_invalid_password);
09304 } else {
09305 newpassword2[1] = '\0';
09306 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09307 if (cmd == '#')
09308 newpassword2[0] = '\0';
09309 if (cmd < 0 || cmd == 't' || cmd == '#')
09310 return cmd;
09311 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09312 if (cmd < 0 || cmd == 't' || cmd == '#')
09313 return cmd;
09314 if (!strcmp(newpassword, newpassword2))
09315 break;
09316 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09317 cmd = ast_play_and_wait(chan, vm_mismatch);
09318 }
09319 if (++tries == 3)
09320 return -1;
09321 if (cmd != 0) {
09322 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09323 }
09324 }
09325 if (pwdchange & PWDCHANGE_INTERNAL)
09326 vm_change_password(vmu, newpassword);
09327 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09328 vm_change_password_shell(vmu, newpassword);
09329
09330 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09331 cmd = ast_play_and_wait(chan, vm_passchanged);
09332
09333 return cmd;
09334 }
09335
09336 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09337 {
09338 int cmd = 0;
09339 int retries = 0;
09340 int duration = 0;
09341 char newpassword[80] = "";
09342 char newpassword2[80] = "";
09343 char prefile[PATH_MAX] = "";
09344 unsigned char buf[256];
09345 int bytes = 0;
09346
09347 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09348 if (ast_adsi_available(chan)) {
09349 bytes += adsi_logo(buf + bytes);
09350 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09351 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09352 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09353 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09354 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09355 }
09356 while ((cmd >= 0) && (cmd != 't')) {
09357 if (cmd)
09358 retries = 0;
09359 switch (cmd) {
09360 case '1':
09361 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09362 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09363 break;
09364 case '2':
09365 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09366 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09367 break;
09368 case '3':
09369 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09370 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09371 break;
09372 case '4':
09373 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09374 break;
09375 case '5':
09376 if (vmu->password[0] == '-') {
09377 cmd = ast_play_and_wait(chan, "vm-no");
09378 break;
09379 }
09380 newpassword[1] = '\0';
09381 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09382 if (cmd == '#')
09383 newpassword[0] = '\0';
09384 else {
09385 if (cmd < 0)
09386 break;
09387 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09388 break;
09389 }
09390 }
09391 cmd = check_password(vmu, newpassword);
09392 if (cmd != 0) {
09393 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09394 cmd = ast_play_and_wait(chan, vm_invalid_password);
09395 if (!cmd) {
09396 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09397 }
09398 break;
09399 }
09400 newpassword2[1] = '\0';
09401 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09402 if (cmd == '#')
09403 newpassword2[0] = '\0';
09404 else {
09405 if (cmd < 0)
09406 break;
09407
09408 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09409 break;
09410 }
09411 }
09412 if (strcmp(newpassword, newpassword2)) {
09413 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09414 cmd = ast_play_and_wait(chan, vm_mismatch);
09415 if (!cmd) {
09416 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09417 }
09418 break;
09419 }
09420
09421 if (pwdchange & PWDCHANGE_INTERNAL) {
09422 vm_change_password(vmu, newpassword);
09423 }
09424 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09425 vm_change_password_shell(vmu, newpassword);
09426 }
09427
09428 ast_debug(1, "User %s set password to %s of length %d\n",
09429 vms->username, newpassword, (int) strlen(newpassword));
09430 cmd = ast_play_and_wait(chan, vm_passchanged);
09431 break;
09432 case '*':
09433 cmd = 't';
09434 break;
09435 default:
09436 cmd = 0;
09437 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09438 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09439 if (ast_fileexists(prefile, NULL, NULL)) {
09440 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09441 }
09442 DISPOSE(prefile, -1);
09443 if (!cmd) {
09444 cmd = ast_play_and_wait(chan, "vm-options");
09445 }
09446 if (!cmd) {
09447 cmd = ast_waitfordigit(chan, 6000);
09448 }
09449 if (!cmd) {
09450 retries++;
09451 }
09452 if (retries > 3) {
09453 cmd = 't';
09454 }
09455 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09456 }
09457 }
09458 if (cmd == 't')
09459 cmd = 0;
09460 return cmd;
09461 }
09462
09463
09464
09465
09466
09467
09468
09469
09470
09471
09472
09473
09474
09475
09476
09477
09478
09479 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09480 {
09481 int cmd = 0;
09482 int retries = 0;
09483 int duration = 0;
09484 char prefile[PATH_MAX] = "";
09485 unsigned char buf[256];
09486 int bytes = 0;
09487
09488 if (ast_adsi_available(chan)) {
09489 bytes += adsi_logo(buf + bytes);
09490 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09491 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09492 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09493 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09494 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09495 }
09496
09497 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09498 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09499 while ((cmd >= 0) && (cmd != 't')) {
09500 if (cmd)
09501 retries = 0;
09502 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09503 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09504 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09505 if (cmd == -1) {
09506 break;
09507 }
09508 cmd = 't';
09509 } else {
09510 switch (cmd) {
09511 case '1':
09512 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09513 break;
09514 case '2':
09515 DELETE(prefile, -1, prefile, vmu);
09516 ast_play_and_wait(chan, "vm-tempremoved");
09517 cmd = 't';
09518 break;
09519 case '*':
09520 cmd = 't';
09521 break;
09522 default:
09523 cmd = ast_play_and_wait(chan,
09524 ast_fileexists(prefile, NULL, NULL) > 0 ?
09525 "vm-tempgreeting2" : "vm-tempgreeting");
09526 if (!cmd) {
09527 cmd = ast_waitfordigit(chan, 6000);
09528 }
09529 if (!cmd) {
09530 retries++;
09531 }
09532 if (retries > 3) {
09533 cmd = 't';
09534 }
09535 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09536 }
09537 }
09538 DISPOSE(prefile, -1);
09539 }
09540 if (cmd == 't')
09541 cmd = 0;
09542 return cmd;
09543 }
09544
09545
09546
09547
09548
09549
09550
09551
09552
09553 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09554 {
09555 int cmd = 0;
09556
09557 if (vms->lastmsg > -1) {
09558 cmd = play_message(chan, vmu, vms);
09559 } else {
09560 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09561 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09562 if (!cmd) {
09563 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09564 cmd = ast_play_and_wait(chan, vms->fn);
09565 }
09566 if (!cmd)
09567 cmd = ast_play_and_wait(chan, "vm-messages");
09568 } else {
09569 if (!cmd)
09570 cmd = ast_play_and_wait(chan, "vm-messages");
09571 if (!cmd) {
09572 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09573 cmd = ast_play_and_wait(chan, vms->fn);
09574 }
09575 }
09576 }
09577 return cmd;
09578 }
09579
09580
09581 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09582 {
09583 int cmd = 0;
09584
09585 if (vms->lastmsg > -1) {
09586 cmd = play_message(chan, vmu, vms);
09587 } else {
09588 if (!strcasecmp(vms->fn, "INBOX")) {
09589 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09590 } else {
09591 cmd = ast_play_and_wait(chan, "vm-nomessages");
09592 }
09593 }
09594 return cmd;
09595 }
09596
09597
09598
09599
09600
09601
09602
09603
09604
09605 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09606 {
09607 int cmd = 0;
09608
09609 if (vms->lastmsg > -1) {
09610 cmd = play_message(chan, vmu, vms);
09611 } else {
09612 cmd = ast_play_and_wait(chan, "vm-youhave");
09613 if (!cmd)
09614 cmd = ast_play_and_wait(chan, "vm-no");
09615 if (!cmd) {
09616 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09617 cmd = ast_play_and_wait(chan, vms->fn);
09618 }
09619 if (!cmd)
09620 cmd = ast_play_and_wait(chan, "vm-messages");
09621 }
09622 return cmd;
09623 }
09624
09625
09626
09627
09628
09629
09630
09631
09632
09633 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09634 {
09635 int cmd;
09636
09637 if (vms->lastmsg > -1) {
09638 cmd = play_message(chan, vmu, vms);
09639 } else {
09640 cmd = ast_play_and_wait(chan, "vm-no");
09641 if (!cmd)
09642 cmd = ast_play_and_wait(chan, "vm-message");
09643 if (!cmd) {
09644 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09645 cmd = ast_play_and_wait(chan, vms->fn);
09646 }
09647 }
09648 return cmd;
09649 }
09650
09651
09652
09653
09654
09655
09656
09657
09658
09659 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09660 {
09661 int cmd;
09662
09663 if (vms->lastmsg > -1) {
09664 cmd = play_message(chan, vmu, vms);
09665 } else {
09666 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09667 if (!cmd)
09668 cmd = ast_play_and_wait(chan, "vm-messages");
09669 if (!cmd) {
09670 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09671 cmd = ast_play_and_wait(chan, vms->fn);
09672 }
09673 }
09674 return cmd;
09675 }
09676
09677
09678
09679
09680
09681
09682
09683
09684
09685 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09686 {
09687 int cmd;
09688
09689 if (vms->lastmsg > -1) {
09690 cmd = play_message(chan, vmu, vms);
09691 } else {
09692 cmd = ast_play_and_wait(chan, "vm-no");
09693 if (!cmd) {
09694 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09695 cmd = ast_play_and_wait(chan, vms->fn);
09696 }
09697 if (!cmd)
09698 cmd = ast_play_and_wait(chan, "vm-messages");
09699 }
09700 return cmd;
09701 }
09702
09703
09704
09705
09706
09707
09708
09709
09710
09711 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09712 {
09713 int cmd;
09714
09715 if (vms->lastmsg > -1) {
09716 cmd = play_message(chan, vmu, vms);
09717 } else {
09718 cmd = ast_play_and_wait(chan, "vm-you");
09719 if (!cmd)
09720 cmd = ast_play_and_wait(chan, "vm-haveno");
09721 if (!cmd)
09722 cmd = ast_play_and_wait(chan, "vm-messages");
09723 if (!cmd) {
09724 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09725 cmd = ast_play_and_wait(chan, vms->fn);
09726 }
09727 }
09728 return cmd;
09729 }
09730
09731
09732
09733
09734
09735
09736
09737
09738
09739 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09740 {
09741 int cmd = 0;
09742
09743 if (vms->lastmsg > -1) {
09744 cmd = play_message(chan, vmu, vms);
09745 } else {
09746 cmd = ast_play_and_wait(chan, "vm-no");
09747 if (!cmd) {
09748 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09749 cmd = ast_play_and_wait(chan, vms->fn);
09750 }
09751 }
09752 return cmd;
09753 }
09754
09755
09756
09757
09758
09759
09760
09761
09762
09763
09764
09765
09766 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09767 {
09768 if (!strncasecmp(chan->language, "es", 2)) {
09769 return vm_browse_messages_es(chan, vms, vmu);
09770 } else if (!strncasecmp(chan->language, "gr", 2)) {
09771 return vm_browse_messages_gr(chan, vms, vmu);
09772 } else if (!strncasecmp(chan->language, "he", 2)) {
09773 return vm_browse_messages_he(chan, vms, vmu);
09774 } else if (!strncasecmp(chan->language, "it", 2)) {
09775 return vm_browse_messages_it(chan, vms, vmu);
09776 } else if (!strncasecmp(chan->language, "pt", 2)) {
09777 return vm_browse_messages_pt(chan, vms, vmu);
09778 } else if (!strncasecmp(chan->language, "vi", 2)) {
09779 return vm_browse_messages_vi(chan, vms, vmu);
09780 } else if (!strncasecmp(chan->language, "zh", 2)) {
09781 return vm_browse_messages_zh(chan, vms, vmu);
09782 } else {
09783 return vm_browse_messages_en(chan, vms, vmu);
09784 }
09785 }
09786
09787 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09788 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09789 int skipuser, int max_logins, int silent)
09790 {
09791 int useadsi = 0, valid = 0, logretries = 0;
09792 char password[AST_MAX_EXTENSION]="", *passptr;
09793 struct ast_vm_user vmus, *vmu = NULL;
09794
09795
09796 adsi_begin(chan, &useadsi);
09797 if (!skipuser && useadsi)
09798 adsi_login(chan);
09799 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09800 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09801 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09802 return -1;
09803 }
09804
09805
09806
09807 while (!valid && (logretries < max_logins)) {
09808
09809 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09810 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09811 return -1;
09812 }
09813 if (ast_strlen_zero(mailbox)) {
09814 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09815 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09816 } else {
09817 ast_verb(3, "Username not entered\n");
09818 return -1;
09819 }
09820 } else if (mailbox[0] == '*') {
09821
09822 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09823 if (ast_exists_extension(chan, chan->context, "a", 1,
09824 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09825 return -1;
09826 }
09827 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09828 mailbox[0] = '\0';
09829 }
09830
09831 if (useadsi)
09832 adsi_password(chan);
09833
09834 if (!ast_strlen_zero(prefix)) {
09835 char fullusername[80] = "";
09836 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09837 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09838 ast_copy_string(mailbox, fullusername, mailbox_size);
09839 }
09840
09841 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09842 vmu = find_user(&vmus, context, mailbox);
09843 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09844
09845 password[0] = '\0';
09846 } else {
09847 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09848 if (ast_streamfile(chan, vm_password, chan->language)) {
09849 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09850 return -1;
09851 }
09852 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09853 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09854 return -1;
09855 } else if (password[0] == '*') {
09856
09857 ast_verb(4, "Password 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 mailbox[0] = '*';
09861 return -1;
09862 }
09863 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09864 mailbox[0] = '\0';
09865
09866 vmu = NULL;
09867 }
09868 }
09869
09870 if (vmu) {
09871 passptr = vmu->password;
09872 if (passptr[0] == '-') passptr++;
09873 }
09874 if (vmu && !strcmp(passptr, password))
09875 valid++;
09876 else {
09877 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09878 if (!ast_strlen_zero(prefix))
09879 mailbox[0] = '\0';
09880 }
09881 logretries++;
09882 if (!valid) {
09883 if (skipuser || logretries >= max_logins) {
09884 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09885 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09886 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09887 return -1;
09888 }
09889 } else {
09890 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09891 if (useadsi)
09892 adsi_login(chan);
09893 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09894 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09895 return -1;
09896 }
09897 }
09898 if (ast_waitstream(chan, ""))
09899 return -1;
09900 }
09901 }
09902 if (!valid && (logretries >= max_logins)) {
09903 ast_stopstream(chan);
09904 ast_play_and_wait(chan, "vm-goodbye");
09905 return -1;
09906 }
09907 if (vmu && !skipuser) {
09908 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09909 }
09910 return 0;
09911 }
09912
09913 static int vm_execmain(struct ast_channel *chan, const char *data)
09914 {
09915
09916
09917
09918 int res = -1;
09919 int cmd = 0;
09920 int valid = 0;
09921 char prefixstr[80] ="";
09922 char ext_context[256]="";
09923 int box;
09924 int useadsi = 0;
09925 int skipuser = 0;
09926 struct vm_state vms;
09927 struct ast_vm_user *vmu = NULL, vmus;
09928 char *context = NULL;
09929 int silentexit = 0;
09930 struct ast_flags flags = { 0 };
09931 signed char record_gain = 0;
09932 int play_auto = 0;
09933 int play_folder = 0;
09934 int in_urgent = 0;
09935 #ifdef IMAP_STORAGE
09936 int deleted = 0;
09937 #endif
09938
09939
09940 memset(&vms, 0, sizeof(vms));
09941
09942 vms.lastmsg = -1;
09943
09944 memset(&vmus, 0, sizeof(vmus));
09945
09946 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09947 if (chan->_state != AST_STATE_UP) {
09948 ast_debug(1, "Before ast_answer\n");
09949 ast_answer(chan);
09950 }
09951
09952 if (!ast_strlen_zero(data)) {
09953 char *opts[OPT_ARG_ARRAY_SIZE];
09954 char *parse;
09955 AST_DECLARE_APP_ARGS(args,
09956 AST_APP_ARG(argv0);
09957 AST_APP_ARG(argv1);
09958 );
09959
09960 parse = ast_strdupa(data);
09961
09962 AST_STANDARD_APP_ARGS(args, parse);
09963
09964 if (args.argc == 2) {
09965 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09966 return -1;
09967 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09968 int gain;
09969 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09970 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09971 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09972 return -1;
09973 } else {
09974 record_gain = (signed char) gain;
09975 }
09976 } else {
09977 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09978 }
09979 }
09980 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09981 play_auto = 1;
09982 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09983
09984 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09985 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09986 play_folder = -1;
09987 }
09988 } else {
09989 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09990 }
09991 } else {
09992 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09993 }
09994 if (play_folder > 9 || play_folder < 0) {
09995 ast_log(AST_LOG_WARNING,
09996 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09997 opts[OPT_ARG_PLAYFOLDER]);
09998 play_folder = 0;
09999 }
10000 }
10001 } else {
10002
10003 while (*(args.argv0)) {
10004 if (*(args.argv0) == 's')
10005 ast_set_flag(&flags, OPT_SILENT);
10006 else if (*(args.argv0) == 'p')
10007 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10008 else
10009 break;
10010 (args.argv0)++;
10011 }
10012
10013 }
10014
10015 valid = ast_test_flag(&flags, OPT_SILENT);
10016
10017 if ((context = strchr(args.argv0, '@')))
10018 *context++ = '\0';
10019
10020 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10021 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10022 else
10023 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10024
10025 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10026 skipuser++;
10027 else
10028 valid = 0;
10029 }
10030
10031 if (!valid)
10032 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10033
10034 ast_debug(1, "After vm_authenticate\n");
10035
10036 if (vms.username[0] == '*') {
10037 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10038
10039
10040 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10041 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10042 res = 0;
10043 goto out;
10044 }
10045 }
10046
10047 if (!res) {
10048 valid = 1;
10049 if (!skipuser)
10050 vmu = &vmus;
10051 } else {
10052 res = 0;
10053 }
10054
10055
10056 adsi_begin(chan, &useadsi);
10057
10058 ast_test_suite_assert(valid);
10059 if (!valid) {
10060 goto out;
10061 }
10062 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10063
10064 #ifdef IMAP_STORAGE
10065 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10066 pthread_setspecific(ts_vmstate.key, &vms);
10067
10068 vms.interactive = 1;
10069 vms.updated = 1;
10070 if (vmu)
10071 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10072 vmstate_insert(&vms);
10073 init_vm_state(&vms);
10074 #endif
10075
10076
10077 if (!ast_strlen_zero(vmu->language))
10078 ast_string_field_set(chan, language, vmu->language);
10079
10080
10081 ast_debug(1, "Before open_mailbox\n");
10082 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10083 if (res < 0)
10084 goto out;
10085 vms.oldmessages = vms.lastmsg + 1;
10086 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10087
10088 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10089 if (res < 0)
10090 goto out;
10091 vms.newmessages = vms.lastmsg + 1;
10092 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10093
10094 in_urgent = 1;
10095 res = open_mailbox(&vms, vmu, 11);
10096 if (res < 0)
10097 goto out;
10098 vms.urgentmessages = vms.lastmsg + 1;
10099 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10100
10101
10102 if (play_auto) {
10103 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10104 if (vms.urgentmessages) {
10105 in_urgent = 1;
10106 res = open_mailbox(&vms, vmu, 11);
10107 } else {
10108 in_urgent = 0;
10109 res = open_mailbox(&vms, vmu, play_folder);
10110 }
10111 if (res < 0)
10112 goto out;
10113
10114
10115 if (vms.lastmsg == -1) {
10116 in_urgent = 0;
10117 cmd = vm_browse_messages(chan, &vms, vmu);
10118 res = 0;
10119 goto out;
10120 }
10121 } else {
10122 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10123
10124 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10125 in_urgent = 0;
10126 play_folder = 1;
10127 if (res < 0)
10128 goto out;
10129 } else if (!vms.urgentmessages && vms.newmessages) {
10130
10131 in_urgent = 0;
10132 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10133 if (res < 0)
10134 goto out;
10135 }
10136 }
10137
10138 if (useadsi)
10139 adsi_status(chan, &vms);
10140 res = 0;
10141
10142
10143 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10144 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10145 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10146 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10147 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10148 if ((cmd == 't') || (cmd == '#')) {
10149
10150 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10151 res = 0;
10152 goto out;
10153 } else if (cmd < 0) {
10154
10155 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10156 res = -1;
10157 goto out;
10158 }
10159 }
10160 #ifdef IMAP_STORAGE
10161 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10162 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10163 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10164 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10165 }
10166 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10167 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10168 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10169 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10170 }
10171 #endif
10172
10173 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10174 if (play_auto) {
10175 cmd = '1';
10176 } else {
10177 cmd = vm_intro(chan, vmu, &vms);
10178 }
10179 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10180
10181 vms.repeats = 0;
10182 vms.starting = 1;
10183 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10184
10185 switch (cmd) {
10186 case '1':
10187 vms.curmsg = 0;
10188
10189 case '5':
10190 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10191 cmd = vm_browse_messages(chan, &vms, vmu);
10192 break;
10193 case '2':
10194 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10195 if (useadsi)
10196 adsi_folders(chan, 0, "Change to folder...");
10197
10198 cmd = get_folder2(chan, "vm-changeto", 0);
10199 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10200 if (cmd == '#') {
10201 cmd = 0;
10202 } else if (cmd > 0) {
10203 cmd = cmd - '0';
10204 res = close_mailbox(&vms, vmu);
10205 if (res == ERROR_LOCK_PATH)
10206 goto out;
10207
10208 if (cmd != 11) in_urgent = 0;
10209 res = open_mailbox(&vms, vmu, cmd);
10210 if (res < 0)
10211 goto out;
10212 play_folder = cmd;
10213 cmd = 0;
10214 }
10215 if (useadsi)
10216 adsi_status2(chan, &vms);
10217
10218 if (!cmd) {
10219 cmd = vm_play_folder_name(chan, vms.vmbox);
10220 }
10221
10222 vms.starting = 1;
10223 vms.curmsg = 0;
10224 break;
10225 case '3':
10226 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10227 cmd = 0;
10228 vms.repeats = 0;
10229 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10230 switch (cmd) {
10231 case '1':
10232 if (vms.lastmsg > -1 && !vms.starting) {
10233 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10234 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10235 res = cmd;
10236 goto out;
10237 }
10238 } else {
10239 cmd = ast_play_and_wait(chan, "vm-sorry");
10240 }
10241 cmd = 't';
10242 break;
10243 case '2':
10244 if (!vms.starting)
10245 ast_verb(3, "Callback Requested\n");
10246 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10247 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10248 if (cmd == 9) {
10249 silentexit = 1;
10250 goto out;
10251 } else if (cmd == ERROR_LOCK_PATH) {
10252 res = cmd;
10253 goto out;
10254 }
10255 } else {
10256 cmd = ast_play_and_wait(chan, "vm-sorry");
10257 }
10258 cmd = 't';
10259 break;
10260 case '3':
10261 if (vms.lastmsg > -1 && !vms.starting) {
10262 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10263 if (cmd == ERROR_LOCK_PATH) {
10264 res = cmd;
10265 goto out;
10266 }
10267 } else {
10268 cmd = ast_play_and_wait(chan, "vm-sorry");
10269 }
10270 cmd = 't';
10271 break;
10272 case '4':
10273 if (!ast_strlen_zero(vmu->dialout)) {
10274 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10275 if (cmd == 9) {
10276 silentexit = 1;
10277 goto out;
10278 }
10279 } else {
10280 cmd = ast_play_and_wait(chan, "vm-sorry");
10281 }
10282 cmd = 't';
10283 break;
10284
10285 case '5':
10286 if (ast_test_flag(vmu, VM_SVMAIL)) {
10287 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10288 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10289 res = cmd;
10290 goto out;
10291 }
10292 } else {
10293 cmd = ast_play_and_wait(chan, "vm-sorry");
10294 }
10295 cmd = 't';
10296 break;
10297
10298 case '*':
10299 cmd = 't';
10300 break;
10301
10302 default:
10303 cmd = 0;
10304 if (!vms.starting) {
10305 cmd = ast_play_and_wait(chan, "vm-toreply");
10306 }
10307 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10308 cmd = ast_play_and_wait(chan, "vm-tocallback");
10309 }
10310 if (!cmd && !vms.starting) {
10311 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10312 }
10313 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10314 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10315 }
10316 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10317 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10318 }
10319 if (!cmd) {
10320 cmd = ast_play_and_wait(chan, "vm-starmain");
10321 }
10322 if (!cmd) {
10323 cmd = ast_waitfordigit(chan, 6000);
10324 }
10325 if (!cmd) {
10326 vms.repeats++;
10327 }
10328 if (vms.repeats > 3) {
10329 cmd = 't';
10330 }
10331 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10332 }
10333 }
10334 if (cmd == 't') {
10335 cmd = 0;
10336 vms.repeats = 0;
10337 }
10338 break;
10339 case '4':
10340 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10341 if (vms.curmsg > 0) {
10342 vms.curmsg--;
10343 cmd = play_message(chan, vmu, &vms);
10344 } else {
10345
10346
10347
10348
10349 if (in_urgent == 0 && vms.urgentmessages > 0) {
10350
10351 in_urgent = 1;
10352 res = close_mailbox(&vms, vmu);
10353 if (res == ERROR_LOCK_PATH)
10354 goto out;
10355 res = open_mailbox(&vms, vmu, 11);
10356 if (res < 0)
10357 goto out;
10358 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10359 vms.curmsg = vms.lastmsg;
10360 if (vms.lastmsg < 0) {
10361 cmd = ast_play_and_wait(chan, "vm-nomore");
10362 }
10363 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10364 vms.curmsg = vms.lastmsg;
10365 cmd = play_message(chan, vmu, &vms);
10366 } else {
10367 cmd = ast_play_and_wait(chan, "vm-nomore");
10368 }
10369 }
10370 break;
10371 case '6':
10372 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10373 if (vms.curmsg < vms.lastmsg) {
10374 vms.curmsg++;
10375 cmd = play_message(chan, vmu, &vms);
10376 } else {
10377 if (in_urgent && vms.newmessages > 0) {
10378
10379
10380
10381
10382 in_urgent = 0;
10383 res = close_mailbox(&vms, vmu);
10384 if (res == ERROR_LOCK_PATH)
10385 goto out;
10386 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10387 if (res < 0)
10388 goto out;
10389 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10390 vms.curmsg = -1;
10391 if (vms.lastmsg < 0) {
10392 cmd = ast_play_and_wait(chan, "vm-nomore");
10393 }
10394 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10395 vms.curmsg = 0;
10396 cmd = play_message(chan, vmu, &vms);
10397 } else {
10398 cmd = ast_play_and_wait(chan, "vm-nomore");
10399 }
10400 }
10401 break;
10402 case '7':
10403 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10404 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10405 if (useadsi)
10406 adsi_delete(chan, &vms);
10407 if (vms.deleted[vms.curmsg]) {
10408 if (play_folder == 0) {
10409 if (in_urgent) {
10410 vms.urgentmessages--;
10411 } else {
10412 vms.newmessages--;
10413 }
10414 }
10415 else if (play_folder == 1)
10416 vms.oldmessages--;
10417 cmd = ast_play_and_wait(chan, "vm-deleted");
10418 } else {
10419 if (play_folder == 0) {
10420 if (in_urgent) {
10421 vms.urgentmessages++;
10422 } else {
10423 vms.newmessages++;
10424 }
10425 }
10426 else if (play_folder == 1)
10427 vms.oldmessages++;
10428 cmd = ast_play_and_wait(chan, "vm-undeleted");
10429 }
10430 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10431 if (vms.curmsg < vms.lastmsg) {
10432 vms.curmsg++;
10433 cmd = play_message(chan, vmu, &vms);
10434 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10435 vms.curmsg = 0;
10436 cmd = play_message(chan, vmu, &vms);
10437 } else {
10438
10439
10440
10441
10442 if (in_urgent == 1) {
10443
10444 in_urgent = 0;
10445 res = close_mailbox(&vms, vmu);
10446 if (res == ERROR_LOCK_PATH)
10447 goto out;
10448 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10449 if (res < 0)
10450 goto out;
10451 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10452 vms.curmsg = -1;
10453 if (vms.lastmsg < 0) {
10454 cmd = ast_play_and_wait(chan, "vm-nomore");
10455 }
10456 } else {
10457 cmd = ast_play_and_wait(chan, "vm-nomore");
10458 }
10459 }
10460 }
10461 } else
10462 cmd = 0;
10463 #ifdef IMAP_STORAGE
10464 deleted = 1;
10465 #endif
10466 break;
10467
10468 case '8':
10469 if (vms.lastmsg > -1) {
10470 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10471 if (cmd == ERROR_LOCK_PATH) {
10472 res = cmd;
10473 goto out;
10474 }
10475 } else {
10476
10477
10478
10479
10480 if (in_urgent == 1 && vms.newmessages > 0) {
10481
10482 in_urgent = 0;
10483 res = close_mailbox(&vms, vmu);
10484 if (res == ERROR_LOCK_PATH)
10485 goto out;
10486 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10487 if (res < 0)
10488 goto out;
10489 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10490 vms.curmsg = -1;
10491 if (vms.lastmsg < 0) {
10492 cmd = ast_play_and_wait(chan, "vm-nomore");
10493 }
10494 } else {
10495 cmd = ast_play_and_wait(chan, "vm-nomore");
10496 }
10497 }
10498 break;
10499 case '9':
10500 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10501 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10502
10503 cmd = 0;
10504 break;
10505 }
10506 if (useadsi)
10507 adsi_folders(chan, 1, "Save to folder...");
10508 cmd = get_folder2(chan, "vm-savefolder", 1);
10509 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10510 box = 0;
10511 if (cmd == '#') {
10512 cmd = 0;
10513 break;
10514 } else if (cmd > 0) {
10515 box = cmd = cmd - '0';
10516 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10517 if (cmd == ERROR_LOCK_PATH) {
10518 res = cmd;
10519 goto out;
10520 #ifndef IMAP_STORAGE
10521 } else if (!cmd) {
10522 vms.deleted[vms.curmsg] = 1;
10523 #endif
10524 } else {
10525 vms.deleted[vms.curmsg] = 0;
10526 vms.heard[vms.curmsg] = 0;
10527 }
10528 }
10529 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10530 if (useadsi)
10531 adsi_message(chan, &vms);
10532 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10533 if (!cmd) {
10534 cmd = ast_play_and_wait(chan, "vm-message");
10535 if (!cmd)
10536 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10537 if (!cmd)
10538 cmd = ast_play_and_wait(chan, "vm-savedto");
10539 if (!cmd)
10540 cmd = vm_play_folder_name(chan, vms.fn);
10541 } else {
10542 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10543 }
10544 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10545 if (vms.curmsg < vms.lastmsg) {
10546 vms.curmsg++;
10547 cmd = play_message(chan, vmu, &vms);
10548 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10549 vms.curmsg = 0;
10550 cmd = play_message(chan, vmu, &vms);
10551 } else {
10552
10553
10554
10555
10556 if (in_urgent == 1 && vms.newmessages > 0) {
10557
10558 in_urgent = 0;
10559 res = close_mailbox(&vms, vmu);
10560 if (res == ERROR_LOCK_PATH)
10561 goto out;
10562 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10563 if (res < 0)
10564 goto out;
10565 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10566 vms.curmsg = -1;
10567 if (vms.lastmsg < 0) {
10568 cmd = ast_play_and_wait(chan, "vm-nomore");
10569 }
10570 } else {
10571 cmd = ast_play_and_wait(chan, "vm-nomore");
10572 }
10573 }
10574 }
10575 break;
10576 case '*':
10577 if (!vms.starting) {
10578 cmd = ast_play_and_wait(chan, "vm-onefor");
10579 if (!strncasecmp(chan->language, "he", 2)) {
10580 cmd = ast_play_and_wait(chan, "vm-for");
10581 }
10582 if (!cmd)
10583 cmd = vm_play_folder_name(chan, vms.vmbox);
10584 if (!cmd)
10585 cmd = ast_play_and_wait(chan, "vm-opts");
10586 if (!cmd)
10587 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10588 } else
10589 cmd = 0;
10590 break;
10591 case '0':
10592 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10593 if (useadsi)
10594 adsi_status(chan, &vms);
10595 break;
10596 default:
10597 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10598 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10599 break;
10600 }
10601 }
10602 if ((cmd == 't') || (cmd == '#')) {
10603
10604 res = 0;
10605 } else {
10606
10607 res = -1;
10608 }
10609
10610 out:
10611 if (res > -1) {
10612 ast_stopstream(chan);
10613 adsi_goodbye(chan);
10614 if (valid && res != OPERATOR_EXIT) {
10615 if (silentexit)
10616 res = ast_play_and_wait(chan, "vm-dialout");
10617 else
10618 res = ast_play_and_wait(chan, "vm-goodbye");
10619 }
10620 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10621 res = 0;
10622 }
10623 if (useadsi)
10624 ast_adsi_unload_session(chan);
10625 }
10626 if (vmu)
10627 close_mailbox(&vms, vmu);
10628 if (valid) {
10629 int new = 0, old = 0, urgent = 0;
10630 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10631 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10632
10633 run_externnotify(vmu->context, vmu->mailbox, NULL);
10634 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10635 queue_mwi_event(ext_context, urgent, new, old);
10636 }
10637 #ifdef IMAP_STORAGE
10638
10639 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10640 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10641 ast_mutex_lock(&vms.lock);
10642 #ifdef HAVE_IMAP_TK2006
10643 if (LEVELUIDPLUS (vms.mailstream)) {
10644 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10645 } else
10646 #endif
10647 mail_expunge(vms.mailstream);
10648 ast_mutex_unlock(&vms.lock);
10649 }
10650
10651
10652 if (vmu) {
10653 vmstate_delete(&vms);
10654 }
10655 #endif
10656 if (vmu)
10657 free_user(vmu);
10658
10659 #ifdef IMAP_STORAGE
10660 pthread_setspecific(ts_vmstate.key, NULL);
10661 #endif
10662 return res;
10663 }
10664
10665 static int vm_exec(struct ast_channel *chan, const char *data)
10666 {
10667 int res = 0;
10668 char *tmp;
10669 struct leave_vm_options leave_options;
10670 struct ast_flags flags = { 0 };
10671 char *opts[OPT_ARG_ARRAY_SIZE];
10672 AST_DECLARE_APP_ARGS(args,
10673 AST_APP_ARG(argv0);
10674 AST_APP_ARG(argv1);
10675 );
10676
10677 memset(&leave_options, 0, sizeof(leave_options));
10678
10679 if (chan->_state != AST_STATE_UP)
10680 ast_answer(chan);
10681
10682 if (!ast_strlen_zero(data)) {
10683 tmp = ast_strdupa(data);
10684 AST_STANDARD_APP_ARGS(args, tmp);
10685 if (args.argc == 2) {
10686 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10687 return -1;
10688 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10689 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10690 int gain;
10691
10692 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10693 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10694 return -1;
10695 } else {
10696 leave_options.record_gain = (signed char) gain;
10697 }
10698 }
10699 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10700 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10701 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10702 }
10703 }
10704 } else {
10705 char temp[256];
10706 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10707 if (res < 0)
10708 return res;
10709 if (ast_strlen_zero(temp))
10710 return 0;
10711 args.argv0 = ast_strdupa(temp);
10712 }
10713
10714 res = leave_voicemail(chan, args.argv0, &leave_options);
10715 if (res == 't') {
10716 ast_play_and_wait(chan, "vm-goodbye");
10717 res = 0;
10718 }
10719
10720 if (res == OPERATOR_EXIT) {
10721 res = 0;
10722 }
10723
10724 if (res == ERROR_LOCK_PATH) {
10725 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10726 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10727 res = 0;
10728 }
10729
10730 return res;
10731 }
10732
10733 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10734 {
10735 struct ast_vm_user *vmu;
10736
10737 if (!ast_strlen_zero(box) && box[0] == '*') {
10738 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10739 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10740 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10741 "\n\tand will be ignored.\n", box, context);
10742 return NULL;
10743 }
10744
10745 AST_LIST_TRAVERSE(&users, vmu, list) {
10746 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10747 if (strcasecmp(vmu->context, context)) {
10748 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10749 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10750 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10751 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10752 }
10753 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10754 return NULL;
10755 }
10756 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10757 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10758 return NULL;
10759 }
10760 }
10761
10762 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10763 return NULL;
10764
10765 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10766 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10767
10768 AST_LIST_INSERT_TAIL(&users, vmu, list);
10769
10770 return vmu;
10771 }
10772
10773 static int append_mailbox(const char *context, const char *box, const char *data)
10774 {
10775
10776 char *tmp;
10777 char *stringp;
10778 char *s;
10779 struct ast_vm_user *vmu;
10780 char *mailbox_full;
10781 int new = 0, old = 0, urgent = 0;
10782 char secretfn[PATH_MAX] = "";
10783
10784 tmp = ast_strdupa(data);
10785
10786 if (!(vmu = find_or_create(context, box)))
10787 return -1;
10788
10789 populate_defaults(vmu);
10790
10791 stringp = tmp;
10792 if ((s = strsep(&stringp, ","))) {
10793 if (!ast_strlen_zero(s) && s[0] == '*') {
10794 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10795 "\n\tmust be reset in voicemail.conf.\n", box);
10796 }
10797
10798 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10799 }
10800 if (stringp && (s = strsep(&stringp, ","))) {
10801 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10802 }
10803 if (stringp && (s = strsep(&stringp, ","))) {
10804 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10805 }
10806 if (stringp && (s = strsep(&stringp, ","))) {
10807 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10808 }
10809 if (stringp && (s = strsep(&stringp, ","))) {
10810 apply_options(vmu, s);
10811 }
10812
10813 switch (vmu->passwordlocation) {
10814 case OPT_PWLOC_SPOOLDIR:
10815 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10816 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10817 }
10818
10819 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10820 strcpy(mailbox_full, box);
10821 strcat(mailbox_full, "@");
10822 strcat(mailbox_full, context);
10823
10824 inboxcount2(mailbox_full, &urgent, &new, &old);
10825 queue_mwi_event(mailbox_full, urgent, new, old);
10826
10827 return 0;
10828 }
10829
10830 AST_TEST_DEFINE(test_voicemail_vmuser)
10831 {
10832 int res = 0;
10833 struct ast_vm_user *vmu;
10834
10835 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10836 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10837 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10838 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10839 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10840 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10841 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10842 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10843 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10844 #ifdef IMAP_STORAGE
10845 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10846 "imapfolder=INBOX|imapvmshareid=6000";
10847 #endif
10848
10849 switch (cmd) {
10850 case TEST_INIT:
10851 info->name = "vmuser";
10852 info->category = "/apps/app_voicemail/";
10853 info->summary = "Vmuser unit test";
10854 info->description =
10855 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10856 return AST_TEST_NOT_RUN;
10857 case TEST_EXECUTE:
10858 break;
10859 }
10860
10861 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10862 return AST_TEST_NOT_RUN;
10863 }
10864 populate_defaults(vmu);
10865 ast_set_flag(vmu, VM_ALLOCED);
10866
10867 apply_options(vmu, options_string);
10868
10869 if (!ast_test_flag(vmu, VM_ATTACH)) {
10870 ast_test_status_update(test, "Parse failure for attach option\n");
10871 res = 1;
10872 }
10873 if (strcasecmp(vmu->attachfmt, "wav49")) {
10874 ast_test_status_update(test, "Parse failure for attachftm option\n");
10875 res = 1;
10876 }
10877 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10878 ast_test_status_update(test, "Parse failure for serveremail option\n");
10879 res = 1;
10880 }
10881 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10882 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10883 res = 1;
10884 }
10885 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10886 ast_test_status_update(test, "Parse failure for emailbody option\n");
10887 res = 1;
10888 }
10889 if (strcasecmp(vmu->zonetag, "central")) {
10890 ast_test_status_update(test, "Parse failure for tz option\n");
10891 res = 1;
10892 }
10893 if (!ast_test_flag(vmu, VM_DELETE)) {
10894 ast_test_status_update(test, "Parse failure for delete option\n");
10895 res = 1;
10896 }
10897 if (!ast_test_flag(vmu, VM_SAYCID)) {
10898 ast_test_status_update(test, "Parse failure for saycid option\n");
10899 res = 1;
10900 }
10901 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10902 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10903 res = 1;
10904 }
10905 if (!ast_test_flag(vmu, VM_REVIEW)) {
10906 ast_test_status_update(test, "Parse failure for review option\n");
10907 res = 1;
10908 }
10909 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10910 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10911 res = 1;
10912 }
10913 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10914 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10915 res = 1;
10916 }
10917 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10918 ast_test_status_update(test, "Parse failure for operator option\n");
10919 res = 1;
10920 }
10921 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10922 ast_test_status_update(test, "Parse failure for envelope option\n");
10923 res = 1;
10924 }
10925 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10926 ast_test_status_update(test, "Parse failure for moveheard option\n");
10927 res = 1;
10928 }
10929 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10930 ast_test_status_update(test, "Parse failure for sayduration option\n");
10931 res = 1;
10932 }
10933 if (vmu->saydurationm != 5) {
10934 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10935 res = 1;
10936 }
10937 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10938 ast_test_status_update(test, "Parse failure for forcename option\n");
10939 res = 1;
10940 }
10941 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10942 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10943 res = 1;
10944 }
10945 if (strcasecmp(vmu->callback, "somecontext")) {
10946 ast_test_status_update(test, "Parse failure for callbacks option\n");
10947 res = 1;
10948 }
10949 if (strcasecmp(vmu->dialout, "somecontext2")) {
10950 ast_test_status_update(test, "Parse failure for dialout option\n");
10951 res = 1;
10952 }
10953 if (strcasecmp(vmu->exit, "somecontext3")) {
10954 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10955 res = 1;
10956 }
10957 if (vmu->minsecs != 10) {
10958 ast_test_status_update(test, "Parse failure for minsecs option\n");
10959 res = 1;
10960 }
10961 if (vmu->maxsecs != 100) {
10962 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10963 res = 1;
10964 }
10965 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10966 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10967 res = 1;
10968 }
10969 if (vmu->maxdeletedmsg != 50) {
10970 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10971 res = 1;
10972 }
10973 if (vmu->volgain != 1.3) {
10974 ast_test_status_update(test, "Parse failure for volgain option\n");
10975 res = 1;
10976 }
10977 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10978 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10979 res = 1;
10980 }
10981 #ifdef IMAP_STORAGE
10982 apply_options(vmu, option_string2);
10983
10984 if (strcasecmp(vmu->imapuser, "imapuser")) {
10985 ast_test_status_update(test, "Parse failure for imapuser option\n");
10986 res = 1;
10987 }
10988 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10989 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10990 res = 1;
10991 }
10992 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10993 ast_test_status_update(test, "Parse failure for imapfolder option\n");
10994 res = 1;
10995 }
10996 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10997 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10998 res = 1;
10999 }
11000 #endif
11001
11002 free_user(vmu);
11003 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11004 }
11005
11006 static int vm_box_exists(struct ast_channel *chan, const char *data)
11007 {
11008 struct ast_vm_user svm;
11009 char *context, *box;
11010 AST_DECLARE_APP_ARGS(args,
11011 AST_APP_ARG(mbox);
11012 AST_APP_ARG(options);
11013 );
11014 static int dep_warning = 0;
11015
11016 if (ast_strlen_zero(data)) {
11017 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11018 return -1;
11019 }
11020
11021 if (!dep_warning) {
11022 dep_warning = 1;
11023 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11024 }
11025
11026 box = ast_strdupa(data);
11027
11028 AST_STANDARD_APP_ARGS(args, box);
11029
11030 if (args.options) {
11031 }
11032
11033 if ((context = strchr(args.mbox, '@'))) {
11034 *context = '\0';
11035 context++;
11036 }
11037
11038 if (find_user(&svm, context, args.mbox)) {
11039 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11040 } else
11041 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11042
11043 return 0;
11044 }
11045
11046 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11047 {
11048 struct ast_vm_user svm;
11049 AST_DECLARE_APP_ARGS(arg,
11050 AST_APP_ARG(mbox);
11051 AST_APP_ARG(context);
11052 );
11053
11054 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11055
11056 if (ast_strlen_zero(arg.mbox)) {
11057 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11058 return -1;
11059 }
11060
11061 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11062 return 0;
11063 }
11064
11065 static struct ast_custom_function mailbox_exists_acf = {
11066 .name = "MAILBOX_EXISTS",
11067 .read = acf_mailbox_exists,
11068 };
11069
11070 static int vmauthenticate(struct ast_channel *chan, const char *data)
11071 {
11072 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11073 struct ast_vm_user vmus;
11074 char *options = NULL;
11075 int silent = 0, skipuser = 0;
11076 int res = -1;
11077
11078 if (data) {
11079 s = ast_strdupa(data);
11080 user = strsep(&s, ",");
11081 options = strsep(&s, ",");
11082 if (user) {
11083 s = user;
11084 user = strsep(&s, "@");
11085 context = strsep(&s, "");
11086 if (!ast_strlen_zero(user))
11087 skipuser++;
11088 ast_copy_string(mailbox, user, sizeof(mailbox));
11089 }
11090 }
11091
11092 if (options) {
11093 silent = (strchr(options, 's')) != NULL;
11094 }
11095
11096 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11097 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11098 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11099 ast_play_and_wait(chan, "auth-thankyou");
11100 res = 0;
11101 } else if (mailbox[0] == '*') {
11102
11103 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11104 res = 0;
11105 }
11106 }
11107
11108 return res;
11109 }
11110
11111 static char *show_users_realtime(int fd, const char *context)
11112 {
11113 struct ast_config *cfg;
11114 const char *cat = NULL;
11115
11116 if (!(cfg = ast_load_realtime_multientry("voicemail",
11117 "context", context, SENTINEL))) {
11118 return CLI_FAILURE;
11119 }
11120
11121 ast_cli(fd,
11122 "\n"
11123 "=============================================================\n"
11124 "=== Configured Voicemail Users ==============================\n"
11125 "=============================================================\n"
11126 "===\n");
11127
11128 while ((cat = ast_category_browse(cfg, cat))) {
11129 struct ast_variable *var = NULL;
11130 ast_cli(fd,
11131 "=== Mailbox ...\n"
11132 "===\n");
11133 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11134 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11135 ast_cli(fd,
11136 "===\n"
11137 "=== ---------------------------------------------------------\n"
11138 "===\n");
11139 }
11140
11141 ast_cli(fd,
11142 "=============================================================\n"
11143 "\n");
11144
11145 ast_config_destroy(cfg);
11146
11147 return CLI_SUCCESS;
11148 }
11149
11150 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11151 {
11152 int which = 0;
11153 int wordlen;
11154 struct ast_vm_user *vmu;
11155 const char *context = "";
11156
11157
11158 if (pos > 4)
11159 return NULL;
11160 if (pos == 3)
11161 return (state == 0) ? ast_strdup("for") : NULL;
11162 wordlen = strlen(word);
11163 AST_LIST_TRAVERSE(&users, vmu, list) {
11164 if (!strncasecmp(word, vmu->context, wordlen)) {
11165 if (context && strcmp(context, vmu->context) && ++which > state)
11166 return ast_strdup(vmu->context);
11167
11168 context = vmu->context;
11169 }
11170 }
11171 return NULL;
11172 }
11173
11174
11175 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11176 {
11177 struct ast_vm_user *vmu;
11178 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11179 const char *context = NULL;
11180 int users_counter = 0;
11181
11182 switch (cmd) {
11183 case CLI_INIT:
11184 e->command = "voicemail show users";
11185 e->usage =
11186 "Usage: voicemail show users [for <context>]\n"
11187 " Lists all mailboxes currently set up\n";
11188 return NULL;
11189 case CLI_GENERATE:
11190 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11191 }
11192
11193 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11194 return CLI_SHOWUSAGE;
11195 if (a->argc == 5) {
11196 if (strcmp(a->argv[3],"for"))
11197 return CLI_SHOWUSAGE;
11198 context = a->argv[4];
11199 }
11200
11201 if (ast_check_realtime("voicemail")) {
11202 if (!context) {
11203 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11204 return CLI_SHOWUSAGE;
11205 }
11206 return show_users_realtime(a->fd, context);
11207 }
11208
11209 AST_LIST_LOCK(&users);
11210 if (AST_LIST_EMPTY(&users)) {
11211 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11212 AST_LIST_UNLOCK(&users);
11213 return CLI_FAILURE;
11214 }
11215 if (!context) {
11216 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11217 } else {
11218 int count = 0;
11219 AST_LIST_TRAVERSE(&users, vmu, list) {
11220 if (!strcmp(context, vmu->context)) {
11221 count++;
11222 break;
11223 }
11224 }
11225 if (count) {
11226 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11227 } else {
11228 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11229 AST_LIST_UNLOCK(&users);
11230 return CLI_FAILURE;
11231 }
11232 }
11233 AST_LIST_TRAVERSE(&users, vmu, list) {
11234 int newmsgs = 0, oldmsgs = 0;
11235 char count[12], tmp[256] = "";
11236
11237 if (!context || !strcmp(context, vmu->context)) {
11238 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11239 inboxcount(tmp, &newmsgs, &oldmsgs);
11240 snprintf(count, sizeof(count), "%d", newmsgs);
11241 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11242 users_counter++;
11243 }
11244 }
11245 AST_LIST_UNLOCK(&users);
11246 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11247 return CLI_SUCCESS;
11248 }
11249
11250
11251 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11252 {
11253 struct vm_zone *zone;
11254 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11255 char *res = CLI_SUCCESS;
11256
11257 switch (cmd) {
11258 case CLI_INIT:
11259 e->command = "voicemail show zones";
11260 e->usage =
11261 "Usage: voicemail show zones\n"
11262 " Lists zone message formats\n";
11263 return NULL;
11264 case CLI_GENERATE:
11265 return NULL;
11266 }
11267
11268 if (a->argc != 3)
11269 return CLI_SHOWUSAGE;
11270
11271 AST_LIST_LOCK(&zones);
11272 if (!AST_LIST_EMPTY(&zones)) {
11273 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11274 AST_LIST_TRAVERSE(&zones, zone, list) {
11275 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11276 }
11277 } else {
11278 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11279 res = CLI_FAILURE;
11280 }
11281 AST_LIST_UNLOCK(&zones);
11282
11283 return res;
11284 }
11285
11286
11287 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11288 {
11289 switch (cmd) {
11290 case CLI_INIT:
11291 e->command = "voicemail reload";
11292 e->usage =
11293 "Usage: voicemail reload\n"
11294 " Reload voicemail configuration\n";
11295 return NULL;
11296 case CLI_GENERATE:
11297 return NULL;
11298 }
11299
11300 if (a->argc != 2)
11301 return CLI_SHOWUSAGE;
11302
11303 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11304 load_config(1);
11305
11306 return CLI_SUCCESS;
11307 }
11308
11309 static struct ast_cli_entry cli_voicemail[] = {
11310 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11311 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11312 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11313 };
11314
11315 #ifdef IMAP_STORAGE
11316 #define DATA_EXPORT_VM_USERS(USER) \
11317 USER(ast_vm_user, context, AST_DATA_STRING) \
11318 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11319 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11320 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11321 USER(ast_vm_user, email, AST_DATA_STRING) \
11322 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11323 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11324 USER(ast_vm_user, pager, AST_DATA_STRING) \
11325 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11326 USER(ast_vm_user, language, AST_DATA_STRING) \
11327 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11328 USER(ast_vm_user, callback, AST_DATA_STRING) \
11329 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11330 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11331 USER(ast_vm_user, exit, AST_DATA_STRING) \
11332 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11333 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11334 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11335 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11336 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11337 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11338 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11339 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11340 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11341 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11342 #else
11343 #define DATA_EXPORT_VM_USERS(USER) \
11344 USER(ast_vm_user, context, AST_DATA_STRING) \
11345 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11346 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11347 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11348 USER(ast_vm_user, email, AST_DATA_STRING) \
11349 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11350 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11351 USER(ast_vm_user, pager, AST_DATA_STRING) \
11352 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11353 USER(ast_vm_user, language, AST_DATA_STRING) \
11354 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11355 USER(ast_vm_user, callback, AST_DATA_STRING) \
11356 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11357 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11358 USER(ast_vm_user, exit, AST_DATA_STRING) \
11359 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11360 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11361 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11362 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11363 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11364 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11365 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11366 #endif
11367
11368 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11369
11370 #define DATA_EXPORT_VM_ZONES(ZONE) \
11371 ZONE(vm_zone, name, AST_DATA_STRING) \
11372 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11373 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11374
11375 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11376
11377
11378
11379
11380
11381
11382
11383
11384 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11385 struct ast_data *data_root, struct ast_vm_user *user)
11386 {
11387 struct ast_data *data_user, *data_zone;
11388 struct ast_data *data_state;
11389 struct vm_zone *zone = NULL;
11390 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11391 char ext_context[256] = "";
11392
11393 data_user = ast_data_add_node(data_root, "user");
11394 if (!data_user) {
11395 return -1;
11396 }
11397
11398 ast_data_add_structure(ast_vm_user, data_user, user);
11399
11400 AST_LIST_LOCK(&zones);
11401 AST_LIST_TRAVERSE(&zones, zone, list) {
11402 if (!strcmp(zone->name, user->zonetag)) {
11403 break;
11404 }
11405 }
11406 AST_LIST_UNLOCK(&zones);
11407
11408
11409 data_state = ast_data_add_node(data_user, "state");
11410 if (!data_state) {
11411 return -1;
11412 }
11413 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11414 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11415 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11416 ast_data_add_int(data_state, "newmsg", newmsg);
11417 ast_data_add_int(data_state, "oldmsg", oldmsg);
11418
11419 if (zone) {
11420 data_zone = ast_data_add_node(data_user, "zone");
11421 ast_data_add_structure(vm_zone, data_zone, zone);
11422 }
11423
11424 if (!ast_data_search_match(search, data_user)) {
11425 ast_data_remove_node(data_root, data_user);
11426 }
11427
11428 return 0;
11429 }
11430
11431 static int vm_users_data_provider_get(const struct ast_data_search *search,
11432 struct ast_data *data_root)
11433 {
11434 struct ast_vm_user *user;
11435
11436 AST_LIST_LOCK(&users);
11437 AST_LIST_TRAVERSE(&users, user, list) {
11438 vm_users_data_provider_get_helper(search, data_root, user);
11439 }
11440 AST_LIST_UNLOCK(&users);
11441
11442 return 0;
11443 }
11444
11445 static const struct ast_data_handler vm_users_data_provider = {
11446 .version = AST_DATA_HANDLER_VERSION,
11447 .get = vm_users_data_provider_get
11448 };
11449
11450 static const struct ast_data_entry vm_data_providers[] = {
11451 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11452 };
11453
11454 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11455 {
11456 int new = 0, old = 0, urgent = 0;
11457
11458 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11459
11460 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11461 mwi_sub->old_urgent = urgent;
11462 mwi_sub->old_new = new;
11463 mwi_sub->old_old = old;
11464 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11465 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11466 }
11467 }
11468
11469 static void poll_subscribed_mailboxes(void)
11470 {
11471 struct mwi_sub *mwi_sub;
11472
11473 AST_RWLIST_RDLOCK(&mwi_subs);
11474 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11475 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11476 poll_subscribed_mailbox(mwi_sub);
11477 }
11478 }
11479 AST_RWLIST_UNLOCK(&mwi_subs);
11480 }
11481
11482 static void *mb_poll_thread(void *data)
11483 {
11484 while (poll_thread_run) {
11485 struct timespec ts = { 0, };
11486 struct timeval wait;
11487
11488 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11489 ts.tv_sec = wait.tv_sec;
11490 ts.tv_nsec = wait.tv_usec * 1000;
11491
11492 ast_mutex_lock(&poll_lock);
11493 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11494 ast_mutex_unlock(&poll_lock);
11495
11496 if (!poll_thread_run)
11497 break;
11498
11499 poll_subscribed_mailboxes();
11500 }
11501
11502 return NULL;
11503 }
11504
11505 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11506 {
11507 ast_free(mwi_sub);
11508 }
11509
11510 static int handle_unsubscribe(void *datap)
11511 {
11512 struct mwi_sub *mwi_sub;
11513 uint32_t *uniqueid = datap;
11514
11515 AST_RWLIST_WRLOCK(&mwi_subs);
11516 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11517 if (mwi_sub->uniqueid == *uniqueid) {
11518 AST_LIST_REMOVE_CURRENT(entry);
11519 break;
11520 }
11521 }
11522 AST_RWLIST_TRAVERSE_SAFE_END
11523 AST_RWLIST_UNLOCK(&mwi_subs);
11524
11525 if (mwi_sub)
11526 mwi_sub_destroy(mwi_sub);
11527
11528 ast_free(uniqueid);
11529 return 0;
11530 }
11531
11532 static int handle_subscribe(void *datap)
11533 {
11534 unsigned int len;
11535 struct mwi_sub *mwi_sub;
11536 struct mwi_sub_task *p = datap;
11537
11538 len = sizeof(*mwi_sub);
11539 if (!ast_strlen_zero(p->mailbox))
11540 len += strlen(p->mailbox);
11541
11542 if (!ast_strlen_zero(p->context))
11543 len += strlen(p->context) + 1;
11544
11545 if (!(mwi_sub = ast_calloc(1, len)))
11546 return -1;
11547
11548 mwi_sub->uniqueid = p->uniqueid;
11549 if (!ast_strlen_zero(p->mailbox))
11550 strcpy(mwi_sub->mailbox, p->mailbox);
11551
11552 if (!ast_strlen_zero(p->context)) {
11553 strcat(mwi_sub->mailbox, "@");
11554 strcat(mwi_sub->mailbox, p->context);
11555 }
11556
11557 AST_RWLIST_WRLOCK(&mwi_subs);
11558 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11559 AST_RWLIST_UNLOCK(&mwi_subs);
11560 ast_free((void *) p->mailbox);
11561 ast_free((void *) p->context);
11562 ast_free(p);
11563 poll_subscribed_mailbox(mwi_sub);
11564 return 0;
11565 }
11566
11567 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11568 {
11569 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11570
11571 if (!uniqueid) {
11572 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11573 return;
11574 }
11575
11576 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11577 ast_free(uniqueid);
11578 return;
11579 }
11580
11581 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11582 ast_free(uniqueid);
11583 return;
11584 }
11585
11586 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11587 *uniqueid = u;
11588 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11589 ast_free(uniqueid);
11590 }
11591 }
11592
11593 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11594 {
11595 struct mwi_sub_task *mwist;
11596
11597 if (ast_event_get_type(event) != AST_EVENT_SUB)
11598 return;
11599
11600 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11601 return;
11602
11603 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11604 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11605 return;
11606 }
11607 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11608 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11609 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11610
11611 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11612 ast_free(mwist);
11613 }
11614 }
11615
11616 static void start_poll_thread(void)
11617 {
11618 int errcode;
11619 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11620 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11621 AST_EVENT_IE_END);
11622
11623 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11624 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11625 AST_EVENT_IE_END);
11626
11627 if (mwi_sub_sub)
11628 ast_event_report_subs(mwi_sub_sub);
11629
11630 poll_thread_run = 1;
11631
11632 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11633 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11634 }
11635 }
11636
11637 static void stop_poll_thread(void)
11638 {
11639 poll_thread_run = 0;
11640
11641 if (mwi_sub_sub) {
11642 ast_event_unsubscribe(mwi_sub_sub);
11643 mwi_sub_sub = NULL;
11644 }
11645
11646 if (mwi_unsub_sub) {
11647 ast_event_unsubscribe(mwi_unsub_sub);
11648 mwi_unsub_sub = NULL;
11649 }
11650
11651 ast_mutex_lock(&poll_lock);
11652 ast_cond_signal(&poll_cond);
11653 ast_mutex_unlock(&poll_lock);
11654
11655 pthread_join(poll_thread, NULL);
11656
11657 poll_thread = AST_PTHREADT_NULL;
11658 }
11659
11660
11661 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11662 {
11663 struct ast_vm_user *vmu = NULL;
11664 const char *id = astman_get_header(m, "ActionID");
11665 char actionid[128] = "";
11666
11667 if (!ast_strlen_zero(id))
11668 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11669
11670 AST_LIST_LOCK(&users);
11671
11672 if (AST_LIST_EMPTY(&users)) {
11673 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11674 AST_LIST_UNLOCK(&users);
11675 return RESULT_SUCCESS;
11676 }
11677
11678 astman_send_ack(s, m, "Voicemail user list will follow");
11679
11680 AST_LIST_TRAVERSE(&users, vmu, list) {
11681 char dirname[256];
11682
11683 #ifdef IMAP_STORAGE
11684 int new, old;
11685 inboxcount(vmu->mailbox, &new, &old);
11686 #endif
11687
11688 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11689 astman_append(s,
11690 "%s"
11691 "Event: VoicemailUserEntry\r\n"
11692 "VMContext: %s\r\n"
11693 "VoiceMailbox: %s\r\n"
11694 "Fullname: %s\r\n"
11695 "Email: %s\r\n"
11696 "Pager: %s\r\n"
11697 "ServerEmail: %s\r\n"
11698 "MailCommand: %s\r\n"
11699 "Language: %s\r\n"
11700 "TimeZone: %s\r\n"
11701 "Callback: %s\r\n"
11702 "Dialout: %s\r\n"
11703 "UniqueID: %s\r\n"
11704 "ExitContext: %s\r\n"
11705 "SayDurationMinimum: %d\r\n"
11706 "SayEnvelope: %s\r\n"
11707 "SayCID: %s\r\n"
11708 "AttachMessage: %s\r\n"
11709 "AttachmentFormat: %s\r\n"
11710 "DeleteMessage: %s\r\n"
11711 "VolumeGain: %.2f\r\n"
11712 "CanReview: %s\r\n"
11713 "CallOperator: %s\r\n"
11714 "MaxMessageCount: %d\r\n"
11715 "MaxMessageLength: %d\r\n"
11716 "NewMessageCount: %d\r\n"
11717 #ifdef IMAP_STORAGE
11718 "OldMessageCount: %d\r\n"
11719 "IMAPUser: %s\r\n"
11720 #endif
11721 "\r\n",
11722 actionid,
11723 vmu->context,
11724 vmu->mailbox,
11725 vmu->fullname,
11726 vmu->email,
11727 vmu->pager,
11728 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11729 mailcmd,
11730 vmu->language,
11731 vmu->zonetag,
11732 vmu->callback,
11733 vmu->dialout,
11734 vmu->uniqueid,
11735 vmu->exit,
11736 vmu->saydurationm,
11737 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11738 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11739 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11740 vmu->attachfmt,
11741 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11742 vmu->volgain,
11743 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11744 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11745 vmu->maxmsg,
11746 vmu->maxsecs,
11747 #ifdef IMAP_STORAGE
11748 new, old, vmu->imapuser
11749 #else
11750 count_messages(vmu, dirname)
11751 #endif
11752 );
11753 }
11754 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11755
11756 AST_LIST_UNLOCK(&users);
11757
11758 return RESULT_SUCCESS;
11759 }
11760
11761
11762 static void free_vm_users(void)
11763 {
11764 struct ast_vm_user *current;
11765 AST_LIST_LOCK(&users);
11766 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11767 ast_set_flag(current, VM_ALLOCED);
11768 free_user(current);
11769 }
11770 AST_LIST_UNLOCK(&users);
11771 }
11772
11773
11774 static void free_vm_zones(void)
11775 {
11776 struct vm_zone *zcur;
11777 AST_LIST_LOCK(&zones);
11778 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11779 free_zone(zcur);
11780 AST_LIST_UNLOCK(&zones);
11781 }
11782
11783 static const char *substitute_escapes(const char *value)
11784 {
11785 char *current;
11786
11787
11788 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11789
11790 ast_str_reset(str);
11791
11792
11793 for (current = (char *) value; *current; current++) {
11794 if (*current == '\\') {
11795 current++;
11796 if (!*current) {
11797 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11798 break;
11799 }
11800 switch (*current) {
11801 case '\\':
11802 ast_str_append(&str, 0, "\\");
11803 break;
11804 case 'r':
11805 ast_str_append(&str, 0, "\r");
11806 break;
11807 case 'n':
11808 #ifdef IMAP_STORAGE
11809 if (!str->used || str->str[str->used - 1] != '\r') {
11810 ast_str_append(&str, 0, "\r");
11811 }
11812 #endif
11813 ast_str_append(&str, 0, "\n");
11814 break;
11815 case 't':
11816 ast_str_append(&str, 0, "\t");
11817 break;
11818 default:
11819 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11820 break;
11821 }
11822 } else {
11823 ast_str_append(&str, 0, "%c", *current);
11824 }
11825 }
11826
11827 return ast_str_buffer(str);
11828 }
11829
11830 static int load_config(int reload)
11831 {
11832 struct ast_config *cfg, *ucfg;
11833 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11834 int res;
11835
11836 ast_unload_realtime("voicemail");
11837 ast_unload_realtime("voicemail_data");
11838
11839 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11840 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11841 return 0;
11842 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11843 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11844 ucfg = NULL;
11845 }
11846 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11847 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11848 ast_config_destroy(ucfg);
11849 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11850 return 0;
11851 }
11852 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11853 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11854 return 0;
11855 } else {
11856 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11857 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11858 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11859 ucfg = NULL;
11860 }
11861 }
11862
11863 res = actual_load_config(reload, cfg, ucfg);
11864
11865 ast_config_destroy(cfg);
11866 ast_config_destroy(ucfg);
11867
11868 return res;
11869 }
11870
11871 #ifdef TEST_FRAMEWORK
11872 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11873 {
11874 ast_unload_realtime("voicemail");
11875 ast_unload_realtime("voicemail_data");
11876 return actual_load_config(reload, cfg, ucfg);
11877 }
11878 #endif
11879
11880 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11881 {
11882 struct ast_vm_user *current;
11883 char *cat;
11884 struct ast_variable *var;
11885 const char *val;
11886 char *q, *stringp, *tmp;
11887 int x;
11888 int tmpadsi[4];
11889 char secretfn[PATH_MAX] = "";
11890
11891 #ifdef IMAP_STORAGE
11892 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11893 #endif
11894
11895 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11896 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11897 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11898 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11899 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11900
11901
11902 free_vm_users();
11903
11904
11905 free_vm_zones();
11906
11907 AST_LIST_LOCK(&users);
11908
11909 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11910 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11911
11912 if (cfg) {
11913
11914
11915 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11916 val = "default";
11917 ast_copy_string(userscontext, val, sizeof(userscontext));
11918
11919 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11920 val = "yes";
11921 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11922
11923 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11924 val = "no";
11925 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11926
11927 volgain = 0.0;
11928 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11929 sscanf(val, "%30lf", &volgain);
11930
11931 #ifdef ODBC_STORAGE
11932 strcpy(odbc_database, "asterisk");
11933 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11934 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11935 }
11936 strcpy(odbc_table, "voicemessages");
11937 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11938 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11939 }
11940 #endif
11941
11942 strcpy(mailcmd, SENDMAIL);
11943 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11944 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11945
11946 maxsilence = 0;
11947 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11948 maxsilence = atoi(val);
11949 if (maxsilence > 0)
11950 maxsilence *= 1000;
11951 }
11952
11953 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11954 maxmsg = MAXMSG;
11955 } else {
11956 maxmsg = atoi(val);
11957 if (maxmsg < 0) {
11958 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11959 maxmsg = MAXMSG;
11960 } else if (maxmsg > MAXMSGLIMIT) {
11961 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11962 maxmsg = MAXMSGLIMIT;
11963 }
11964 }
11965
11966 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11967 maxdeletedmsg = 0;
11968 } else {
11969 if (sscanf(val, "%30d", &x) == 1)
11970 maxdeletedmsg = x;
11971 else if (ast_true(val))
11972 maxdeletedmsg = MAXMSG;
11973 else
11974 maxdeletedmsg = 0;
11975
11976 if (maxdeletedmsg < 0) {
11977 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11978 maxdeletedmsg = MAXMSG;
11979 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11980 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11981 maxdeletedmsg = MAXMSGLIMIT;
11982 }
11983 }
11984
11985
11986 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11987 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11988 }
11989
11990
11991 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11992 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11993 }
11994
11995
11996 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11997 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11998 pwdchange = PWDCHANGE_EXTERNAL;
11999 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12000 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12001 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12002 }
12003
12004
12005 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12006 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12007 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12008 }
12009
12010 #ifdef IMAP_STORAGE
12011
12012 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12013 ast_copy_string(imapserver, val, sizeof(imapserver));
12014 } else {
12015 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12016 }
12017
12018 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12019 ast_copy_string(imapport, val, sizeof(imapport));
12020 } else {
12021 ast_copy_string(imapport, "143", sizeof(imapport));
12022 }
12023
12024 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12025 ast_copy_string(imapflags, val, sizeof(imapflags));
12026 }
12027
12028 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12029 ast_copy_string(authuser, val, sizeof(authuser));
12030 }
12031
12032 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12033 ast_copy_string(authpassword, val, sizeof(authpassword));
12034 }
12035
12036 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12037 if (ast_false(val))
12038 expungeonhangup = 0;
12039 else
12040 expungeonhangup = 1;
12041 } else {
12042 expungeonhangup = 1;
12043 }
12044
12045 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12046 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12047 } else {
12048 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12049 }
12050 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12051 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12052 }
12053 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12054 imapgreetings = ast_true(val);
12055 } else {
12056 imapgreetings = 0;
12057 }
12058 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12059 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12060 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12061
12062 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12063 } else {
12064 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12065 }
12066
12067
12068
12069
12070
12071 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12072 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12073 } else {
12074 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12075 }
12076
12077 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12078 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12079 } else {
12080 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12081 }
12082
12083 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12084 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12085 } else {
12086 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12087 }
12088
12089 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12090 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12091 } else {
12092 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12093 }
12094
12095
12096 imapversion++;
12097 #endif
12098
12099 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12100 ast_copy_string(externnotify, val, sizeof(externnotify));
12101 ast_debug(1, "found externnotify: %s\n", externnotify);
12102 } else {
12103 externnotify[0] = '\0';
12104 }
12105
12106
12107 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12108 ast_debug(1, "Enabled SMDI voicemail notification\n");
12109 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12110 smdi_iface = ast_smdi_interface_find(val);
12111 } else {
12112 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12113 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12114 }
12115 if (!smdi_iface) {
12116 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12117 }
12118 }
12119
12120
12121 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12122 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12123 silencethreshold = atoi(val);
12124
12125 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12126 val = ASTERISK_USERNAME;
12127 ast_copy_string(serveremail, val, sizeof(serveremail));
12128
12129 vmmaxsecs = 0;
12130 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12131 if (sscanf(val, "%30d", &x) == 1) {
12132 vmmaxsecs = x;
12133 } else {
12134 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12135 }
12136 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12137 static int maxmessage_deprecate = 0;
12138 if (maxmessage_deprecate == 0) {
12139 maxmessage_deprecate = 1;
12140 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12141 }
12142 if (sscanf(val, "%30d", &x) == 1) {
12143 vmmaxsecs = x;
12144 } else {
12145 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12146 }
12147 }
12148
12149 vmminsecs = 0;
12150 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12151 if (sscanf(val, "%30d", &x) == 1) {
12152 vmminsecs = x;
12153 if (maxsilence / 1000 >= vmminsecs) {
12154 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12155 }
12156 } else {
12157 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12158 }
12159 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12160 static int maxmessage_deprecate = 0;
12161 if (maxmessage_deprecate == 0) {
12162 maxmessage_deprecate = 1;
12163 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12164 }
12165 if (sscanf(val, "%30d", &x) == 1) {
12166 vmminsecs = x;
12167 if (maxsilence / 1000 >= vmminsecs) {
12168 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12169 }
12170 } else {
12171 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12172 }
12173 }
12174
12175 val = ast_variable_retrieve(cfg, "general", "format");
12176 if (!val) {
12177 val = "wav";
12178 } else {
12179 tmp = ast_strdupa(val);
12180 val = ast_format_str_reduce(tmp);
12181 if (!val) {
12182 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12183 val = "wav";
12184 }
12185 }
12186 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12187
12188 skipms = 3000;
12189 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12190 if (sscanf(val, "%30d", &x) == 1) {
12191 maxgreet = x;
12192 } else {
12193 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12194 }
12195 }
12196
12197 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12198 if (sscanf(val, "%30d", &x) == 1) {
12199 skipms = x;
12200 } else {
12201 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12202 }
12203 }
12204
12205 maxlogins = 3;
12206 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12207 if (sscanf(val, "%30d", &x) == 1) {
12208 maxlogins = x;
12209 } else {
12210 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12211 }
12212 }
12213
12214 minpassword = MINPASSWORD;
12215 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12216 if (sscanf(val, "%30d", &x) == 1) {
12217 minpassword = x;
12218 } else {
12219 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12220 }
12221 }
12222
12223
12224 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12225 val = "no";
12226 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12227
12228
12229 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12230 val = "no";
12231 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12232
12233 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12234 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12235 stringp = ast_strdupa(val);
12236 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12237 if (!ast_strlen_zero(stringp)) {
12238 q = strsep(&stringp, ",");
12239 while ((*q == ' ')||(*q == '\t'))
12240 q++;
12241 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12242 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12243 } else {
12244 cidinternalcontexts[x][0] = '\0';
12245 }
12246 }
12247 }
12248 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12249 ast_debug(1, "VM Review Option disabled globally\n");
12250 val = "no";
12251 }
12252 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12253
12254
12255 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12256 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12257 val = "no";
12258 } else {
12259 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12260 }
12261 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12262 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12263 ast_debug(1, "VM next message wrap disabled globally\n");
12264 val = "no";
12265 }
12266 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12267
12268 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12269 ast_debug(1, "VM Operator break disabled globally\n");
12270 val = "no";
12271 }
12272 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12273
12274 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12275 ast_debug(1, "VM CID Info before msg disabled globally\n");
12276 val = "no";
12277 }
12278 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12279
12280 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12281 ast_debug(1, "Send Voicemail msg disabled globally\n");
12282 val = "no";
12283 }
12284 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12285
12286 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12287 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12288 val = "yes";
12289 }
12290 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12291
12292 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12293 ast_debug(1, "Move Heard enabled globally\n");
12294 val = "yes";
12295 }
12296 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12297
12298 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12299 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12300 val = "no";
12301 }
12302 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12303
12304 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12305 ast_debug(1, "Duration info before msg enabled globally\n");
12306 val = "yes";
12307 }
12308 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12309
12310 saydurationminfo = 2;
12311 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12312 if (sscanf(val, "%30d", &x) == 1) {
12313 saydurationminfo = x;
12314 } else {
12315 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12316 }
12317 }
12318
12319 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12320 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12321 val = "no";
12322 }
12323 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12324
12325 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12326 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12327 ast_debug(1, "found dialout context: %s\n", dialcontext);
12328 } else {
12329 dialcontext[0] = '\0';
12330 }
12331
12332 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12333 ast_copy_string(callcontext, val, sizeof(callcontext));
12334 ast_debug(1, "found callback context: %s\n", callcontext);
12335 } else {
12336 callcontext[0] = '\0';
12337 }
12338
12339 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12340 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12341 ast_debug(1, "found operator context: %s\n", exitcontext);
12342 } else {
12343 exitcontext[0] = '\0';
12344 }
12345
12346
12347 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12348 ast_copy_string(vm_password, val, sizeof(vm_password));
12349 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12350 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12351 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12352 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12353 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12354 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12355 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12356 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12357 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12358 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12359 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12360 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12361 }
12362 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12363 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12364 }
12365
12366 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12367 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12368 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12369 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12370 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12371 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12372 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12373 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12374 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12375 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12376
12377 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12378 val = "no";
12379 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12380
12381 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12382 val = "voicemail.conf";
12383 }
12384 if (!(strcmp(val, "spooldir"))) {
12385 passwordlocation = OPT_PWLOC_SPOOLDIR;
12386 } else {
12387 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12388 }
12389
12390 poll_freq = DEFAULT_POLL_FREQ;
12391 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12392 if (sscanf(val, "%30u", &poll_freq) != 1) {
12393 poll_freq = DEFAULT_POLL_FREQ;
12394 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12395 }
12396 }
12397
12398 poll_mailboxes = 0;
12399 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12400 poll_mailboxes = ast_true(val);
12401
12402 memset(fromstring, 0, sizeof(fromstring));
12403 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12404 strcpy(charset, "ISO-8859-1");
12405 if (emailbody) {
12406 ast_free(emailbody);
12407 emailbody = NULL;
12408 }
12409 if (emailsubject) {
12410 ast_free(emailsubject);
12411 emailsubject = NULL;
12412 }
12413 if (pagerbody) {
12414 ast_free(pagerbody);
12415 pagerbody = NULL;
12416 }
12417 if (pagersubject) {
12418 ast_free(pagersubject);
12419 pagersubject = NULL;
12420 }
12421 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12422 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12423 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12424 ast_copy_string(fromstring, val, sizeof(fromstring));
12425 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12426 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12427 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12428 ast_copy_string(charset, val, sizeof(charset));
12429 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12430 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12431 for (x = 0; x < 4; x++) {
12432 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12433 }
12434 }
12435 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12436 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12437 for (x = 0; x < 4; x++) {
12438 memcpy(&adsisec[x], &tmpadsi[x], 1);
12439 }
12440 }
12441 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12442 if (atoi(val)) {
12443 adsiver = atoi(val);
12444 }
12445 }
12446 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12447 ast_copy_string(zonetag, val, sizeof(zonetag));
12448 }
12449 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12450 ast_copy_string(locale, val, sizeof(locale));
12451 }
12452 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12453 emailsubject = ast_strdup(substitute_escapes(val));
12454 }
12455 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12456 emailbody = ast_strdup(substitute_escapes(val));
12457 }
12458 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12459 pagersubject = ast_strdup(substitute_escapes(val));
12460 }
12461 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12462 pagerbody = ast_strdup(substitute_escapes(val));
12463 }
12464
12465
12466 if (ucfg) {
12467 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12468 if (!strcasecmp(cat, "general")) {
12469 continue;
12470 }
12471 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12472 continue;
12473 if ((current = find_or_create(userscontext, cat))) {
12474 populate_defaults(current);
12475 apply_options_full(current, ast_variable_browse(ucfg, cat));
12476 ast_copy_string(current->context, userscontext, sizeof(current->context));
12477 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12478 current->passwordlocation = OPT_PWLOC_USERSCONF;
12479 }
12480
12481 switch (current->passwordlocation) {
12482 case OPT_PWLOC_SPOOLDIR:
12483 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12484 read_password_from_file(secretfn, current->password, sizeof(current->password));
12485 }
12486 }
12487 }
12488 }
12489
12490
12491 cat = ast_category_browse(cfg, NULL);
12492 while (cat) {
12493 if (strcasecmp(cat, "general")) {
12494 var = ast_variable_browse(cfg, cat);
12495 if (strcasecmp(cat, "zonemessages")) {
12496
12497 while (var) {
12498 append_mailbox(cat, var->name, var->value);
12499 var = var->next;
12500 }
12501 } else {
12502
12503 while (var) {
12504 struct vm_zone *z;
12505 if ((z = ast_malloc(sizeof(*z)))) {
12506 char *msg_format, *tzone;
12507 msg_format = ast_strdupa(var->value);
12508 tzone = strsep(&msg_format, "|,");
12509 if (msg_format) {
12510 ast_copy_string(z->name, var->name, sizeof(z->name));
12511 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12512 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12513 AST_LIST_LOCK(&zones);
12514 AST_LIST_INSERT_HEAD(&zones, z, list);
12515 AST_LIST_UNLOCK(&zones);
12516 } else {
12517 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12518 ast_free(z);
12519 }
12520 } else {
12521 AST_LIST_UNLOCK(&users);
12522 return -1;
12523 }
12524 var = var->next;
12525 }
12526 }
12527 }
12528 cat = ast_category_browse(cfg, cat);
12529 }
12530
12531 AST_LIST_UNLOCK(&users);
12532
12533 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12534 start_poll_thread();
12535 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12536 stop_poll_thread();;
12537
12538 return 0;
12539 } else {
12540 AST_LIST_UNLOCK(&users);
12541 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12542 return 0;
12543 }
12544 }
12545
12546 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12547 {
12548 int res = -1;
12549 char dir[PATH_MAX];
12550 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12551 ast_debug(2, "About to try retrieving name file %s\n", dir);
12552 RETRIEVE(dir, -1, mailbox, context);
12553 if (ast_fileexists(dir, NULL, NULL)) {
12554 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12555 }
12556 DISPOSE(dir, -1);
12557 return res;
12558 }
12559
12560 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12561 struct ast_config *pwconf;
12562 struct ast_flags config_flags = { 0 };
12563
12564 pwconf = ast_config_load(secretfn, config_flags);
12565 if (pwconf) {
12566 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12567 if (val) {
12568 ast_copy_string(password, val, passwordlen);
12569 ast_config_destroy(pwconf);
12570 return;
12571 }
12572 ast_config_destroy(pwconf);
12573 }
12574 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12575 }
12576
12577 static int write_password_to_file(const char *secretfn, const char *password) {
12578 struct ast_config *conf;
12579 struct ast_category *cat;
12580 struct ast_variable *var;
12581 int res = -1;
12582
12583 if (!(conf = ast_config_new())) {
12584 ast_log(LOG_ERROR, "Error creating new config structure\n");
12585 return res;
12586 }
12587 if (!(cat = ast_category_new("general", "", 1))) {
12588 ast_log(LOG_ERROR, "Error creating new category structure\n");
12589 ast_config_destroy(conf);
12590 return res;
12591 }
12592 if (!(var = ast_variable_new("password", password, ""))) {
12593 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12594 ast_config_destroy(conf);
12595 ast_category_destroy(cat);
12596 return res;
12597 }
12598 ast_category_append(conf, cat);
12599 ast_variable_append(cat, var);
12600 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12601 res = 0;
12602 } else {
12603 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12604 }
12605
12606 ast_config_destroy(conf);
12607 return res;
12608 }
12609
12610 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12611 {
12612 char *context;
12613 char *args_copy;
12614 int res;
12615
12616 if (ast_strlen_zero(data)) {
12617 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12618 return -1;
12619 }
12620
12621 args_copy = ast_strdupa(data);
12622 if ((context = strchr(args_copy, '@'))) {
12623 *context++ = '\0';
12624 } else {
12625 context = "default";
12626 }
12627
12628 if ((res = sayname(chan, args_copy, context) < 0)) {
12629 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12630 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12631 if (!res) {
12632 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12633 }
12634 }
12635
12636 return res;
12637 }
12638
12639 #ifdef TEST_FRAMEWORK
12640 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12641 {
12642 return 0;
12643 }
12644
12645 static struct ast_frame *fake_read(struct ast_channel *ast)
12646 {
12647 return &ast_null_frame;
12648 }
12649
12650 AST_TEST_DEFINE(test_voicemail_vmsayname)
12651 {
12652 char dir[PATH_MAX];
12653 char dir2[PATH_MAX];
12654 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12655 static const char TEST_EXTENSION[] = "1234";
12656
12657 struct ast_channel *test_channel1 = NULL;
12658 int res = -1;
12659
12660 static const struct ast_channel_tech fake_tech = {
12661 .write = fake_write,
12662 .read = fake_read,
12663 };
12664
12665 switch (cmd) {
12666 case TEST_INIT:
12667 info->name = "vmsayname_exec";
12668 info->category = "/apps/app_voicemail/";
12669 info->summary = "Vmsayname unit test";
12670 info->description =
12671 "This tests passing various parameters to vmsayname";
12672 return AST_TEST_NOT_RUN;
12673 case TEST_EXECUTE:
12674 break;
12675 }
12676
12677 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12678 NULL, NULL, 0, 0, "TestChannel1"))) {
12679 goto exit_vmsayname_test;
12680 }
12681
12682
12683 test_channel1->nativeformats = AST_FORMAT_GSM;
12684 test_channel1->writeformat = AST_FORMAT_GSM;
12685 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12686 test_channel1->readformat = AST_FORMAT_GSM;
12687 test_channel1->rawreadformat = AST_FORMAT_GSM;
12688 test_channel1->tech = &fake_tech;
12689
12690 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12691 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12692 if (!(res = vmsayname_exec(test_channel1, dir))) {
12693 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12694 if (ast_fileexists(dir, NULL, NULL)) {
12695 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12696 res = -1;
12697 goto exit_vmsayname_test;
12698 } else {
12699
12700 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12701 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12702 goto exit_vmsayname_test;
12703 }
12704 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12705 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12706
12707 if ((res = symlink(dir, dir2))) {
12708 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12709 goto exit_vmsayname_test;
12710 }
12711 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12712 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12713 res = vmsayname_exec(test_channel1, dir);
12714
12715
12716 unlink(dir2);
12717 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12718 rmdir(dir2);
12719 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12720 rmdir(dir2);
12721 }
12722 }
12723
12724 exit_vmsayname_test:
12725
12726 if (test_channel1) {
12727 ast_hangup(test_channel1);
12728 }
12729
12730 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12731 }
12732
12733 AST_TEST_DEFINE(test_voicemail_msgcount)
12734 {
12735 int i, j, res = AST_TEST_PASS, syserr;
12736 struct ast_vm_user *vmu;
12737 struct vm_state vms;
12738 #ifdef IMAP_STORAGE
12739 struct ast_channel *chan = NULL;
12740 #endif
12741 struct {
12742 char dir[256];
12743 char file[256];
12744 char txtfile[256];
12745 } tmp[3];
12746 char syscmd[256];
12747 const char origweasels[] = "tt-weasels";
12748 const char testcontext[] = "test";
12749 const char testmailbox[] = "00000000";
12750 const char testspec[] = "00000000@test";
12751 FILE *txt;
12752 int new, old, urgent;
12753 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12754 const int folder2mbox[3] = { 1, 11, 0 };
12755 const int expected_results[3][12] = {
12756
12757 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12758 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12759 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12760 };
12761
12762 switch (cmd) {
12763 case TEST_INIT:
12764 info->name = "test_voicemail_msgcount";
12765 info->category = "/apps/app_voicemail/";
12766 info->summary = "Test Voicemail status checks";
12767 info->description =
12768 "Verify that message counts are correct when retrieved through the public API";
12769 return AST_TEST_NOT_RUN;
12770 case TEST_EXECUTE:
12771 break;
12772 }
12773
12774
12775 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12776 if ((syserr = ast_safe_system(syscmd))) {
12777 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12778 syserr > 0 ? strerror(syserr) : "unable to fork()");
12779 return AST_TEST_FAIL;
12780 }
12781
12782 #ifdef IMAP_STORAGE
12783 if (!(chan = ast_dummy_channel_alloc())) {
12784 ast_test_status_update(test, "Unable to create dummy channel\n");
12785 return AST_TEST_FAIL;
12786 }
12787 #endif
12788
12789 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12790 !(vmu = find_or_create(testcontext, testmailbox))) {
12791 ast_test_status_update(test, "Cannot create vmu structure\n");
12792 ast_unreplace_sigchld();
12793 #ifdef IMAP_STORAGE
12794 chan = ast_channel_unref(chan);
12795 #endif
12796 return AST_TEST_FAIL;
12797 }
12798
12799 populate_defaults(vmu);
12800 memset(&vms, 0, sizeof(vms));
12801
12802
12803 for (i = 0; i < 3; i++) {
12804 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12805 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12806 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12807
12808 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12809 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12810 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12811 if ((syserr = ast_safe_system(syscmd))) {
12812 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12813 syserr > 0 ? strerror(syserr) : "unable to fork()");
12814 ast_unreplace_sigchld();
12815 #ifdef IMAP_STORAGE
12816 chan = ast_channel_unref(chan);
12817 #endif
12818 return AST_TEST_FAIL;
12819 }
12820 }
12821
12822 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12823 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12824 fclose(txt);
12825 } else {
12826 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12827 res = AST_TEST_FAIL;
12828 break;
12829 }
12830 open_mailbox(&vms, vmu, folder2mbox[i]);
12831 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12832
12833
12834 for (j = 0; j < 3; j++) {
12835
12836 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12837 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12838 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12839 res = AST_TEST_FAIL;
12840 }
12841 }
12842
12843 new = old = urgent = 0;
12844 if (ast_app_inboxcount(testspec, &new, &old)) {
12845 ast_test_status_update(test, "inboxcount returned failure\n");
12846 res = AST_TEST_FAIL;
12847 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12848 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12849 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12850 res = AST_TEST_FAIL;
12851 }
12852
12853 new = old = urgent = 0;
12854 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12855 ast_test_status_update(test, "inboxcount2 returned failure\n");
12856 res = AST_TEST_FAIL;
12857 } else if (old != expected_results[i][6 + 0] ||
12858 urgent != expected_results[i][6 + 1] ||
12859 new != expected_results[i][6 + 2] ) {
12860 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12861 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12862 res = AST_TEST_FAIL;
12863 }
12864
12865 new = old = urgent = 0;
12866 for (j = 0; j < 3; j++) {
12867 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12868 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12869 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12870 res = AST_TEST_FAIL;
12871 }
12872 }
12873 }
12874
12875 for (i = 0; i < 3; i++) {
12876
12877
12878
12879 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12880 DISPOSE(tmp[i].dir, 0);
12881 }
12882
12883 if (vms.deleted) {
12884 ast_free(vms.deleted);
12885 }
12886 if (vms.heard) {
12887 ast_free(vms.heard);
12888 }
12889
12890 #ifdef IMAP_STORAGE
12891 chan = ast_channel_unref(chan);
12892 #endif
12893
12894
12895 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12896 if ((syserr = ast_safe_system(syscmd))) {
12897 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12898 syserr > 0 ? strerror(syserr) : "unable to fork()");
12899 }
12900
12901 return res;
12902 }
12903
12904 AST_TEST_DEFINE(test_voicemail_notify_endl)
12905 {
12906 int res = AST_TEST_PASS;
12907 char testcontext[] = "test";
12908 char testmailbox[] = "00000000";
12909 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12910 char attach[256], attach2[256];
12911 char buf[256] = "";
12912 struct ast_channel *chan = NULL;
12913 struct ast_vm_user *vmu, vmus = {
12914 .flags = 0,
12915 };
12916 FILE *file;
12917 struct {
12918 char *name;
12919 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12920 void *location;
12921 union {
12922 int intval;
12923 char *strval;
12924 } u;
12925 } test_items[] = {
12926 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12927 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12928 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12929 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12930 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12931 { "attach2", STRPTR, attach2, .u.strval = "" },
12932 { "attach", STRPTR, attach, .u.strval = "" },
12933 };
12934 int which;
12935
12936 switch (cmd) {
12937 case TEST_INIT:
12938 info->name = "test_voicemail_notify_endl";
12939 info->category = "/apps/app_voicemail/";
12940 info->summary = "Test Voicemail notification end-of-line";
12941 info->description =
12942 "Verify that notification emails use a consistent end-of-line character";
12943 return AST_TEST_NOT_RUN;
12944 case TEST_EXECUTE:
12945 break;
12946 }
12947
12948 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12949 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12950
12951 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12952 !(vmu = find_or_create(testcontext, testmailbox))) {
12953 ast_test_status_update(test, "Cannot create vmu structure\n");
12954 return AST_TEST_NOT_RUN;
12955 }
12956
12957 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12958 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12959 return AST_TEST_NOT_RUN;
12960 }
12961
12962 populate_defaults(vmu);
12963 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12964 #ifdef IMAP_STORAGE
12965
12966 #endif
12967
12968 file = tmpfile();
12969 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12970
12971 rewind(file);
12972 if (ftruncate(fileno(file), 0)) {
12973 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12974 res = AST_TEST_FAIL;
12975 break;
12976 }
12977
12978
12979 if (test_items[which].type == INT) {
12980 *((int *) test_items[which].location) = test_items[which].u.intval;
12981 } else if (test_items[which].type == FLAGVAL) {
12982 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12983 ast_clear_flag(vmu, test_items[which].u.intval);
12984 } else {
12985 ast_set_flag(vmu, test_items[which].u.intval);
12986 }
12987 } else if (test_items[which].type == STATIC) {
12988 strcpy(test_items[which].location, test_items[which].u.strval);
12989 } else if (test_items[which].type == STRPTR) {
12990 test_items[which].location = test_items[which].u.strval;
12991 }
12992
12993 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12994 rewind(file);
12995 while (fgets(buf, sizeof(buf), file)) {
12996 if (
12997 #ifdef IMAP_STORAGE
12998 buf[strlen(buf) - 2] != '\r'
12999 #else
13000 buf[strlen(buf) - 2] == '\r'
13001 #endif
13002 || buf[strlen(buf) - 1] != '\n') {
13003 res = AST_TEST_FAIL;
13004 }
13005 }
13006 }
13007 fclose(file);
13008 return res;
13009 }
13010
13011 AST_TEST_DEFINE(test_voicemail_load_config)
13012 {
13013 int res = AST_TEST_PASS;
13014 struct ast_vm_user *vmu;
13015 struct ast_config *cfg;
13016 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13017 int fd;
13018 FILE *file;
13019 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13020
13021 switch (cmd) {
13022 case TEST_INIT:
13023 info->name = "test_voicemail_load_config";
13024 info->category = "/apps/app_voicemail/";
13025 info->summary = "Test loading Voicemail config";
13026 info->description =
13027 "Verify that configuration is loaded consistently. "
13028 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13029 "some options were loaded after the mailboxes were instantiated, causing "
13030 "those options not to be set correctly.";
13031 return AST_TEST_NOT_RUN;
13032 case TEST_EXECUTE:
13033 break;
13034 }
13035
13036
13037 if ((fd = mkstemp(config_filename)) < 0) {
13038 return AST_TEST_FAIL;
13039 }
13040 if (!(file = fdopen(fd, "w"))) {
13041 close(fd);
13042 unlink(config_filename);
13043 return AST_TEST_FAIL;
13044 }
13045 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13046 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13047 fputs("00000002 => 9999,Mrs. Test\n", file);
13048 fclose(file);
13049
13050 if (!(cfg = ast_config_load(config_filename, config_flags))) {
13051 res = AST_TEST_FAIL;
13052 goto cleanup;
13053 }
13054
13055 load_config_from_memory(1, cfg, NULL);
13056 ast_config_destroy(cfg);
13057
13058 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13059 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13060 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13061
13062 AST_LIST_LOCK(&users);
13063 AST_LIST_TRAVERSE(&users, vmu, list) {
13064 if (!strcmp(vmu->mailbox, "00000001")) {
13065 if (0);
13066 CHECK(vmu, callback, "othercontext")
13067 CHECK(vmu, locale, "nl_NL.UTF-8")
13068 CHECK(vmu, zonetag, "central")
13069 } else if (!strcmp(vmu->mailbox, "00000002")) {
13070 if (0);
13071 CHECK(vmu, callback, "somecontext")
13072 CHECK(vmu, locale, "de_DE.UTF-8")
13073 CHECK(vmu, zonetag, "european")
13074 }
13075 }
13076 AST_LIST_UNLOCK(&users);
13077
13078 #undef CHECK
13079
13080
13081 load_config(1);
13082
13083 cleanup:
13084 unlink(config_filename);
13085 return res;
13086 }
13087
13088 #endif
13089
13090 static int reload(void)
13091 {
13092 return load_config(1);
13093 }
13094
13095 static int unload_module(void)
13096 {
13097 int res;
13098
13099 res = ast_unregister_application(app);
13100 res |= ast_unregister_application(app2);
13101 res |= ast_unregister_application(app3);
13102 res |= ast_unregister_application(app4);
13103 res |= ast_unregister_application(sayname_app);
13104 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13105 res |= ast_manager_unregister("VoicemailUsersList");
13106 res |= ast_data_unregister(NULL);
13107 #ifdef TEST_FRAMEWORK
13108 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13109 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13110 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13111 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13112 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13113 #endif
13114 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13115 ast_uninstall_vm_functions();
13116 ao2_ref(inprocess_container, -1);
13117
13118 if (poll_thread != AST_PTHREADT_NULL)
13119 stop_poll_thread();
13120
13121 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13122 ast_unload_realtime("voicemail");
13123 ast_unload_realtime("voicemail_data");
13124
13125 free_vm_users();
13126 free_vm_zones();
13127 return res;
13128 }
13129
13130 static int load_module(void)
13131 {
13132 int res;
13133 my_umask = umask(0);
13134 umask(my_umask);
13135
13136 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13137 return AST_MODULE_LOAD_DECLINE;
13138 }
13139
13140
13141 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13142
13143 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13144 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13145 }
13146
13147 if ((res = load_config(0)))
13148 return res;
13149
13150 res = ast_register_application_xml(app, vm_exec);
13151 res |= ast_register_application_xml(app2, vm_execmain);
13152 res |= ast_register_application_xml(app3, vm_box_exists);
13153 res |= ast_register_application_xml(app4, vmauthenticate);
13154 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13155 res |= ast_custom_function_register(&mailbox_exists_acf);
13156 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13157 #ifdef TEST_FRAMEWORK
13158 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13159 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13160 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13161 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13162 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13163 #endif
13164
13165 if (res)
13166 return res;
13167
13168 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13169 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13170
13171 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13172 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13173 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13174
13175 return res;
13176 }
13177
13178 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13179 {
13180 int cmd = 0;
13181 char destination[80] = "";
13182 int retries = 0;
13183
13184 if (!num) {
13185 ast_verb(3, "Destination number will be entered manually\n");
13186 while (retries < 3 && cmd != 't') {
13187 destination[1] = '\0';
13188 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13189 if (!cmd)
13190 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13191 if (!cmd)
13192 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13193 if (!cmd) {
13194 cmd = ast_waitfordigit(chan, 6000);
13195 if (cmd)
13196 destination[0] = cmd;
13197 }
13198 if (!cmd) {
13199 retries++;
13200 } else {
13201
13202 if (cmd < 0)
13203 return 0;
13204 if (cmd == '*') {
13205 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13206 return 0;
13207 }
13208 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13209 retries++;
13210 else
13211 cmd = 't';
13212 }
13213 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13214 }
13215 if (retries >= 3) {
13216 return 0;
13217 }
13218
13219 } else {
13220 if (option_verbose > 2)
13221 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13222 ast_copy_string(destination, num, sizeof(destination));
13223 }
13224
13225 if (!ast_strlen_zero(destination)) {
13226 if (destination[strlen(destination) -1 ] == '*')
13227 return 0;
13228 if (option_verbose > 2)
13229 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13230 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13231 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13232 chan->priority = 0;
13233 return 9;
13234 }
13235 return 0;
13236 }
13237
13238
13239
13240
13241
13242
13243
13244
13245
13246
13247
13248
13249
13250
13251 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)
13252 {
13253 int res = 0;
13254 char filename[PATH_MAX];
13255 struct ast_config *msg_cfg = NULL;
13256 const char *origtime, *context;
13257 char *name, *num;
13258 int retries = 0;
13259 char *cid;
13260 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13261
13262 vms->starting = 0;
13263
13264 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13265
13266
13267 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13268 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13269 msg_cfg = ast_config_load(filename, config_flags);
13270 DISPOSE(vms->curdir, vms->curmsg);
13271 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13272 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13273 return 0;
13274 }
13275
13276 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13277 ast_config_destroy(msg_cfg);
13278 return 0;
13279 }
13280
13281 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13282
13283 context = ast_variable_retrieve(msg_cfg, "message", "context");
13284 if (!strncasecmp("macro", context, 5))
13285 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13286 switch (option) {
13287 case 3:
13288 if (!res)
13289 res = play_message_datetime(chan, vmu, origtime, filename);
13290 if (!res)
13291 res = play_message_callerid(chan, vms, cid, context, 0);
13292
13293 res = 't';
13294 break;
13295
13296 case 2:
13297
13298 if (ast_strlen_zero(cid))
13299 break;
13300
13301 ast_callerid_parse(cid, &name, &num);
13302 while ((res > -1) && (res != 't')) {
13303 switch (res) {
13304 case '1':
13305 if (num) {
13306
13307 res = dialout(chan, vmu, num, vmu->callback);
13308 if (res) {
13309 ast_config_destroy(msg_cfg);
13310 return 9;
13311 }
13312 } else {
13313 res = '2';
13314 }
13315 break;
13316
13317 case '2':
13318
13319 if (!ast_strlen_zero(vmu->dialout)) {
13320 res = dialout(chan, vmu, NULL, vmu->dialout);
13321 if (res) {
13322 ast_config_destroy(msg_cfg);
13323 return 9;
13324 }
13325 } else {
13326 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13327 res = ast_play_and_wait(chan, "vm-sorry");
13328 }
13329 ast_config_destroy(msg_cfg);
13330 return res;
13331 case '*':
13332 res = 't';
13333 break;
13334 case '3':
13335 case '4':
13336 case '5':
13337 case '6':
13338 case '7':
13339 case '8':
13340 case '9':
13341 case '0':
13342
13343 res = ast_play_and_wait(chan, "vm-sorry");
13344 retries++;
13345 break;
13346 default:
13347 if (num) {
13348 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13349 res = ast_play_and_wait(chan, "vm-num-i-have");
13350 if (!res)
13351 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13352 if (!res)
13353 res = ast_play_and_wait(chan, "vm-tocallnum");
13354
13355 if (!ast_strlen_zero(vmu->dialout)) {
13356 if (!res)
13357 res = ast_play_and_wait(chan, "vm-calldiffnum");
13358 }
13359 } else {
13360 res = ast_play_and_wait(chan, "vm-nonumber");
13361 if (!ast_strlen_zero(vmu->dialout)) {
13362 if (!res)
13363 res = ast_play_and_wait(chan, "vm-toenternumber");
13364 }
13365 }
13366 if (!res) {
13367 res = ast_play_and_wait(chan, "vm-star-cancel");
13368 }
13369 if (!res) {
13370 res = ast_waitfordigit(chan, 6000);
13371 }
13372 if (!res) {
13373 retries++;
13374 if (retries > 3) {
13375 res = 't';
13376 }
13377 }
13378 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13379 break;
13380
13381 }
13382 if (res == 't')
13383 res = 0;
13384 else if (res == '*')
13385 res = -1;
13386 }
13387 break;
13388
13389 case 1:
13390
13391 if (ast_strlen_zero(cid))
13392 break;
13393
13394 ast_callerid_parse(cid, &name, &num);
13395 if (!num) {
13396 ast_verb(3, "No CID number available, no reply sent\n");
13397 if (!res)
13398 res = ast_play_and_wait(chan, "vm-nonumber");
13399 ast_config_destroy(msg_cfg);
13400 return res;
13401 } else {
13402 struct ast_vm_user vmu2;
13403 if (find_user(&vmu2, vmu->context, num)) {
13404 struct leave_vm_options leave_options;
13405 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13406 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13407
13408 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13409
13410 memset(&leave_options, 0, sizeof(leave_options));
13411 leave_options.record_gain = record_gain;
13412 res = leave_voicemail(chan, mailbox, &leave_options);
13413 if (!res)
13414 res = 't';
13415 ast_config_destroy(msg_cfg);
13416 return res;
13417 } else {
13418
13419 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13420 ast_play_and_wait(chan, "vm-nobox");
13421 res = 't';
13422 ast_config_destroy(msg_cfg);
13423 return res;
13424 }
13425 }
13426 res = 0;
13427
13428 break;
13429 }
13430
13431 #ifndef IMAP_STORAGE
13432 ast_config_destroy(msg_cfg);
13433
13434 if (!res) {
13435 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13436 vms->heard[msg] = 1;
13437 res = wait_file(chan, vms, vms->fn);
13438 }
13439 #endif
13440 return res;
13441 }
13442
13443 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13444 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13445 signed char record_gain, struct vm_state *vms, char *flag)
13446 {
13447
13448 int res = 0;
13449 int cmd = 0;
13450 int max_attempts = 3;
13451 int attempts = 0;
13452 int recorded = 0;
13453 int msg_exists = 0;
13454 signed char zero_gain = 0;
13455 char tempfile[PATH_MAX];
13456 char *acceptdtmf = "#";
13457 char *canceldtmf = "";
13458 int canceleddtmf = 0;
13459
13460
13461
13462
13463 if (duration == NULL) {
13464 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13465 return -1;
13466 }
13467
13468 if (!outsidecaller)
13469 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13470 else
13471 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13472
13473 cmd = '3';
13474
13475 while ((cmd >= 0) && (cmd != 't')) {
13476 switch (cmd) {
13477 case '1':
13478 if (!msg_exists) {
13479
13480 cmd = '3';
13481 break;
13482 } else {
13483
13484 ast_verb(3, "Saving message as is\n");
13485 if (!outsidecaller)
13486 ast_filerename(tempfile, recordfile, NULL);
13487 ast_stream_and_wait(chan, "vm-msgsaved", "");
13488 if (!outsidecaller) {
13489
13490 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13491 DISPOSE(recordfile, -1);
13492 }
13493 cmd = 't';
13494 return res;
13495 }
13496 case '2':
13497
13498 ast_verb(3, "Reviewing the message\n");
13499 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13500 break;
13501 case '3':
13502 msg_exists = 0;
13503
13504 if (recorded == 1)
13505 ast_verb(3, "Re-recording the message\n");
13506 else
13507 ast_verb(3, "Recording the message\n");
13508
13509 if (recorded && outsidecaller) {
13510 cmd = ast_play_and_wait(chan, INTRO);
13511 cmd = ast_play_and_wait(chan, "beep");
13512 }
13513 recorded = 1;
13514
13515 if (record_gain)
13516 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13517 if (ast_test_flag(vmu, VM_OPERATOR))
13518 canceldtmf = "0";
13519 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13520 if (strchr(canceldtmf, cmd)) {
13521
13522 canceleddtmf = 1;
13523 }
13524 if (record_gain)
13525 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13526 if (cmd == -1) {
13527
13528 if (!outsidecaller) {
13529
13530 ast_filedelete(tempfile, NULL);
13531 }
13532 return cmd;
13533 }
13534 if (cmd == '0') {
13535 break;
13536 } else if (cmd == '*') {
13537 break;
13538 #if 0
13539 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13540
13541 ast_verb(3, "Message too short\n");
13542 cmd = ast_play_and_wait(chan, "vm-tooshort");
13543 cmd = ast_filedelete(tempfile, NULL);
13544 break;
13545 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13546
13547 ast_verb(3, "Nothing recorded\n");
13548 cmd = ast_filedelete(tempfile, NULL);
13549 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13550 if (!cmd)
13551 cmd = ast_play_and_wait(chan, "vm-speakup");
13552 break;
13553 #endif
13554 } else {
13555
13556 msg_exists = 1;
13557 cmd = 0;
13558 }
13559 break;
13560 case '4':
13561 if (outsidecaller) {
13562
13563 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13564 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13565 res = ast_play_and_wait(chan, "vm-marked-urgent");
13566 strcpy(flag, "Urgent");
13567 } else if (flag) {
13568 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13569 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13570 strcpy(flag, "");
13571 } else {
13572 ast_play_and_wait(chan, "vm-sorry");
13573 }
13574 cmd = 0;
13575 } else {
13576 cmd = ast_play_and_wait(chan, "vm-sorry");
13577 }
13578 break;
13579 case '5':
13580 case '6':
13581 case '7':
13582 case '8':
13583 case '9':
13584 case '*':
13585 case '#':
13586 cmd = ast_play_and_wait(chan, "vm-sorry");
13587 break;
13588 #if 0
13589
13590
13591 case '*':
13592
13593 cmd = ast_play_and_wait(chan, "vm-deleted");
13594 cmd = ast_filedelete(tempfile, NULL);
13595 if (outsidecaller) {
13596 res = vm_exec(chan, NULL);
13597 return res;
13598 }
13599 else
13600 return 1;
13601 #endif
13602 case '0':
13603 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13604 cmd = ast_play_and_wait(chan, "vm-sorry");
13605 break;
13606 }
13607 if (msg_exists || recorded) {
13608 cmd = ast_play_and_wait(chan, "vm-saveoper");
13609 if (!cmd)
13610 cmd = ast_waitfordigit(chan, 3000);
13611 if (cmd == '1') {
13612 ast_filerename(tempfile, recordfile, NULL);
13613 ast_play_and_wait(chan, "vm-msgsaved");
13614 cmd = '0';
13615 } else if (cmd == '4') {
13616 if (flag) {
13617 ast_play_and_wait(chan, "vm-marked-urgent");
13618 strcpy(flag, "Urgent");
13619 }
13620 ast_play_and_wait(chan, "vm-msgsaved");
13621 cmd = '0';
13622 } else {
13623 ast_play_and_wait(chan, "vm-deleted");
13624 DELETE(tempfile, -1, tempfile, vmu);
13625 cmd = '0';
13626 }
13627 }
13628 return cmd;
13629 default:
13630
13631
13632
13633 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13634 return cmd;
13635 if (msg_exists) {
13636 cmd = ast_play_and_wait(chan, "vm-review");
13637 if (!cmd && outsidecaller) {
13638 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13639 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13640 } else if (flag) {
13641 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13642 }
13643 }
13644 } else {
13645 cmd = ast_play_and_wait(chan, "vm-torerecord");
13646 if (!cmd)
13647 cmd = ast_waitfordigit(chan, 600);
13648 }
13649
13650 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13651 cmd = ast_play_and_wait(chan, "vm-reachoper");
13652 if (!cmd)
13653 cmd = ast_waitfordigit(chan, 600);
13654 }
13655 #if 0
13656 if (!cmd)
13657 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13658 #endif
13659 if (!cmd)
13660 cmd = ast_waitfordigit(chan, 6000);
13661 if (!cmd) {
13662 attempts++;
13663 }
13664 if (attempts > max_attempts) {
13665 cmd = 't';
13666 }
13667 }
13668 }
13669 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13670
13671 ast_filedelete(tempfile, NULL);
13672 }
13673
13674 if (cmd != 't' && outsidecaller)
13675 ast_play_and_wait(chan, "vm-goodbye");
13676
13677 return cmd;
13678 }
13679
13680
13681
13682
13683
13684 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13685 .load = load_module,
13686 .unload = unload_module,
13687 .reload = reload,
13688 .nonoptreq = "res_adsi,res_smdi",
13689 );