00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 #include "asterisk.h"
00066
00067 #ifdef IMAP_STORAGE
00068 #include <ctype.h>
00069 #include <signal.h>
00070 #include <pwd.h>
00071 #ifdef USE_SYSTEM_IMAP
00072 #include <imap/c-client.h>
00073 #include <imap/imap4r1.h>
00074 #include <imap/linkage.h>
00075 #elif defined (USE_SYSTEM_CCLIENT)
00076 #include <c-client/c-client.h>
00077 #include <c-client/imap4r1.h>
00078 #include <c-client/linkage.h>
00079 #else
00080 #include "c-client.h"
00081 #include "imap4r1.h"
00082 #include "linkage.h"
00083 #endif
00084 #endif
00085
00086 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426691 $")
00087
00088 #include "asterisk/paths.h"
00089 #include <sys/time.h>
00090 #include <sys/stat.h>
00091 #include <sys/mman.h>
00092 #include <time.h>
00093 #include <dirent.h>
00094 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00095 #include <sys/wait.h>
00096 #endif
00097
00098 #include "asterisk/logger.h"
00099 #include "asterisk/lock.h"
00100 #include "asterisk/file.h"
00101 #include "asterisk/channel.h"
00102 #include "asterisk/pbx.h"
00103 #include "asterisk/config.h"
00104 #include "asterisk/say.h"
00105 #include "asterisk/module.h"
00106 #include "asterisk/adsi.h"
00107 #include "asterisk/app.h"
00108 #include "asterisk/manager.h"
00109 #include "asterisk/dsp.h"
00110 #include "asterisk/localtime.h"
00111 #include "asterisk/cli.h"
00112 #include "asterisk/utils.h"
00113 #include "asterisk/stringfields.h"
00114 #include "asterisk/smdi.h"
00115 #include "asterisk/astobj2.h"
00116 #include "asterisk/event.h"
00117 #include "asterisk/taskprocessor.h"
00118 #include "asterisk/test.h"
00119
00120 #ifdef ODBC_STORAGE
00121 #include "asterisk/res_odbc.h"
00122 #endif
00123
00124 #ifdef IMAP_STORAGE
00125 #include "asterisk/threadstorage.h"
00126 #endif
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366 #ifdef IMAP_STORAGE
00367 static char imapserver[48];
00368 static char imapport[8];
00369 static char imapflags[128];
00370 static char imapfolder[64];
00371 static char imapparentfolder[64] = "\0";
00372 static char greetingfolder[64];
00373 static char authuser[32];
00374 static char authpassword[42];
00375 static int imapversion = 1;
00376
00377 static int expungeonhangup = 1;
00378 static int imapgreetings = 0;
00379 static char delimiter = '\0';
00380
00381 struct vm_state;
00382 struct ast_vm_user;
00383
00384 AST_THREADSTORAGE(ts_vmstate);
00385
00386
00387 static int init_mailstream(struct vm_state *vms, int box);
00388 static void write_file(char *filename, char *buffer, unsigned long len);
00389 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00390 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00391 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00392 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00393 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00394 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00395 static void vmstate_insert(struct vm_state *vms);
00396 static void vmstate_delete(struct vm_state *vms);
00397 static void set_update(MAILSTREAM * stream);
00398 static void init_vm_state(struct vm_state *vms);
00399 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00400 static void get_mailbox_delimiter(MAILSTREAM *stream);
00401 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00402 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00403 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00404 static void update_messages_by_imapuser(const char *user, unsigned long number);
00405 static int vm_delete(char *file);
00406
00407 static int imap_remove_file (char *dir, int msgnum);
00408 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00409 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00410 static void check_quota(struct vm_state *vms, char *mailbox);
00411 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00412 struct vmstate {
00413 struct vm_state *vms;
00414 AST_LIST_ENTRY(vmstate) list;
00415 };
00416
00417 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00418
00419 #endif
00420
00421 #define SMDI_MWI_WAIT_TIMEOUT 1000
00422
00423 #define COMMAND_TIMEOUT 5000
00424
00425 #define VOICEMAIL_DIR_MODE 0777
00426 #define VOICEMAIL_FILE_MODE 0666
00427 #define CHUNKSIZE 65536
00428
00429 #define VOICEMAIL_CONFIG "voicemail.conf"
00430 #define ASTERISK_USERNAME "asterisk"
00431
00432
00433
00434
00435 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00436 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00437 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00438 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00439 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00440 #define VALID_DTMF "1234567890*#"
00441
00442
00443
00444 #define SENDMAIL "/usr/sbin/sendmail -t"
00445
00446 #define INTRO "vm-intro"
00447
00448 #define MAXMSG 100
00449 #define MAXMSGLIMIT 9999
00450
00451 #define MINPASSWORD 0
00452
00453 #define BASELINELEN 72
00454 #define BASEMAXINLINE 256
00455 #ifdef IMAP_STORAGE
00456 #define ENDL "\r\n"
00457 #else
00458 #define ENDL "\n"
00459 #endif
00460
00461 #define MAX_DATETIME_FORMAT 512
00462 #define MAX_NUM_CID_CONTEXTS 10
00463
00464 #define VM_REVIEW (1 << 0)
00465 #define VM_OPERATOR (1 << 1)
00466 #define VM_SAYCID (1 << 2)
00467 #define VM_SVMAIL (1 << 3)
00468 #define VM_ENVELOPE (1 << 4)
00469 #define VM_SAYDURATION (1 << 5)
00470 #define VM_SKIPAFTERCMD (1 << 6)
00471 #define VM_FORCENAME (1 << 7)
00472 #define VM_FORCEGREET (1 << 8)
00473 #define VM_PBXSKIP (1 << 9)
00474 #define VM_DIRECFORWARD (1 << 10)
00475 #define VM_ATTACH (1 << 11)
00476 #define VM_DELETE (1 << 12)
00477 #define VM_ALLOCED (1 << 13)
00478 #define VM_SEARCH (1 << 14)
00479 #define VM_TEMPGREETWARN (1 << 15)
00480 #define VM_MOVEHEARD (1 << 16)
00481 #define VM_MESSAGEWRAP (1 << 17)
00482 #define VM_FWDURGAUTO (1 << 18)
00483 #define ERROR_LOCK_PATH -100
00484 #define OPERATOR_EXIT 300
00485
00486
00487 enum vm_box {
00488 NEW_FOLDER,
00489 OLD_FOLDER,
00490 WORK_FOLDER,
00491 FAMILY_FOLDER,
00492 FRIENDS_FOLDER,
00493 GREETINGS_FOLDER
00494 };
00495
00496 enum vm_option_flags {
00497 OPT_SILENT = (1 << 0),
00498 OPT_BUSY_GREETING = (1 << 1),
00499 OPT_UNAVAIL_GREETING = (1 << 2),
00500 OPT_RECORDGAIN = (1 << 3),
00501 OPT_PREPEND_MAILBOX = (1 << 4),
00502 OPT_AUTOPLAY = (1 << 6),
00503 OPT_DTMFEXIT = (1 << 7),
00504 OPT_MESSAGE_Urgent = (1 << 8),
00505 OPT_MESSAGE_PRIORITY = (1 << 9)
00506 };
00507
00508 enum vm_option_args {
00509 OPT_ARG_RECORDGAIN = 0,
00510 OPT_ARG_PLAYFOLDER = 1,
00511 OPT_ARG_DTMFEXIT = 2,
00512
00513 OPT_ARG_ARRAY_SIZE = 3,
00514 };
00515
00516 enum vm_passwordlocation {
00517 OPT_PWLOC_VOICEMAILCONF = 0,
00518 OPT_PWLOC_SPOOLDIR = 1,
00519 OPT_PWLOC_USERSCONF = 2,
00520 };
00521
00522 AST_APP_OPTIONS(vm_app_options, {
00523 AST_APP_OPTION('s', OPT_SILENT),
00524 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00525 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00526 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00527 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00528 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00529 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00530 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00531 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00532 });
00533
00534 static int load_config(int reload);
00535 #ifdef TEST_FRAMEWORK
00536 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00537 #endif
00538 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 struct baseio {
00624 int iocp;
00625 int iolen;
00626 int linelength;
00627 int ateof;
00628 unsigned char iobuf[BASEMAXINLINE];
00629 };
00630
00631
00632
00633 struct ast_vm_user {
00634 char context[AST_MAX_CONTEXT];
00635 char mailbox[AST_MAX_EXTENSION];
00636 char password[80];
00637 char fullname[80];
00638 char email[80];
00639 char *emailsubject;
00640 char *emailbody;
00641 char pager[80];
00642 char serveremail[80];
00643 char language[MAX_LANGUAGE];
00644 char zonetag[80];
00645 char locale[20];
00646 char callback[80];
00647 char dialout[80];
00648 char uniqueid[80];
00649 char exit[80];
00650 char attachfmt[20];
00651 unsigned int flags;
00652 int saydurationm;
00653 int minsecs;
00654 int maxmsg;
00655 int maxdeletedmsg;
00656 int maxsecs;
00657 int passwordlocation;
00658 #ifdef IMAP_STORAGE
00659 char imapuser[80];
00660 char imappassword[80];
00661 char imapfolder[64];
00662 char imapvmshareid[80];
00663 int imapversion;
00664 #endif
00665 double volgain;
00666 AST_LIST_ENTRY(ast_vm_user) list;
00667 };
00668
00669
00670 struct vm_zone {
00671 AST_LIST_ENTRY(vm_zone) list;
00672 char name[80];
00673 char timezone[80];
00674 char msg_format[512];
00675 };
00676
00677 #define VMSTATE_MAX_MSG_ARRAY 256
00678
00679
00680 struct vm_state {
00681 char curbox[80];
00682 char username[80];
00683 char context[80];
00684 char curdir[PATH_MAX];
00685 char vmbox[PATH_MAX];
00686 char fn[PATH_MAX];
00687 char intro[PATH_MAX];
00688 int *deleted;
00689 int *heard;
00690 int dh_arraysize;
00691 int curmsg;
00692 int lastmsg;
00693 int newmessages;
00694 int oldmessages;
00695 int urgentmessages;
00696 int starting;
00697 int repeats;
00698 #ifdef IMAP_STORAGE
00699 ast_mutex_t lock;
00700 int updated;
00701 long *msgArray;
00702 unsigned msg_array_max;
00703 MAILSTREAM *mailstream;
00704 int vmArrayIndex;
00705 char imapuser[80];
00706 char imapfolder[64];
00707 int imapversion;
00708 int interactive;
00709 char introfn[PATH_MAX];
00710 unsigned int quota_limit;
00711 unsigned int quota_usage;
00712 struct vm_state *persist_vms;
00713 #endif
00714 };
00715
00716 #ifdef ODBC_STORAGE
00717 static char odbc_database[80];
00718 static char odbc_table[80];
00719 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00720 #define DISPOSE(a,b) remove_file(a,b)
00721 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00722 #define EXISTS(a,b,c,d) (message_exists(a,b))
00723 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00724 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00725 #define DELETE(a,b,c,d) (delete_file(a,b))
00726 #else
00727 #ifdef IMAP_STORAGE
00728 #define DISPOSE(a,b) (imap_remove_file(a,b))
00729 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00730 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00731 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00732 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00733 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00734 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00735 #else
00736 #define RETRIEVE(a,b,c,d)
00737 #define DISPOSE(a,b)
00738 #define STORE(a,b,c,d,e,f,g,h,i,j)
00739 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00740 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00741 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00742 #define DELETE(a,b,c,d) (vm_delete(c))
00743 #endif
00744 #endif
00745
00746 static char VM_SPOOL_DIR[PATH_MAX];
00747
00748 static char ext_pass_cmd[128];
00749 static char ext_pass_check_cmd[128];
00750
00751 static int my_umask;
00752
00753 #define PWDCHANGE_INTERNAL (1 << 1)
00754 #define PWDCHANGE_EXTERNAL (1 << 2)
00755 static int pwdchange = PWDCHANGE_INTERNAL;
00756
00757 #ifdef ODBC_STORAGE
00758 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00759 #else
00760 # ifdef IMAP_STORAGE
00761 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00762 # else
00763 # define tdesc "Comedian Mail (Voicemail System)"
00764 # endif
00765 #endif
00766
00767 static char userscontext[AST_MAX_EXTENSION] = "default";
00768
00769 static char *addesc = "Comedian Mail";
00770
00771
00772 static char *app = "VoiceMail";
00773
00774
00775 static char *app2 = "VoiceMailMain";
00776
00777 static char *app3 = "MailboxExists";
00778 static char *app4 = "VMAuthenticate";
00779
00780 static char *sayname_app = "VMSayName";
00781
00782 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00783 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00784 static char zonetag[80];
00785 static char locale[20];
00786 static int maxsilence;
00787 static int maxmsg;
00788 static int maxdeletedmsg;
00789 static int silencethreshold = 128;
00790 static char serveremail[80];
00791 static char mailcmd[160];
00792 static char externnotify[160];
00793 static struct ast_smdi_interface *smdi_iface = NULL;
00794 static char vmfmts[80];
00795 static double volgain;
00796 static int vmminsecs;
00797 static int vmmaxsecs;
00798 static int maxgreet;
00799 static int skipms;
00800 static int maxlogins;
00801 static int minpassword;
00802 static int passwordlocation;
00803
00804
00805
00806 static unsigned int poll_mailboxes;
00807
00808
00809 static unsigned int poll_freq;
00810
00811 #define DEFAULT_POLL_FREQ 30
00812
00813 AST_MUTEX_DEFINE_STATIC(poll_lock);
00814 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00815 static pthread_t poll_thread = AST_PTHREADT_NULL;
00816 static unsigned char poll_thread_run;
00817
00818
00819 static struct ast_event_sub *mwi_sub_sub;
00820
00821 static struct ast_event_sub *mwi_unsub_sub;
00822
00823
00824
00825
00826
00827
00828
00829
00830 struct mwi_sub {
00831 AST_RWLIST_ENTRY(mwi_sub) entry;
00832 int old_urgent;
00833 int old_new;
00834 int old_old;
00835 uint32_t uniqueid;
00836 char mailbox[1];
00837 };
00838
00839 struct mwi_sub_task {
00840 const char *mailbox;
00841 const char *context;
00842 uint32_t uniqueid;
00843 };
00844
00845 static struct ast_taskprocessor *mwi_subscription_tps;
00846
00847 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00848
00849
00850 static char listen_control_forward_key[12];
00851 static char listen_control_reverse_key[12];
00852 static char listen_control_pause_key[12];
00853 static char listen_control_restart_key[12];
00854 static char listen_control_stop_key[12];
00855
00856
00857 static char vm_password[80] = "vm-password";
00858 static char vm_newpassword[80] = "vm-newpassword";
00859 static char vm_passchanged[80] = "vm-passchanged";
00860 static char vm_reenterpassword[80] = "vm-reenterpassword";
00861 static char vm_mismatch[80] = "vm-mismatch";
00862 static char vm_invalid_password[80] = "vm-invalid-password";
00863 static char vm_pls_try_again[80] = "vm-pls-try-again";
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875 static char vm_prepend_timeout[80] = "vm-then-pound";
00876
00877 static struct ast_flags globalflags = {0};
00878
00879 static int saydurationminfo;
00880
00881 static char dialcontext[AST_MAX_CONTEXT] = "";
00882 static char callcontext[AST_MAX_CONTEXT] = "";
00883 static char exitcontext[AST_MAX_CONTEXT] = "";
00884
00885 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00886
00887
00888 static char *emailbody = NULL;
00889 static char *emailsubject = NULL;
00890 static char *pagerbody = NULL;
00891 static char *pagersubject = NULL;
00892 static char fromstring[100];
00893 static char pagerfromstring[100];
00894 static char charset[32] = "ISO-8859-1";
00895
00896 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00897 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00898 static int adsiver = 1;
00899 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00900 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00901
00902
00903 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00904 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
00905 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00906 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00907 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00908 signed char record_gain, struct vm_state *vms, char *flag);
00909 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00910 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00911 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
00912 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
00913 static void apply_options(struct ast_vm_user *vmu, const char *options);
00914 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
00915 static int is_valid_dtmf(const char *key);
00916 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00917 static int write_password_to_file(const char *secretfn, const char *password);
00918 static const char *substitute_escapes(const char *value);
00919 static void free_user(struct ast_vm_user *vmu);
00920
00921 struct ao2_container *inprocess_container;
00922
00923 struct inprocess {
00924 int count;
00925 char *context;
00926 char mailbox[0];
00927 };
00928
00929 static int inprocess_hash_fn(const void *obj, const int flags)
00930 {
00931 const struct inprocess *i = obj;
00932 return atoi(i->mailbox);
00933 }
00934
00935 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00936 {
00937 struct inprocess *i = obj, *j = arg;
00938 if (strcmp(i->mailbox, j->mailbox)) {
00939 return 0;
00940 }
00941 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00942 }
00943
00944 static int inprocess_count(const char *context, const char *mailbox, int delta)
00945 {
00946 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00947 arg->context = arg->mailbox + strlen(mailbox) + 1;
00948 strcpy(arg->mailbox, mailbox);
00949 strcpy(arg->context, context);
00950 ao2_lock(inprocess_container);
00951 if ((i = ao2_find(inprocess_container, arg, 0))) {
00952 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00953 ao2_unlock(inprocess_container);
00954 ao2_ref(i, -1);
00955 return ret;
00956 }
00957 if (delta < 0) {
00958 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00959 }
00960 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00961 ao2_unlock(inprocess_container);
00962 return 0;
00963 }
00964 i->context = i->mailbox + strlen(mailbox) + 1;
00965 strcpy(i->mailbox, mailbox);
00966 strcpy(i->context, context);
00967 i->count = delta;
00968 ao2_link(inprocess_container, i);
00969 ao2_unlock(inprocess_container);
00970 ao2_ref(i, -1);
00971 return 0;
00972 }
00973
00974 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00975 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00976 #endif
00977
00978
00979
00980
00981
00982
00983
00984 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00985 {
00986 char *bufptr = buf;
00987 for (; *input; input++) {
00988 if (*input < 32) {
00989 continue;
00990 }
00991 *bufptr++ = *input;
00992 if (bufptr == buf + buflen - 1) {
00993 break;
00994 }
00995 }
00996 *bufptr = '\0';
00997 return buf;
00998 }
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 static void populate_defaults(struct ast_vm_user *vmu)
01015 {
01016 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01017 vmu->passwordlocation = passwordlocation;
01018 if (saydurationminfo) {
01019 vmu->saydurationm = saydurationminfo;
01020 }
01021 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01022 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01023 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01024 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01025 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01026 if (vmminsecs) {
01027 vmu->minsecs = vmminsecs;
01028 }
01029 if (vmmaxsecs) {
01030 vmu->maxsecs = vmmaxsecs;
01031 }
01032 if (maxmsg) {
01033 vmu->maxmsg = maxmsg;
01034 }
01035 if (maxdeletedmsg) {
01036 vmu->maxdeletedmsg = maxdeletedmsg;
01037 }
01038 vmu->volgain = volgain;
01039 ast_free(vmu->emailsubject);
01040 vmu->emailsubject = NULL;
01041 ast_free(vmu->emailbody);
01042 vmu->emailbody = NULL;
01043 #ifdef IMAP_STORAGE
01044 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01045 #endif
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01057 {
01058 int x;
01059 if (!strcasecmp(var, "attach")) {
01060 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01061 } else if (!strcasecmp(var, "attachfmt")) {
01062 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01063 } else if (!strcasecmp(var, "serveremail")) {
01064 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01065 } else if (!strcasecmp(var, "emailbody")) {
01066 vmu->emailbody = ast_strdup(substitute_escapes(value));
01067 } else if (!strcasecmp(var, "emailsubject")) {
01068 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01069 } else if (!strcasecmp(var, "language")) {
01070 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01071 } else if (!strcasecmp(var, "tz")) {
01072 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01073 } else if (!strcasecmp(var, "locale")) {
01074 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01075 #ifdef IMAP_STORAGE
01076 } else if (!strcasecmp(var, "imapuser")) {
01077 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01078 vmu->imapversion = imapversion;
01079 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01080 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01081 vmu->imapversion = imapversion;
01082 } else if (!strcasecmp(var, "imapfolder")) {
01083 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01084 } else if (!strcasecmp(var, "imapvmshareid")) {
01085 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01086 vmu->imapversion = imapversion;
01087 #endif
01088 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01089 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01090 } else if (!strcasecmp(var, "saycid")){
01091 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01092 } else if (!strcasecmp(var, "sendvoicemail")){
01093 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01094 } else if (!strcasecmp(var, "review")){
01095 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01096 } else if (!strcasecmp(var, "tempgreetwarn")){
01097 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01098 } else if (!strcasecmp(var, "messagewrap")){
01099 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01100 } else if (!strcasecmp(var, "operator")) {
01101 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01102 } else if (!strcasecmp(var, "envelope")){
01103 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01104 } else if (!strcasecmp(var, "moveheard")){
01105 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01106 } else if (!strcasecmp(var, "sayduration")){
01107 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01108 } else if (!strcasecmp(var, "saydurationm")){
01109 if (sscanf(value, "%30d", &x) == 1) {
01110 vmu->saydurationm = x;
01111 } else {
01112 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01113 }
01114 } else if (!strcasecmp(var, "forcename")){
01115 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01116 } else if (!strcasecmp(var, "forcegreetings")){
01117 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01118 } else if (!strcasecmp(var, "callback")) {
01119 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01120 } else if (!strcasecmp(var, "dialout")) {
01121 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01122 } else if (!strcasecmp(var, "exitcontext")) {
01123 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01124 } else if (!strcasecmp(var, "minsecs")) {
01125 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01126 vmu->minsecs = x;
01127 } else {
01128 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01129 vmu->minsecs = vmminsecs;
01130 }
01131 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01132 vmu->maxsecs = atoi(value);
01133 if (vmu->maxsecs <= 0) {
01134 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01135 vmu->maxsecs = vmmaxsecs;
01136 } else {
01137 vmu->maxsecs = atoi(value);
01138 }
01139 if (!strcasecmp(var, "maxmessage"))
01140 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01141 } else if (!strcasecmp(var, "maxmsg")) {
01142 vmu->maxmsg = atoi(value);
01143
01144 if (vmu->maxmsg < 0) {
01145 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01146 vmu->maxmsg = MAXMSG;
01147 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01148 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01149 vmu->maxmsg = MAXMSGLIMIT;
01150 }
01151 } else if (!strcasecmp(var, "nextaftercmd")) {
01152 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01153 } else if (!strcasecmp(var, "backupdeleted")) {
01154 if (sscanf(value, "%30d", &x) == 1)
01155 vmu->maxdeletedmsg = x;
01156 else if (ast_true(value))
01157 vmu->maxdeletedmsg = MAXMSG;
01158 else
01159 vmu->maxdeletedmsg = 0;
01160
01161 if (vmu->maxdeletedmsg < 0) {
01162 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01163 vmu->maxdeletedmsg = MAXMSG;
01164 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01165 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01166 vmu->maxdeletedmsg = MAXMSGLIMIT;
01167 }
01168 } else if (!strcasecmp(var, "volgain")) {
01169 sscanf(value, "%30lf", &vmu->volgain);
01170 } else if (!strcasecmp(var, "passwordlocation")) {
01171 if (!strcasecmp(value, "spooldir")) {
01172 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01173 } else {
01174 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01175 }
01176 } else if (!strcasecmp(var, "options")) {
01177 apply_options(vmu, value);
01178 }
01179 }
01180
01181 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01182 {
01183 int fds[2], pid = 0;
01184
01185 memset(buf, 0, len);
01186
01187 if (pipe(fds)) {
01188 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01189 } else {
01190
01191 pid = ast_safe_fork(0);
01192
01193 if (pid < 0) {
01194
01195 close(fds[0]);
01196 close(fds[1]);
01197 snprintf(buf, len, "FAILURE: Fork failed");
01198 } else if (pid) {
01199
01200 close(fds[1]);
01201 if (read(fds[0], buf, len) < 0) {
01202 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01203 }
01204 close(fds[0]);
01205 } else {
01206
01207 AST_DECLARE_APP_ARGS(arg,
01208 AST_APP_ARG(v)[20];
01209 );
01210 char *mycmd = ast_strdupa(command);
01211
01212 close(fds[0]);
01213 dup2(fds[1], STDOUT_FILENO);
01214 close(fds[1]);
01215 ast_close_fds_above_n(STDOUT_FILENO);
01216
01217 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01218
01219 execv(arg.v[0], arg.v);
01220 printf("FAILURE: %s", strerror(errno));
01221 _exit(0);
01222 }
01223 }
01224 return buf;
01225 }
01226
01227
01228
01229
01230
01231
01232
01233
01234 static int check_password(struct ast_vm_user *vmu, char *password)
01235 {
01236
01237 if (strlen(password) < minpassword)
01238 return 1;
01239
01240 if (!ast_strlen_zero(password) && password[0] == '*')
01241 return 1;
01242 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01243 char cmd[255], buf[255];
01244
01245 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01246
01247 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01248 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01249 ast_debug(5, "Result: %s\n", buf);
01250 if (!strncasecmp(buf, "VALID", 5)) {
01251 ast_debug(3, "Passed password check: '%s'\n", buf);
01252 return 0;
01253 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01254 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01255 return 0;
01256 } else {
01257 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01258 return 1;
01259 }
01260 }
01261 }
01262 return 0;
01263 }
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01276 {
01277 int res = -1;
01278 if (!strcmp(vmu->password, password)) {
01279
01280 return 0;
01281 }
01282
01283 if (strlen(password) > 10) {
01284 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01285 }
01286 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01287 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01288 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01289 res = 0;
01290 }
01291 return res;
01292 }
01293
01294
01295
01296
01297 static void apply_options(struct ast_vm_user *vmu, const char *options)
01298 {
01299 char *stringp;
01300 char *s;
01301 char *var, *value;
01302 stringp = ast_strdupa(options);
01303 while ((s = strsep(&stringp, "|"))) {
01304 value = s;
01305 if ((var = strsep(&value, "=")) && value) {
01306 apply_option(vmu, var, value);
01307 }
01308 }
01309 }
01310
01311
01312
01313
01314
01315
01316 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01317 {
01318 for (; var; var = var->next) {
01319 if (!strcasecmp(var->name, "vmsecret")) {
01320 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01321 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01322 if (ast_strlen_zero(retval->password)) {
01323 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01324 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01325 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01326 } else {
01327 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01328 }
01329 }
01330 } else if (!strcasecmp(var->name, "uniqueid")) {
01331 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01332 } else if (!strcasecmp(var->name, "pager")) {
01333 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01334 } else if (!strcasecmp(var->name, "email")) {
01335 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01336 } else if (!strcasecmp(var->name, "fullname")) {
01337 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01338 } else if (!strcasecmp(var->name, "context")) {
01339 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01340 } else if (!strcasecmp(var->name, "emailsubject")) {
01341 ast_free(retval->emailsubject);
01342 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01343 } else if (!strcasecmp(var->name, "emailbody")) {
01344 ast_free(retval->emailbody);
01345 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01346 #ifdef IMAP_STORAGE
01347 } else if (!strcasecmp(var->name, "imapuser")) {
01348 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01349 retval->imapversion = imapversion;
01350 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01351 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01352 retval->imapversion = imapversion;
01353 } else if (!strcasecmp(var->name, "imapfolder")) {
01354 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01355 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01356 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01357 retval->imapversion = imapversion;
01358 #endif
01359 } else
01360 apply_option(retval, var->name, var->value);
01361 }
01362 }
01363
01364
01365
01366
01367
01368
01369
01370
01371 static int is_valid_dtmf(const char *key)
01372 {
01373 int i;
01374 char *local_key = ast_strdupa(key);
01375
01376 for (i = 0; i < strlen(key); ++i) {
01377 if (!strchr(VALID_DTMF, *local_key)) {
01378 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01379 return 0;
01380 }
01381 local_key++;
01382 }
01383 return 1;
01384 }
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01397 {
01398 struct ast_variable *var;
01399 struct ast_vm_user *retval;
01400
01401 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01402 if (ivm) {
01403 memset(retval, 0, sizeof(*retval));
01404 }
01405 populate_defaults(retval);
01406 if (!ivm) {
01407 ast_set_flag(retval, VM_ALLOCED);
01408 }
01409 if (mailbox) {
01410 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01411 }
01412 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01413 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01414 } else {
01415 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01416 }
01417 if (var) {
01418 apply_options_full(retval, var);
01419 ast_variables_destroy(var);
01420 } else {
01421 if (!ivm)
01422 free_user(retval);
01423 retval = NULL;
01424 }
01425 }
01426 return retval;
01427 }
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01438 {
01439
01440 struct ast_vm_user *vmu = NULL, *cur;
01441 AST_LIST_LOCK(&users);
01442
01443 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01444 context = "default";
01445
01446 AST_LIST_TRAVERSE(&users, cur, list) {
01447 #ifdef IMAP_STORAGE
01448 if (cur->imapversion != imapversion) {
01449 continue;
01450 }
01451 #endif
01452 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01453 break;
01454 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01455 break;
01456 }
01457 if (cur) {
01458
01459 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01460 *vmu = *cur;
01461 if (!ivm) {
01462 vmu->emailbody = ast_strdup(cur->emailbody);
01463 vmu->emailsubject = ast_strdup(cur->emailsubject);
01464 }
01465 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01466 AST_LIST_NEXT(vmu, list) = NULL;
01467 }
01468 } else
01469 vmu = find_user_realtime(ivm, context, mailbox);
01470 AST_LIST_UNLOCK(&users);
01471 return vmu;
01472 }
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01485 {
01486
01487 struct ast_vm_user *cur;
01488 int res = -1;
01489 AST_LIST_LOCK(&users);
01490 AST_LIST_TRAVERSE(&users, cur, list) {
01491 if ((!context || !strcasecmp(context, cur->context)) &&
01492 (!strcasecmp(mailbox, cur->mailbox)))
01493 break;
01494 }
01495 if (cur) {
01496 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01497 res = 0;
01498 }
01499 AST_LIST_UNLOCK(&users);
01500 return res;
01501 }
01502
01503
01504
01505
01506 static inline int valid_config(const struct ast_config *cfg)
01507 {
01508 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01509 }
01510
01511
01512
01513
01514
01515
01516
01517
01518 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01519 {
01520 struct ast_config *cfg = NULL;
01521 struct ast_variable *var = NULL;
01522 struct ast_category *cat = NULL;
01523 char *category = NULL, *value = NULL, *new = NULL;
01524 const char *tmp = NULL;
01525 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01526 char secretfn[PATH_MAX] = "";
01527 int found = 0;
01528
01529 if (!change_password_realtime(vmu, newpassword))
01530 return;
01531
01532
01533 switch (vmu->passwordlocation) {
01534 case OPT_PWLOC_SPOOLDIR:
01535 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01536 if (write_password_to_file(secretfn, newpassword) == 0) {
01537 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01538 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01539 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01540 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01541 break;
01542 } else {
01543 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01544 }
01545
01546 case OPT_PWLOC_VOICEMAILCONF:
01547 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01548 while ((category = ast_category_browse(cfg, category))) {
01549 if (!strcasecmp(category, vmu->context)) {
01550 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01551 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01552 break;
01553 }
01554 value = strstr(tmp, ",");
01555 if (!value) {
01556 new = ast_alloca(strlen(newpassword)+1);
01557 sprintf(new, "%s", newpassword);
01558 } else {
01559 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01560 sprintf(new, "%s%s", newpassword, value);
01561 }
01562 if (!(cat = ast_category_get(cfg, category))) {
01563 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01564 break;
01565 }
01566 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01567 found = 1;
01568 }
01569 }
01570
01571 if (found) {
01572 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01573 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01574 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01575 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01576 ast_config_destroy(cfg);
01577 break;
01578 }
01579
01580 ast_config_destroy(cfg);
01581 }
01582
01583 case OPT_PWLOC_USERSCONF:
01584
01585
01586 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01587 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01588 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01589 ast_debug(4, "users.conf: %s\n", category);
01590 if (!strcasecmp(category, vmu->mailbox)) {
01591 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01592 ast_debug(3, "looks like we need to make vmsecret!\n");
01593 var = ast_variable_new("vmsecret", newpassword, "");
01594 } else {
01595 var = NULL;
01596 }
01597 new = ast_alloca(strlen(newpassword) + 1);
01598 sprintf(new, "%s", newpassword);
01599 if (!(cat = ast_category_get(cfg, category))) {
01600 ast_debug(4, "failed to get category!\n");
01601 ast_free(var);
01602 break;
01603 }
01604 if (!var) {
01605 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01606 } else {
01607 ast_variable_append(cat, var);
01608 }
01609 found = 1;
01610 break;
01611 }
01612 }
01613
01614 if (found) {
01615 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01616 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01617 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01618 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01619 }
01620
01621 ast_config_destroy(cfg);
01622 }
01623 }
01624 }
01625
01626 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01627 {
01628 char buf[255];
01629 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01630 ast_debug(1, "External password: %s\n",buf);
01631 if (!ast_safe_system(buf)) {
01632 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01633 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01634
01635 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01636 }
01637 }
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01653 {
01654 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669 static int make_file(char *dest, const int len, const char *dir, const int num)
01670 {
01671 return snprintf(dest, len, "%s/msg%04d", dir, num);
01672 }
01673
01674
01675 static FILE *vm_mkftemp(char *template)
01676 {
01677 FILE *p = NULL;
01678 int pfd = mkstemp(template);
01679 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01680 if (pfd > -1) {
01681 p = fdopen(pfd, "w+");
01682 if (!p) {
01683 close(pfd);
01684 pfd = -1;
01685 }
01686 }
01687 return p;
01688 }
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01699 {
01700 mode_t mode = VOICEMAIL_DIR_MODE;
01701 int res;
01702
01703 make_dir(dest, len, context, ext, folder);
01704 if ((res = ast_mkdir(dest, mode))) {
01705 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01706 return -1;
01707 }
01708 return 0;
01709 }
01710
01711 static const char * const mailbox_folders[] = {
01712 #ifdef IMAP_STORAGE
01713 imapfolder,
01714 #else
01715 "INBOX",
01716 #endif
01717 "Old",
01718 "Work",
01719 "Family",
01720 "Friends",
01721 "Cust1",
01722 "Cust2",
01723 "Cust3",
01724 "Cust4",
01725 "Cust5",
01726 "Deleted",
01727 "Urgent",
01728 };
01729
01730 static const char *mbox(struct ast_vm_user *vmu, int id)
01731 {
01732 #ifdef IMAP_STORAGE
01733 if (vmu && id == 0) {
01734 return vmu->imapfolder;
01735 }
01736 #endif
01737 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01738 }
01739
01740 static int get_folder_by_name(const char *name)
01741 {
01742 size_t i;
01743
01744 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01745 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01746 return i;
01747 }
01748 }
01749
01750 return -1;
01751 }
01752
01753 static void free_user(struct ast_vm_user *vmu)
01754 {
01755 if (ast_test_flag(vmu, VM_ALLOCED)) {
01756
01757 ast_free(vmu->emailbody);
01758 vmu->emailbody = NULL;
01759
01760 ast_free(vmu->emailsubject);
01761 vmu->emailsubject = NULL;
01762
01763 ast_free(vmu);
01764 }
01765 }
01766
01767 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01768
01769 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01770
01771
01772 if (vms->deleted) {
01773 ast_free(vms->deleted);
01774 vms->deleted = NULL;
01775 }
01776 if (vms->heard) {
01777 ast_free(vms->heard);
01778 vms->heard = NULL;
01779 }
01780 vms->dh_arraysize = 0;
01781
01782 if (arraysize > 0) {
01783 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01784 return -1;
01785 }
01786 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01787 ast_free(vms->deleted);
01788 vms->deleted = NULL;
01789 return -1;
01790 }
01791 vms->dh_arraysize = arraysize;
01792 }
01793
01794 return 0;
01795 }
01796
01797
01798
01799 #ifdef IMAP_STORAGE
01800 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01801 {
01802 char arg[10];
01803 struct vm_state *vms;
01804 unsigned long messageNum;
01805
01806
01807 if (msgnum < 0 && !imapgreetings) {
01808 ast_filedelete(file, NULL);
01809 return;
01810 }
01811
01812 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01813 ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
01814 return;
01815 }
01816
01817 if (msgnum < 0) {
01818 imap_delete_old_greeting(file, vms);
01819 return;
01820 }
01821
01822
01823
01824 messageNum = vms->msgArray[msgnum];
01825 if (messageNum == 0) {
01826 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01827 return;
01828 }
01829 if (option_debug > 2)
01830 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01831
01832 snprintf (arg, sizeof(arg), "%lu", messageNum);
01833 ast_mutex_lock(&vms->lock);
01834 mail_setflag (vms->mailstream, arg, "\\DELETED");
01835 mail_expunge(vms->mailstream);
01836 ast_mutex_unlock(&vms->lock);
01837 }
01838
01839 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01840 {
01841 struct vm_state *vms_p;
01842 char *file, *filename;
01843 char *attachment;
01844 int i;
01845 BODY *body;
01846
01847
01848
01849
01850 if (msgnum > -1 || !imapgreetings) {
01851 return 0;
01852 } else {
01853 file = strrchr(ast_strdupa(dir), '/');
01854 if (file)
01855 *file++ = '\0';
01856 else {
01857 ast_debug (1, "Failed to procure file name from directory passed.\n");
01858 return -1;
01859 }
01860 }
01861
01862
01863 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01864 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01865
01866
01867
01868
01869 if (!(vms_p = create_vm_state_from_user(vmu))) {
01870 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01871 return -1;
01872 }
01873 }
01874
01875
01876 *vms_p->introfn = '\0';
01877
01878 ast_mutex_lock(&vms_p->lock);
01879 init_mailstream(vms_p, GREETINGS_FOLDER);
01880 if (!vms_p->mailstream) {
01881 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01882 ast_mutex_unlock(&vms_p->lock);
01883 return -1;
01884 }
01885
01886
01887 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01888 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01889
01890 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01891 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01892 } else {
01893 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01894 ast_mutex_unlock(&vms_p->lock);
01895 return -1;
01896 }
01897 filename = strsep(&attachment, ".");
01898 if (!strcmp(filename, file)) {
01899 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01900 vms_p->msgArray[vms_p->curmsg] = i + 1;
01901 save_body(body, vms_p, "2", attachment, 0);
01902 ast_mutex_unlock(&vms_p->lock);
01903 return 0;
01904 }
01905 }
01906 ast_mutex_unlock(&vms_p->lock);
01907
01908 return -1;
01909 }
01910
01911 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01912 {
01913 BODY *body;
01914 char *header_content;
01915 char *attachedfilefmt;
01916 char buf[80];
01917 struct vm_state *vms;
01918 char text_file[PATH_MAX];
01919 FILE *text_file_ptr;
01920 int res = 0;
01921 struct ast_vm_user *vmu;
01922
01923 if (!(vmu = find_user(NULL, context, mailbox))) {
01924 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01925 return -1;
01926 }
01927
01928 if (msgnum < 0) {
01929 if (imapgreetings) {
01930 res = imap_retrieve_greeting(dir, msgnum, vmu);
01931 goto exit;
01932 } else {
01933 res = 0;
01934 goto exit;
01935 }
01936 }
01937
01938
01939
01940
01941 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01942
01943
01944
01945
01946
01947
01948
01949 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01950 res = -1;
01951 goto exit;
01952 }
01953
01954 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01955 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01956
01957
01958 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01959 res = 0;
01960 goto exit;
01961 }
01962
01963 if (option_debug > 2)
01964 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01965 if (vms->msgArray[msgnum] == 0) {
01966 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01967 res = -1;
01968 goto exit;
01969 }
01970
01971
01972 ast_mutex_lock(&vms->lock);
01973 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01974 ast_mutex_unlock(&vms->lock);
01975
01976 if (ast_strlen_zero(header_content)) {
01977 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01978 res = -1;
01979 goto exit;
01980 }
01981
01982 ast_mutex_lock(&vms->lock);
01983 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01984 ast_mutex_unlock(&vms->lock);
01985
01986
01987 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01988 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01989 } else {
01990 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01991 res = -1;
01992 goto exit;
01993 }
01994
01995
01996
01997 strsep(&attachedfilefmt, ".");
01998 if (!attachedfilefmt) {
01999 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02000 res = -1;
02001 goto exit;
02002 }
02003
02004 save_body(body, vms, "2", attachedfilefmt, 0);
02005 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02006 *vms->introfn = '\0';
02007 }
02008
02009
02010 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02011
02012 if (!(text_file_ptr = fopen(text_file, "w"))) {
02013 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02014 }
02015
02016 fprintf(text_file_ptr, "%s\n", "[message]");
02017
02018 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02019 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02020 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02021 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02022 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02023 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02024 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02025 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02026 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02027 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02028 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02029 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02030 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02031 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02032 fclose(text_file_ptr);
02033
02034 exit:
02035 free_user(vmu);
02036 return res;
02037 }
02038
02039 static int folder_int(const char *folder)
02040 {
02041
02042 if (!folder) {
02043 return 0;
02044 }
02045 if (!strcasecmp(folder, imapfolder)) {
02046 return 0;
02047 } else if (!strcasecmp(folder, "Old")) {
02048 return 1;
02049 } else if (!strcasecmp(folder, "Work")) {
02050 return 2;
02051 } else if (!strcasecmp(folder, "Family")) {
02052 return 3;
02053 } else if (!strcasecmp(folder, "Friends")) {
02054 return 4;
02055 } else if (!strcasecmp(folder, "Cust1")) {
02056 return 5;
02057 } else if (!strcasecmp(folder, "Cust2")) {
02058 return 6;
02059 } else if (!strcasecmp(folder, "Cust3")) {
02060 return 7;
02061 } else if (!strcasecmp(folder, "Cust4")) {
02062 return 8;
02063 } else if (!strcasecmp(folder, "Cust5")) {
02064 return 9;
02065 } else if (!strcasecmp(folder, "Urgent")) {
02066 return 11;
02067 } else {
02068 return 0;
02069 }
02070 }
02071
02072 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02073 {
02074 SEARCHPGM *pgm;
02075 SEARCHHEADER *hdr;
02076
02077 struct ast_vm_user *vmu, vmus;
02078 struct vm_state *vms_p;
02079 int ret = 0;
02080 int fold = folder_int(folder);
02081 int urgent = 0;
02082
02083
02084 if (fold == 11) {
02085 fold = NEW_FOLDER;
02086 urgent = 1;
02087 }
02088
02089 if (ast_strlen_zero(mailbox))
02090 return 0;
02091
02092
02093 vmu = find_user(&vmus, context, mailbox);
02094 if (!vmu) {
02095 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02096 return -1;
02097 } else {
02098
02099 if (vmu->imapuser[0] == '\0') {
02100 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02101 return -1;
02102 }
02103 }
02104
02105
02106 if (vmu->imapuser[0] == '\0') {
02107 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02108 free_user(vmu);
02109 return -1;
02110 }
02111 ast_assert(msgnum < vms->msg_array_max);
02112
02113
02114 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02115 if (!vms_p) {
02116 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02117 }
02118 if (vms_p) {
02119 ast_debug(3, "Returning before search - user is logged in\n");
02120 if (fold == 0) {
02121 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02122 }
02123 if (fold == 1) {
02124 return vms_p->oldmessages;
02125 }
02126 }
02127
02128
02129 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02130 if (!vms_p) {
02131 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02132 }
02133
02134 if (!vms_p) {
02135 vms_p = create_vm_state_from_user(vmu);
02136 }
02137 ret = init_mailstream(vms_p, fold);
02138 if (!vms_p->mailstream) {
02139 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02140 return -1;
02141 }
02142 if (ret == 0) {
02143 ast_mutex_lock(&vms_p->lock);
02144 pgm = mail_newsearchpgm ();
02145 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02146 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02147 pgm->header = hdr;
02148 if (fold != OLD_FOLDER) {
02149 pgm->unseen = 1;
02150 pgm->seen = 0;
02151 }
02152
02153
02154
02155 else {
02156 pgm->unseen = 0;
02157 pgm->seen = 1;
02158 }
02159
02160 if (fold == NEW_FOLDER) {
02161 if (urgent) {
02162 pgm->flagged = 1;
02163 pgm->unflagged = 0;
02164 } else {
02165 pgm->flagged = 0;
02166 pgm->unflagged = 1;
02167 }
02168 }
02169 pgm->undeleted = 1;
02170 pgm->deleted = 0;
02171
02172 vms_p->vmArrayIndex = 0;
02173 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02174 if (fold == 0 && urgent == 0)
02175 vms_p->newmessages = vms_p->vmArrayIndex;
02176 if (fold == 1)
02177 vms_p->oldmessages = vms_p->vmArrayIndex;
02178 if (fold == 0 && urgent == 1)
02179 vms_p->urgentmessages = vms_p->vmArrayIndex;
02180
02181 mail_free_searchpgm(&pgm);
02182 ast_mutex_unlock(&vms_p->lock);
02183 vms_p->updated = 0;
02184 return vms_p->vmArrayIndex;
02185 } else {
02186 ast_mutex_lock(&vms_p->lock);
02187 mail_ping(vms_p->mailstream);
02188 ast_mutex_unlock(&vms_p->lock);
02189 }
02190 return 0;
02191 }
02192
02193 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02194 {
02195
02196 check_quota(vms, vmu->imapfolder);
02197 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02198 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02199 ast_play_and_wait(chan, "vm-mailboxfull");
02200 return -1;
02201 }
02202
02203
02204 ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
02205 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02206 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02207 ast_play_and_wait(chan, "vm-mailboxfull");
02208 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02209 return -1;
02210 }
02211
02212 return 0;
02213 }
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224 static int messagecount(const char *context, const char *mailbox, const char *folder)
02225 {
02226 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02227 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02228 } else {
02229 return __messagecount(context, mailbox, folder);
02230 }
02231 }
02232
02233 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag)
02234 {
02235 char *myserveremail = serveremail;
02236 char fn[PATH_MAX];
02237 char introfn[PATH_MAX];
02238 char mailbox[256];
02239 char *stringp;
02240 FILE *p = NULL;
02241 char tmp[80] = "/tmp/astmail-XXXXXX";
02242 long len;
02243 void *buf;
02244 int tempcopy = 0;
02245 STRING str;
02246 int ret;
02247 char *imap_flags = NIL;
02248 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02249 int box = NEW_FOLDER;
02250
02251
02252 if (msgnum < 0) {
02253 if(!imapgreetings) {
02254 return 0;
02255 } else {
02256 box = GREETINGS_FOLDER;
02257 }
02258 }
02259
02260 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02261 return -1;
02262 }
02263
02264
02265 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02266 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02267 imap_flags = "\\FLAGGED";
02268 }
02269
02270
02271 fmt = ast_strdupa(fmt);
02272 stringp = fmt;
02273 strsep(&stringp, "|");
02274
02275 if (!ast_strlen_zero(vmu->serveremail))
02276 myserveremail = vmu->serveremail;
02277
02278 if (msgnum > -1)
02279 make_file(fn, sizeof(fn), dir, msgnum);
02280 else
02281 ast_copy_string (fn, dir, sizeof(fn));
02282
02283 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02284 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02285 *introfn = '\0';
02286 }
02287
02288 if (ast_strlen_zero(vmu->email)) {
02289
02290
02291
02292
02293
02294 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02295 tempcopy = 1;
02296 }
02297
02298 if (!strcmp(fmt, "wav49"))
02299 fmt = "WAV";
02300 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02301
02302
02303
02304 if (!(p = vm_mkftemp(tmp))) {
02305 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02306 if (tempcopy)
02307 *(vmu->email) = '\0';
02308 return -1;
02309 }
02310
02311 if (msgnum < 0 && imapgreetings) {
02312 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02313 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02314 return -1;
02315 }
02316 imap_delete_old_greeting(fn, vms);
02317 }
02318
02319 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02320 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02321 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02322 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02323
02324 len = ftell(p);
02325 rewind(p);
02326 if (!(buf = ast_malloc(len + 1))) {
02327 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02328 fclose(p);
02329 if (tempcopy)
02330 *(vmu->email) = '\0';
02331 return -1;
02332 }
02333 if (fread(buf, len, 1, p) < len) {
02334 if (ferror(p)) {
02335 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02336 return -1;
02337 }
02338 }
02339 ((char *) buf)[len] = '\0';
02340 INIT(&str, mail_string, buf, len);
02341 ret = init_mailstream(vms, box);
02342 if (ret == 0) {
02343 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02344 ast_mutex_lock(&vms->lock);
02345 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02346 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02347 ast_mutex_unlock(&vms->lock);
02348 fclose(p);
02349 unlink(tmp);
02350 ast_free(buf);
02351 } else {
02352 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02353 fclose(p);
02354 unlink(tmp);
02355 ast_free(buf);
02356 return -1;
02357 }
02358 ast_debug(3, "%s stored\n", fn);
02359
02360 if (tempcopy)
02361 *(vmu->email) = '\0';
02362 inprocess_count(vmu->mailbox, vmu->context, -1);
02363 return 0;
02364
02365 }
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02381 {
02382 char tmp[PATH_MAX] = "";
02383 char *mailboxnc;
02384 char *context;
02385 char *mb;
02386 char *cur;
02387 if (newmsgs)
02388 *newmsgs = 0;
02389 if (oldmsgs)
02390 *oldmsgs = 0;
02391 if (urgentmsgs)
02392 *urgentmsgs = 0;
02393
02394 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02395
02396 if (ast_strlen_zero(mailbox_context))
02397 return 0;
02398
02399 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02400 context = strchr(tmp, '@');
02401 if (strchr(mailbox_context, ',')) {
02402 int tmpnew, tmpold, tmpurgent;
02403 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02404 mb = tmp;
02405 while ((cur = strsep(&mb, ", "))) {
02406 if (!ast_strlen_zero(cur)) {
02407 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02408 return -1;
02409 else {
02410 if (newmsgs)
02411 *newmsgs += tmpnew;
02412 if (oldmsgs)
02413 *oldmsgs += tmpold;
02414 if (urgentmsgs)
02415 *urgentmsgs += tmpurgent;
02416 }
02417 }
02418 }
02419 return 0;
02420 }
02421 if (context) {
02422 *context = '\0';
02423 mailboxnc = tmp;
02424 context++;
02425 } else {
02426 context = "default";
02427 mailboxnc = (char *) mailbox_context;
02428 }
02429
02430 if (newmsgs) {
02431 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02432 if (!vmu) {
02433 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02434 return -1;
02435 }
02436 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02437 free_user(vmu);
02438 return -1;
02439 }
02440 free_user(vmu);
02441 }
02442 if (oldmsgs) {
02443 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02444 return -1;
02445 }
02446 }
02447 if (urgentmsgs) {
02448 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02449 return -1;
02450 }
02451 }
02452 return 0;
02453 }
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465 static int has_voicemail(const char *mailbox, const char *folder)
02466 {
02467 char tmp[256], *tmp2, *box, *context;
02468 ast_copy_string(tmp, mailbox, sizeof(tmp));
02469 tmp2 = tmp;
02470 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02471 while ((box = strsep(&tmp2, ",&"))) {
02472 if (!ast_strlen_zero(box)) {
02473 if (has_voicemail(box, folder)) {
02474 return 1;
02475 }
02476 }
02477 }
02478 }
02479 if ((context = strchr(tmp, '@'))) {
02480 *context++ = '\0';
02481 } else {
02482 context = "default";
02483 }
02484 return __messagecount(context, tmp, folder) ? 1 : 0;
02485 }
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, char *flag)
02503 {
02504 struct vm_state *sendvms = NULL, *destvms = NULL;
02505 char messagestring[10];
02506 if (msgnum >= recip->maxmsg) {
02507 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02508 return -1;
02509 }
02510 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02511 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02512 return -1;
02513 }
02514 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02515 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02516 return -1;
02517 }
02518 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02519 ast_mutex_lock(&sendvms->lock);
02520 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02521 ast_mutex_unlock(&sendvms->lock);
02522 return 0;
02523 }
02524 ast_mutex_unlock(&sendvms->lock);
02525 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02526 return -1;
02527 }
02528
02529 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02530 {
02531 char tmp[256], *t = tmp;
02532 size_t left = sizeof(tmp);
02533
02534 if (box == OLD_FOLDER) {
02535 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02536 } else {
02537 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02538 }
02539
02540 if (box == NEW_FOLDER) {
02541 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02542 } else {
02543 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02544 }
02545
02546
02547 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02548
02549
02550 if (!ast_strlen_zero(authuser))
02551 ast_build_string(&t, &left, "/authuser=%s", authuser);
02552
02553
02554 if (!ast_strlen_zero(imapflags))
02555 ast_build_string(&t, &left, "/%s", imapflags);
02556
02557
02558 #if 1
02559 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02560 #else
02561 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02562 #endif
02563 if (box == NEW_FOLDER || box == OLD_FOLDER)
02564 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02565 else if (box == GREETINGS_FOLDER)
02566 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02567 else {
02568 if (!ast_strlen_zero(imapparentfolder)) {
02569
02570 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02571 } else {
02572 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02573 }
02574 }
02575 }
02576
02577 static int init_mailstream(struct vm_state *vms, int box)
02578 {
02579 MAILSTREAM *stream = NIL;
02580 long debug;
02581 char tmp[256];
02582
02583 if (!vms) {
02584 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02585 return -1;
02586 }
02587 if (option_debug > 2)
02588 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02589 if (vms->mailstream == NIL || !vms->mailstream) {
02590 if (option_debug)
02591 ast_log(LOG_DEBUG, "mailstream not set.\n");
02592 } else {
02593 stream = vms->mailstream;
02594 }
02595
02596 debug = NIL;
02597
02598 if (delimiter == '\0') {
02599 char *cp;
02600 #ifdef USE_SYSTEM_IMAP
02601 #include <imap/linkage.c>
02602 #elif defined(USE_SYSTEM_CCLIENT)
02603 #include <c-client/linkage.c>
02604 #else
02605 #include "linkage.c"
02606 #endif
02607
02608 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02609 ast_mutex_lock(&vms->lock);
02610 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02611 ast_mutex_unlock(&vms->lock);
02612 if (stream == NIL) {
02613 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02614 return -1;
02615 }
02616 get_mailbox_delimiter(stream);
02617
02618 for (cp = vms->imapfolder; *cp; cp++)
02619 if (*cp == '/')
02620 *cp = delimiter;
02621 }
02622
02623 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02624 if (option_debug > 2)
02625 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02626 ast_mutex_lock(&vms->lock);
02627 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02628 ast_mutex_unlock(&vms->lock);
02629 if (vms->mailstream == NIL) {
02630 return -1;
02631 } else {
02632 return 0;
02633 }
02634 }
02635
02636 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02637 {
02638 SEARCHPGM *pgm;
02639 SEARCHHEADER *hdr;
02640 int ret, urgent = 0;
02641
02642
02643 if (box == 11) {
02644 box = NEW_FOLDER;
02645 urgent = 1;
02646 }
02647
02648 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02649 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02650 vms->imapversion = vmu->imapversion;
02651 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02652
02653 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02654 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02655 return -1;
02656 }
02657
02658 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02659
02660
02661 if (box == 0) {
02662 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02663 check_quota(vms, (char *) mbox(vmu, box));
02664 }
02665
02666 ast_mutex_lock(&vms->lock);
02667 pgm = mail_newsearchpgm();
02668
02669
02670 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02671 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02672 pgm->header = hdr;
02673 pgm->deleted = 0;
02674 pgm->undeleted = 1;
02675
02676
02677 if (box == NEW_FOLDER && urgent == 1) {
02678 pgm->unseen = 1;
02679 pgm->seen = 0;
02680 pgm->flagged = 1;
02681 pgm->unflagged = 0;
02682 } else if (box == NEW_FOLDER && urgent == 0) {
02683 pgm->unseen = 1;
02684 pgm->seen = 0;
02685 pgm->flagged = 0;
02686 pgm->unflagged = 1;
02687 } else if (box == OLD_FOLDER) {
02688 pgm->seen = 1;
02689 pgm->unseen = 0;
02690 }
02691
02692 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02693
02694 vms->vmArrayIndex = 0;
02695 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02696 vms->lastmsg = vms->vmArrayIndex - 1;
02697 mail_free_searchpgm(&pgm);
02698
02699
02700
02701
02702 if (box == 0 && !vms->dh_arraysize) {
02703 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02704 }
02705 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02706 ast_mutex_unlock(&vms->lock);
02707 return -1;
02708 }
02709
02710 ast_mutex_unlock(&vms->lock);
02711 return 0;
02712 }
02713
02714 static void write_file(char *filename, char *buffer, unsigned long len)
02715 {
02716 FILE *output;
02717
02718 output = fopen (filename, "w");
02719 if (fwrite(buffer, len, 1, output) != 1) {
02720 if (ferror(output)) {
02721 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02722 }
02723 }
02724 fclose (output);
02725 }
02726
02727 static void update_messages_by_imapuser(const char *user, unsigned long number)
02728 {
02729 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02730
02731 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02732 return;
02733 }
02734
02735 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02736
02737
02738 if (vms->vmArrayIndex >= vms->msg_array_max) {
02739 long *new_mem = ast_realloc(vms->msgArray, 2 * vms->msg_array_max * sizeof(long));
02740 if (!new_mem) {
02741 return;
02742 }
02743 vms->msgArray = new_mem;
02744 vms->msg_array_max *= 2;
02745 }
02746
02747 vms->msgArray[vms->vmArrayIndex++] = number;
02748 }
02749
02750 void mm_searched(MAILSTREAM *stream, unsigned long number)
02751 {
02752 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02753
02754 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02755 return;
02756
02757 update_messages_by_imapuser(user, number);
02758 }
02759
02760 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02761 {
02762 struct ast_variable *var;
02763 struct ast_vm_user *vmu;
02764
02765 vmu = ast_calloc(1, sizeof *vmu);
02766 if (!vmu)
02767 return NULL;
02768
02769 populate_defaults(vmu);
02770 ast_set_flag(vmu, VM_ALLOCED);
02771
02772 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02773 if (var) {
02774 apply_options_full(vmu, var);
02775 ast_variables_destroy(var);
02776 return vmu;
02777 } else {
02778 ast_free(vmu);
02779 return NULL;
02780 }
02781 }
02782
02783
02784
02785 void mm_exists(MAILSTREAM * stream, unsigned long number)
02786 {
02787
02788 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02789 if (number == 0) return;
02790 set_update(stream);
02791 }
02792
02793
02794 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02795 {
02796
02797 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02798 if (number == 0) return;
02799 set_update(stream);
02800 }
02801
02802
02803 void mm_flags(MAILSTREAM * stream, unsigned long number)
02804 {
02805
02806 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02807 if (number == 0) return;
02808 set_update(stream);
02809 }
02810
02811
02812 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02813 {
02814 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02815 mm_log (string, errflg);
02816 }
02817
02818
02819 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02820 {
02821 if (delimiter == '\0') {
02822 delimiter = delim;
02823 }
02824
02825 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02826 if (attributes & LATT_NOINFERIORS)
02827 ast_debug(5, "no inferiors\n");
02828 if (attributes & LATT_NOSELECT)
02829 ast_debug(5, "no select\n");
02830 if (attributes & LATT_MARKED)
02831 ast_debug(5, "marked\n");
02832 if (attributes & LATT_UNMARKED)
02833 ast_debug(5, "unmarked\n");
02834 }
02835
02836
02837 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02838 {
02839 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02840 if (attributes & LATT_NOINFERIORS)
02841 ast_debug(5, "no inferiors\n");
02842 if (attributes & LATT_NOSELECT)
02843 ast_debug(5, "no select\n");
02844 if (attributes & LATT_MARKED)
02845 ast_debug(5, "marked\n");
02846 if (attributes & LATT_UNMARKED)
02847 ast_debug(5, "unmarked\n");
02848 }
02849
02850
02851 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02852 {
02853 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02854 if (status->flags & SA_MESSAGES)
02855 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02856 if (status->flags & SA_RECENT)
02857 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02858 if (status->flags & SA_UNSEEN)
02859 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02860 if (status->flags & SA_UIDVALIDITY)
02861 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02862 if (status->flags & SA_UIDNEXT)
02863 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02864 ast_log(AST_LOG_NOTICE, "\n");
02865 }
02866
02867
02868 void mm_log(char *string, long errflg)
02869 {
02870 switch ((short) errflg) {
02871 case NIL:
02872 ast_debug(1, "IMAP Info: %s\n", string);
02873 break;
02874 case PARSE:
02875 case WARN:
02876 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02877 break;
02878 case ERROR:
02879 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02880 break;
02881 }
02882 }
02883
02884
02885 void mm_dlog(char *string)
02886 {
02887 ast_log(AST_LOG_NOTICE, "%s\n", string);
02888 }
02889
02890
02891 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02892 {
02893 struct ast_vm_user *vmu;
02894
02895 ast_debug(4, "Entering callback mm_login\n");
02896
02897 ast_copy_string(user, mb->user, MAILTMPLEN);
02898
02899
02900 if (!ast_strlen_zero(authpassword)) {
02901 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02902 } else {
02903 AST_LIST_TRAVERSE(&users, vmu, list) {
02904 if (!strcasecmp(mb->user, vmu->imapuser)) {
02905 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02906 break;
02907 }
02908 }
02909 if (!vmu) {
02910 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02911 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02912 free_user(vmu);
02913 }
02914 }
02915 }
02916 }
02917
02918
02919 void mm_critical(MAILSTREAM * stream)
02920 {
02921 }
02922
02923
02924 void mm_nocritical(MAILSTREAM * stream)
02925 {
02926 }
02927
02928
02929 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02930 {
02931 kill (getpid (), SIGSTOP);
02932 return NIL;
02933 }
02934
02935
02936 void mm_fatal(char *string)
02937 {
02938 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02939 }
02940
02941
02942 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02943 {
02944 struct vm_state *vms;
02945 char *mailbox = stream->mailbox, *user;
02946 char buf[1024] = "";
02947 unsigned long usage = 0, limit = 0;
02948
02949 while (pquota) {
02950 usage = pquota->usage;
02951 limit = pquota->limit;
02952 pquota = pquota->next;
02953 }
02954
02955 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
02956 ast_log(AST_LOG_ERROR, "No state found.\n");
02957 return;
02958 }
02959
02960 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02961
02962 vms->quota_usage = usage;
02963 vms->quota_limit = limit;
02964 }
02965
02966 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02967 {
02968 char *start, *eol_pnt;
02969 int taglen;
02970
02971 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02972 return NULL;
02973
02974 taglen = strlen(tag) + 1;
02975 if (taglen < 1)
02976 return NULL;
02977
02978 if (!(start = strstr(header, tag)))
02979 return NULL;
02980
02981
02982 memset(buf, 0, len);
02983
02984 ast_copy_string(buf, start+taglen, len);
02985 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02986 *eol_pnt = '\0';
02987 return buf;
02988 }
02989
02990 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02991 {
02992 char *start, *quote, *eol_pnt;
02993
02994 if (ast_strlen_zero(mailbox))
02995 return NULL;
02996
02997 if (!(start = strstr(mailbox, "/user=")))
02998 return NULL;
02999
03000 ast_copy_string(buf, start+6, len);
03001
03002 if (!(quote = strchr(buf, '\"'))) {
03003 if (!(eol_pnt = strchr(buf, '/')))
03004 eol_pnt = strchr(buf,'}');
03005 *eol_pnt = '\0';
03006 return buf;
03007 } else {
03008 eol_pnt = strchr(buf+1,'\"');
03009 *eol_pnt = '\0';
03010 return buf+1;
03011 }
03012 }
03013
03014 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03015 {
03016 struct vm_state *vms_p;
03017
03018 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03019 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03020 return vms_p;
03021 }
03022 if (option_debug > 4)
03023 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03024
03025 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03026 return NULL;
03027 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03028 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03029 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03030 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03031 vms_p->mailstream = NIL;
03032 vms_p->imapversion = vmu->imapversion;
03033 if (option_debug > 4)
03034 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03035 vms_p->updated = 1;
03036
03037 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03038 init_vm_state(vms_p);
03039 vmstate_insert(vms_p);
03040 return vms_p;
03041 }
03042
03043 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03044 {
03045 struct vmstate *vlist = NULL;
03046
03047 if (interactive) {
03048 struct vm_state *vms;
03049 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03050 vms = pthread_getspecific(ts_vmstate.key);
03051 return vms;
03052 }
03053
03054 AST_LIST_LOCK(&vmstates);
03055 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03056 if (!vlist->vms) {
03057 ast_debug(3, "error: vms is NULL for %s\n", user);
03058 continue;
03059 }
03060 if (vlist->vms->imapversion != imapversion) {
03061 continue;
03062 }
03063 if (!vlist->vms->imapuser) {
03064 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03065 continue;
03066 }
03067
03068 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03069 AST_LIST_UNLOCK(&vmstates);
03070 return vlist->vms;
03071 }
03072 }
03073 AST_LIST_UNLOCK(&vmstates);
03074
03075 ast_debug(3, "%s not found in vmstates\n", user);
03076
03077 return NULL;
03078 }
03079
03080 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03081 {
03082
03083 struct vmstate *vlist = NULL;
03084 const char *local_context = S_OR(context, "default");
03085
03086 if (interactive) {
03087 struct vm_state *vms;
03088 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03089 vms = pthread_getspecific(ts_vmstate.key);
03090 return vms;
03091 }
03092
03093 AST_LIST_LOCK(&vmstates);
03094 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03095 if (!vlist->vms) {
03096 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03097 continue;
03098 }
03099 if (vlist->vms->imapversion != imapversion) {
03100 continue;
03101 }
03102 if (!vlist->vms->username || !vlist->vms->context) {
03103 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03104 continue;
03105 }
03106
03107 ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
03108
03109 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03110 ast_debug(3, "Found it!\n");
03111 AST_LIST_UNLOCK(&vmstates);
03112 return vlist->vms;
03113 }
03114 }
03115 AST_LIST_UNLOCK(&vmstates);
03116
03117 ast_debug(3, "%s not found in vmstates\n", mailbox);
03118
03119 return NULL;
03120 }
03121
03122 static void vmstate_insert(struct vm_state *vms)
03123 {
03124 struct vmstate *v;
03125 struct vm_state *altvms;
03126
03127
03128
03129
03130 if (vms->interactive == 1) {
03131 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03132 if (altvms) {
03133 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03134 vms->newmessages = altvms->newmessages;
03135 vms->oldmessages = altvms->oldmessages;
03136 vms->vmArrayIndex = altvms->vmArrayIndex;
03137
03138 vms->lastmsg = altvms->lastmsg;
03139 vms->curmsg = altvms->curmsg;
03140
03141 vms->persist_vms = altvms;
03142
03143 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03144 vms->mailstream = altvms->mailstream;
03145 #else
03146 vms->mailstream = NIL;
03147 #endif
03148 }
03149 return;
03150 }
03151
03152 if (!(v = ast_calloc(1, sizeof(*v))))
03153 return;
03154
03155 v->vms = vms;
03156
03157 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03158
03159 AST_LIST_LOCK(&vmstates);
03160 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03161 AST_LIST_UNLOCK(&vmstates);
03162 }
03163
03164 static void vmstate_delete(struct vm_state *vms)
03165 {
03166 struct vmstate *vc = NULL;
03167 struct vm_state *altvms = NULL;
03168
03169
03170
03171 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03172 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03173 altvms->newmessages = vms->newmessages;
03174 altvms->oldmessages = vms->oldmessages;
03175 altvms->updated = 1;
03176 vms->mailstream = mail_close(vms->mailstream);
03177
03178
03179 return;
03180 }
03181
03182 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03183
03184 AST_LIST_LOCK(&vmstates);
03185 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03186 if (vc->vms == vms) {
03187 AST_LIST_REMOVE_CURRENT(list);
03188 break;
03189 }
03190 }
03191 AST_LIST_TRAVERSE_SAFE_END
03192 AST_LIST_UNLOCK(&vmstates);
03193
03194 if (vc) {
03195 ast_mutex_destroy(&vc->vms->lock);
03196 ast_free(vc->vms->msgArray);
03197 vc->vms->msgArray = NULL;
03198 vc->vms->msg_array_max = 0;
03199
03200 ast_free(vc);
03201 } else {
03202 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03203 }
03204 }
03205
03206 static void set_update(MAILSTREAM * stream)
03207 {
03208 struct vm_state *vms;
03209 char *mailbox = stream->mailbox, *user;
03210 char buf[1024] = "";
03211
03212 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03213 if (user && option_debug > 2)
03214 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03215 return;
03216 }
03217
03218 ast_debug(3, "User %s mailbox set for update.\n", user);
03219
03220 vms->updated = 1;
03221 }
03222
03223 static void init_vm_state(struct vm_state *vms)
03224 {
03225 vms->msg_array_max = VMSTATE_MAX_MSG_ARRAY;
03226 vms->msgArray = ast_calloc(vms->msg_array_max, sizeof(long));
03227 if (!vms->msgArray) {
03228
03229 vms->msg_array_max = 0;
03230 }
03231 vms->vmArrayIndex = 0;
03232 ast_mutex_init(&vms->lock);
03233 }
03234
03235 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03236 {
03237 char *body_content;
03238 char *body_decoded;
03239 char *fn = is_intro ? vms->introfn : vms->fn;
03240 unsigned long len;
03241 unsigned long newlen;
03242 char filename[256];
03243
03244 if (!body || body == NIL)
03245 return -1;
03246
03247 ast_mutex_lock(&vms->lock);
03248 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03249 ast_mutex_unlock(&vms->lock);
03250 if (body_content != NIL) {
03251 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03252
03253 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03254
03255 if (!newlen) {
03256 return -1;
03257 }
03258 write_file(filename, (char *) body_decoded, newlen);
03259 } else {
03260 ast_debug(5, "Body of message is NULL.\n");
03261 return -1;
03262 }
03263 return 0;
03264 }
03265
03266
03267
03268
03269
03270
03271
03272
03273 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03274 char tmp[50];
03275 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03276 mail_list(stream, tmp, "*");
03277 }
03278
03279
03280
03281
03282
03283
03284
03285
03286 static void check_quota(struct vm_state *vms, char *mailbox) {
03287 ast_mutex_lock(&vms->lock);
03288 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03289 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03290 if (vms && vms->mailstream != NULL) {
03291 imap_getquotaroot(vms->mailstream, mailbox);
03292 } else {
03293 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03294 }
03295 ast_mutex_unlock(&vms->lock);
03296 }
03297
03298 #endif
03299
03300
03301
03302
03303
03304 static int vm_lock_path(const char *path)
03305 {
03306 switch (ast_lock_path(path)) {
03307 case AST_LOCK_TIMEOUT:
03308 return -1;
03309 default:
03310 return 0;
03311 }
03312 }
03313
03314
03315 #ifdef ODBC_STORAGE
03316 struct generic_prepare_struct {
03317 char *sql;
03318 int argc;
03319 char **argv;
03320 };
03321
03322 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03323 {
03324 struct generic_prepare_struct *gps = data;
03325 int res, i;
03326 SQLHSTMT stmt;
03327
03328 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03329 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03330 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03331 return NULL;
03332 }
03333 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03334 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03335 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03336 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03337 return NULL;
03338 }
03339 for (i = 0; i < gps->argc; i++)
03340 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03341
03342 return stmt;
03343 }
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359 static int retrieve_file(char *dir, int msgnum)
03360 {
03361 int x = 0;
03362 int res;
03363 int fd = -1;
03364 size_t fdlen = 0;
03365 void *fdm = MAP_FAILED;
03366 SQLSMALLINT colcount = 0;
03367 SQLHSTMT stmt;
03368 char sql[PATH_MAX];
03369 char fmt[80]="";
03370 char *c;
03371 char coltitle[256];
03372 SQLSMALLINT collen;
03373 SQLSMALLINT datatype;
03374 SQLSMALLINT decimaldigits;
03375 SQLSMALLINT nullable;
03376 SQLULEN colsize;
03377 SQLLEN colsize2;
03378 FILE *f = NULL;
03379 char rowdata[80];
03380 char fn[PATH_MAX];
03381 char full_fn[PATH_MAX];
03382 char msgnums[80];
03383 char *argv[] = { dir, msgnums };
03384 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03385
03386 struct odbc_obj *obj;
03387 obj = ast_odbc_request_obj(odbc_database, 0);
03388 if (obj) {
03389 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03390 c = strchr(fmt, '|');
03391 if (c)
03392 *c = '\0';
03393 if (!strcasecmp(fmt, "wav49"))
03394 strcpy(fmt, "WAV");
03395 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03396 if (msgnum > -1)
03397 make_file(fn, sizeof(fn), dir, msgnum);
03398 else
03399 ast_copy_string(fn, dir, sizeof(fn));
03400
03401
03402 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03403
03404 if (!(f = fopen(full_fn, "w+"))) {
03405 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03406 goto yuck;
03407 }
03408
03409 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03410 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03411 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03412 if (!stmt) {
03413 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03414 ast_odbc_release_obj(obj);
03415 goto yuck;
03416 }
03417 res = SQLFetch(stmt);
03418 if (res == SQL_NO_DATA) {
03419 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03420 ast_odbc_release_obj(obj);
03421 goto yuck;
03422 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03423 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03424 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03425 ast_odbc_release_obj(obj);
03426 goto yuck;
03427 }
03428 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03429 if (fd < 0) {
03430 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03431 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03432 ast_odbc_release_obj(obj);
03433 goto yuck;
03434 }
03435 res = SQLNumResultCols(stmt, &colcount);
03436 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03437 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03438 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03439 ast_odbc_release_obj(obj);
03440 goto yuck;
03441 }
03442 if (f)
03443 fprintf(f, "[message]\n");
03444 for (x = 0; x < colcount; x++) {
03445 rowdata[0] = '\0';
03446 colsize = 0;
03447 collen = sizeof(coltitle);
03448 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03449 &datatype, &colsize, &decimaldigits, &nullable);
03450 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03451 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03452 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03453 ast_odbc_release_obj(obj);
03454 goto yuck;
03455 }
03456 if (!strcasecmp(coltitle, "recording")) {
03457 off_t offset;
03458 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03459 fdlen = colsize2;
03460 if (fd > -1) {
03461 char tmp[1]="";
03462 lseek(fd, fdlen - 1, SEEK_SET);
03463 if (write(fd, tmp, 1) != 1) {
03464 close(fd);
03465 fd = -1;
03466 continue;
03467 }
03468
03469 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03470 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03471 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03472 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03473 ast_odbc_release_obj(obj);
03474 goto yuck;
03475 } else {
03476 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03477 munmap(fdm, CHUNKSIZE);
03478 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03479 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03480 unlink(full_fn);
03481 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03482 ast_odbc_release_obj(obj);
03483 goto yuck;
03484 }
03485 }
03486 }
03487 if (truncate(full_fn, fdlen) < 0) {
03488 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03489 }
03490 }
03491 } else {
03492 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03493 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03494 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03495 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03496 ast_odbc_release_obj(obj);
03497 goto yuck;
03498 }
03499 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03500 fprintf(f, "%s=%s\n", coltitle, rowdata);
03501 }
03502 }
03503 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03504 ast_odbc_release_obj(obj);
03505 } else
03506 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03507 yuck:
03508 if (f)
03509 fclose(f);
03510 if (fd > -1)
03511 close(fd);
03512 return x - 1;
03513 }
03514
03515
03516
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03527 {
03528 int x = 0;
03529 int res;
03530 SQLHSTMT stmt;
03531 char sql[PATH_MAX];
03532 char rowdata[20];
03533 char *argv[] = { dir };
03534 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03535
03536 struct odbc_obj *obj;
03537 obj = ast_odbc_request_obj(odbc_database, 0);
03538 if (obj) {
03539 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03540
03541 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03542 if (!stmt) {
03543 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03544 ast_odbc_release_obj(obj);
03545 goto yuck;
03546 }
03547 res = SQLFetch(stmt);
03548 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03549 if (res == SQL_NO_DATA) {
03550 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03551 } else {
03552 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03553 }
03554
03555 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03556 ast_odbc_release_obj(obj);
03557 goto yuck;
03558 }
03559 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03560 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03561 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03562 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03563 ast_odbc_release_obj(obj);
03564 goto yuck;
03565 }
03566 if (sscanf(rowdata, "%30d", &x) != 1)
03567 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03568 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03569 ast_odbc_release_obj(obj);
03570 return x;
03571 } else
03572 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03573 yuck:
03574 return x - 1;
03575 }
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586 static int message_exists(char *dir, int msgnum)
03587 {
03588 int x = 0;
03589 int res;
03590 SQLHSTMT stmt;
03591 char sql[PATH_MAX];
03592 char rowdata[20];
03593 char msgnums[20];
03594 char *argv[] = { dir, msgnums };
03595 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03596
03597 struct odbc_obj *obj;
03598 obj = ast_odbc_request_obj(odbc_database, 0);
03599 if (obj) {
03600 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03601 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03602 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03603 if (!stmt) {
03604 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03605 ast_odbc_release_obj(obj);
03606 goto yuck;
03607 }
03608 res = SQLFetch(stmt);
03609 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03610 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03611 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03612 ast_odbc_release_obj(obj);
03613 goto yuck;
03614 }
03615 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03616 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03617 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03618 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03619 ast_odbc_release_obj(obj);
03620 goto yuck;
03621 }
03622 if (sscanf(rowdata, "%30d", &x) != 1)
03623 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03624 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03625 ast_odbc_release_obj(obj);
03626 } else
03627 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03628 yuck:
03629 return x;
03630 }
03631
03632
03633
03634
03635
03636
03637
03638
03639
03640
03641 static int count_messages(struct ast_vm_user *vmu, char *dir)
03642 {
03643 int x = 0;
03644 int res;
03645 SQLHSTMT stmt;
03646 char sql[PATH_MAX];
03647 char rowdata[20];
03648 char *argv[] = { dir };
03649 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03650
03651 struct odbc_obj *obj;
03652 obj = ast_odbc_request_obj(odbc_database, 0);
03653 if (obj) {
03654 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03655 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03656 if (!stmt) {
03657 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03658 ast_odbc_release_obj(obj);
03659 goto yuck;
03660 }
03661 res = SQLFetch(stmt);
03662 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03663 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03664 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03665 ast_odbc_release_obj(obj);
03666 goto yuck;
03667 }
03668 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03669 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03670 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03671 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03672 ast_odbc_release_obj(obj);
03673 goto yuck;
03674 }
03675 if (sscanf(rowdata, "%30d", &x) != 1)
03676 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03677 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03678 ast_odbc_release_obj(obj);
03679 return x;
03680 } else
03681 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03682 yuck:
03683 return x - 1;
03684
03685 }
03686
03687
03688
03689
03690
03691
03692
03693
03694
03695
03696
03697 static void delete_file(const char *sdir, int smsg)
03698 {
03699 SQLHSTMT stmt;
03700 char sql[PATH_MAX];
03701 char msgnums[20];
03702 char *argv[] = { NULL, msgnums };
03703 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03704 struct odbc_obj *obj;
03705
03706 argv[0] = ast_strdupa(sdir);
03707
03708 obj = ast_odbc_request_obj(odbc_database, 0);
03709 if (obj) {
03710 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03711 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03712 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03713 if (!stmt)
03714 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03715 else
03716 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03717 ast_odbc_release_obj(obj);
03718 } else
03719 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03720 return;
03721 }
03722
03723
03724
03725
03726
03727
03728
03729
03730
03731
03732
03733
03734 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03735 {
03736 SQLHSTMT stmt;
03737 char sql[512];
03738 char msgnums[20];
03739 char msgnumd[20];
03740 struct odbc_obj *obj;
03741 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03742 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03743
03744 delete_file(ddir, dmsg);
03745 obj = ast_odbc_request_obj(odbc_database, 0);
03746 if (obj) {
03747 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03748 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03749 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
03750 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03751 if (!stmt)
03752 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03753 else
03754 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03755 ast_odbc_release_obj(obj);
03756 } else
03757 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03758 return;
03759 }
03760
03761 struct insert_data {
03762 char *sql;
03763 const char *dir;
03764 const char *msgnums;
03765 void *data;
03766 SQLLEN datalen;
03767 SQLLEN indlen;
03768 const char *context;
03769 const char *macrocontext;
03770 const char *callerid;
03771 const char *origtime;
03772 const char *duration;
03773 const char *mailboxuser;
03774 const char *mailboxcontext;
03775 const char *category;
03776 const char *flag;
03777 };
03778
03779 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03780 {
03781 struct insert_data *data = vdata;
03782 int res;
03783 SQLHSTMT stmt;
03784
03785 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03786 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03787 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03788 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03789 return NULL;
03790 }
03791
03792 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03793 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03794 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03795 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03796 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03797 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03798 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03799 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03800 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03801 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03802 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03803 if (!ast_strlen_zero(data->category)) {
03804 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03805 }
03806 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03807 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03808 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03809 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03810 return NULL;
03811 }
03812
03813 return stmt;
03814 }
03815
03816
03817
03818
03819
03820
03821
03822
03823
03824
03825
03826
03827
03828
03829 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03830 {
03831 int res = 0;
03832 int fd = -1;
03833 void *fdm = MAP_FAILED;
03834 off_t fdlen = -1;
03835 SQLHSTMT stmt;
03836 char sql[PATH_MAX];
03837 char msgnums[20];
03838 char fn[PATH_MAX];
03839 char full_fn[PATH_MAX];
03840 char fmt[80]="";
03841 char *c;
03842 struct ast_config *cfg = NULL;
03843 struct odbc_obj *obj;
03844 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03845 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03846 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03847
03848 delete_file(dir, msgnum);
03849 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03850 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03851 return -1;
03852 }
03853
03854 do {
03855 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03856 c = strchr(fmt, '|');
03857 if (c)
03858 *c = '\0';
03859 if (!strcasecmp(fmt, "wav49"))
03860 strcpy(fmt, "WAV");
03861 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03862 if (msgnum > -1)
03863 make_file(fn, sizeof(fn), dir, msgnum);
03864 else
03865 ast_copy_string(fn, dir, sizeof(fn));
03866 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03867 cfg = ast_config_load(full_fn, config_flags);
03868 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03869 fd = open(full_fn, O_RDWR);
03870 if (fd < 0) {
03871 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03872 res = -1;
03873 break;
03874 }
03875 if (valid_config(cfg)) {
03876 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03877 idata.context = "";
03878 }
03879 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03880 idata.macrocontext = "";
03881 }
03882 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03883 idata.callerid = "";
03884 }
03885 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03886 idata.origtime = "";
03887 }
03888 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03889 idata.duration = "";
03890 }
03891 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03892 idata.category = "";
03893 }
03894 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03895 idata.flag = "";
03896 }
03897 }
03898 fdlen = lseek(fd, 0, SEEK_END);
03899 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03900 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03901 res = -1;
03902 break;
03903 }
03904 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03905 if (fdm == MAP_FAILED) {
03906 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03907 res = -1;
03908 break;
03909 }
03910 idata.data = fdm;
03911 idata.datalen = idata.indlen = fdlen;
03912
03913 if (!ast_strlen_zero(idata.category))
03914 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03915 else
03916 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03917
03918 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03919 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03920 } else {
03921 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03922 res = -1;
03923 }
03924 } while (0);
03925 if (obj) {
03926 ast_odbc_release_obj(obj);
03927 }
03928 if (valid_config(cfg))
03929 ast_config_destroy(cfg);
03930 if (fdm != MAP_FAILED)
03931 munmap(fdm, fdlen);
03932 if (fd > -1)
03933 close(fd);
03934 return res;
03935 }
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03951 {
03952 SQLHSTMT stmt;
03953 char sql[PATH_MAX];
03954 char msgnums[20];
03955 char msgnumd[20];
03956 struct odbc_obj *obj;
03957 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03958 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03959
03960 delete_file(ddir, dmsg);
03961 obj = ast_odbc_request_obj(odbc_database, 0);
03962 if (obj) {
03963 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03964 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03965 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03966 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03967 if (!stmt)
03968 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03969 else
03970 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03971 ast_odbc_release_obj(obj);
03972 } else
03973 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03974 return;
03975 }
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988 static int remove_file(char *dir, int msgnum)
03989 {
03990 char fn[PATH_MAX];
03991 char full_fn[PATH_MAX];
03992 char msgnums[80];
03993
03994 if (msgnum > -1) {
03995 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03996 make_file(fn, sizeof(fn), dir, msgnum);
03997 } else
03998 ast_copy_string(fn, dir, sizeof(fn));
03999 ast_filedelete(fn, NULL);
04000 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
04001 unlink(full_fn);
04002 return 0;
04003 }
04004 #else
04005 #ifndef IMAP_STORAGE
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015 static int count_messages(struct ast_vm_user *vmu, char *dir)
04016 {
04017
04018 int vmcount = 0;
04019 DIR *vmdir = NULL;
04020 struct dirent *vment = NULL;
04021
04022 if (vm_lock_path(dir))
04023 return ERROR_LOCK_PATH;
04024
04025 if ((vmdir = opendir(dir))) {
04026 while ((vment = readdir(vmdir))) {
04027 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04028 vmcount++;
04029 }
04030 }
04031 closedir(vmdir);
04032 }
04033 ast_unlock_path(dir);
04034
04035 return vmcount;
04036 }
04037
04038
04039
04040
04041
04042
04043
04044
04045 static void rename_file(char *sfn, char *dfn)
04046 {
04047 char stxt[PATH_MAX];
04048 char dtxt[PATH_MAX];
04049 ast_filerename(sfn, dfn, NULL);
04050 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04051 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04052 if (ast_check_realtime("voicemail_data")) {
04053 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04054 }
04055 rename(stxt, dtxt);
04056 }
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04070 {
04071 int x;
04072 unsigned char map[MAXMSGLIMIT] = "";
04073 DIR *msgdir;
04074 struct dirent *msgdirent;
04075 int msgdirint;
04076 char extension[4];
04077 int stopcount = 0;
04078
04079
04080
04081
04082
04083 if (!(msgdir = opendir(dir))) {
04084 return -1;
04085 }
04086
04087 while ((msgdirent = readdir(msgdir))) {
04088 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04089 map[msgdirint] = 1;
04090 stopcount++;
04091 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04092 }
04093 }
04094 closedir(msgdir);
04095
04096 for (x = 0; x < vmu->maxmsg; x++) {
04097 if (map[x] == 1) {
04098 stopcount--;
04099 } else if (map[x] == 0 && !stopcount) {
04100 break;
04101 }
04102 }
04103
04104 return x - 1;
04105 }
04106
04107 #endif
04108 #endif
04109 #ifndef IMAP_STORAGE
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120 static int copy(char *infile, char *outfile)
04121 {
04122 int ifd;
04123 int ofd;
04124 int res;
04125 int len;
04126 char buf[4096];
04127
04128 #ifdef HARDLINK_WHEN_POSSIBLE
04129
04130 if (link(infile, outfile)) {
04131 #endif
04132 if ((ifd = open(infile, O_RDONLY)) < 0) {
04133 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04134 return -1;
04135 }
04136 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04137 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04138 close(ifd);
04139 return -1;
04140 }
04141 do {
04142 len = read(ifd, buf, sizeof(buf));
04143 if (len < 0) {
04144 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04145 close(ifd);
04146 close(ofd);
04147 unlink(outfile);
04148 } else if (len) {
04149 res = write(ofd, buf, len);
04150 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04151 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04152 close(ifd);
04153 close(ofd);
04154 unlink(outfile);
04155 }
04156 }
04157 } while (len);
04158 close(ifd);
04159 close(ofd);
04160 return 0;
04161 #ifdef HARDLINK_WHEN_POSSIBLE
04162 } else {
04163
04164 return 0;
04165 }
04166 #endif
04167 }
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178 static void copy_plain_file(char *frompath, char *topath)
04179 {
04180 char frompath2[PATH_MAX], topath2[PATH_MAX];
04181 struct ast_variable *tmp,*var = NULL;
04182 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04183 ast_filecopy(frompath, topath, NULL);
04184 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04185 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04186 if (ast_check_realtime("voicemail_data")) {
04187 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04188
04189 for (tmp = var; tmp; tmp = tmp->next) {
04190 if (!strcasecmp(tmp->name, "origmailbox")) {
04191 origmailbox = tmp->value;
04192 } else if (!strcasecmp(tmp->name, "context")) {
04193 context = tmp->value;
04194 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04195 macrocontext = tmp->value;
04196 } else if (!strcasecmp(tmp->name, "exten")) {
04197 exten = tmp->value;
04198 } else if (!strcasecmp(tmp->name, "priority")) {
04199 priority = tmp->value;
04200 } else if (!strcasecmp(tmp->name, "callerchan")) {
04201 callerchan = tmp->value;
04202 } else if (!strcasecmp(tmp->name, "callerid")) {
04203 callerid = tmp->value;
04204 } else if (!strcasecmp(tmp->name, "origdate")) {
04205 origdate = tmp->value;
04206 } else if (!strcasecmp(tmp->name, "origtime")) {
04207 origtime = tmp->value;
04208 } else if (!strcasecmp(tmp->name, "category")) {
04209 category = tmp->value;
04210 } else if (!strcasecmp(tmp->name, "duration")) {
04211 duration = tmp->value;
04212 }
04213 }
04214 ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
04215 }
04216 copy(frompath2, topath2);
04217 ast_variables_destroy(var);
04218 }
04219 #endif
04220
04221
04222
04223
04224
04225
04226
04227
04228
04229 static int vm_delete(char *file)
04230 {
04231 char *txt;
04232 int txtsize = 0;
04233
04234 txtsize = (strlen(file) + 5)*sizeof(char);
04235 txt = ast_alloca(txtsize);
04236
04237
04238
04239 if (ast_check_realtime("voicemail_data")) {
04240 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04241 }
04242 snprintf(txt, txtsize, "%s.txt", file);
04243 unlink(txt);
04244 return ast_filedelete(file, NULL);
04245 }
04246
04247
04248
04249
04250 static int inbuf(struct baseio *bio, FILE *fi)
04251 {
04252 int l;
04253
04254 if (bio->ateof)
04255 return 0;
04256
04257 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04258 if (ferror(fi))
04259 return -1;
04260
04261 bio->ateof = 1;
04262 return 0;
04263 }
04264
04265 bio->iolen = l;
04266 bio->iocp = 0;
04267
04268 return 1;
04269 }
04270
04271
04272
04273
04274 static int inchar(struct baseio *bio, FILE *fi)
04275 {
04276 if (bio->iocp>=bio->iolen) {
04277 if (!inbuf(bio, fi))
04278 return EOF;
04279 }
04280
04281 return bio->iobuf[bio->iocp++];
04282 }
04283
04284
04285
04286
04287 static int ochar(struct baseio *bio, int c, FILE *so)
04288 {
04289 if (bio->linelength >= BASELINELEN) {
04290 if (fputs(ENDL, so) == EOF) {
04291 return -1;
04292 }
04293
04294 bio->linelength = 0;
04295 }
04296
04297 if (putc(((unsigned char) c), so) == EOF) {
04298 return -1;
04299 }
04300
04301 bio->linelength++;
04302
04303 return 1;
04304 }
04305
04306
04307
04308
04309
04310
04311
04312
04313
04314
04315 static int base_encode(char *filename, FILE *so)
04316 {
04317 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04318 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04319 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04320 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04321 int i, hiteof = 0;
04322 FILE *fi;
04323 struct baseio bio;
04324
04325 memset(&bio, 0, sizeof(bio));
04326 bio.iocp = BASEMAXINLINE;
04327
04328 if (!(fi = fopen(filename, "rb"))) {
04329 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04330 return -1;
04331 }
04332
04333 while (!hiteof){
04334 unsigned char igroup[3], ogroup[4];
04335 int c, n;
04336
04337 memset(igroup, 0, sizeof(igroup));
04338
04339 for (n = 0; n < 3; n++) {
04340 if ((c = inchar(&bio, fi)) == EOF) {
04341 hiteof = 1;
04342 break;
04343 }
04344
04345 igroup[n] = (unsigned char) c;
04346 }
04347
04348 if (n > 0) {
04349 ogroup[0]= dtable[igroup[0] >> 2];
04350 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04351 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04352 ogroup[3]= dtable[igroup[2] & 0x3F];
04353
04354 if (n < 3) {
04355 ogroup[3] = '=';
04356
04357 if (n < 2)
04358 ogroup[2] = '=';
04359 }
04360
04361 for (i = 0; i < 4; i++)
04362 ochar(&bio, ogroup[i], so);
04363 }
04364 }
04365
04366 fclose(fi);
04367
04368 if (fputs(ENDL, so) == EOF) {
04369 return 0;
04370 }
04371
04372 return 1;
04373 }
04374
04375 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
04376 {
04377 char callerid[256];
04378 char num[12];
04379 char fromdir[256], fromfile[256];
04380 struct ast_config *msg_cfg;
04381 const char *origcallerid, *origtime;
04382 char origcidname[80], origcidnum[80], origdate[80];
04383 int inttime;
04384 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04385
04386
04387 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04388 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04389 snprintf(num, sizeof(num), "%d", msgnum);
04390 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04391 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04392 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04393 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04394 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04395 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04396 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04397 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04398 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04399 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04400
04401
04402 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04403 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04404 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04405 strcat(fromfile, ".txt");
04406 }
04407 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04408 if (option_debug > 0) {
04409 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04410 }
04411 return;
04412 }
04413
04414 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04415 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04416 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04417 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04418 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04419 }
04420
04421 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04422 struct timeval tv = { inttime, };
04423 struct ast_tm tm;
04424 ast_localtime(&tv, &tm, NULL);
04425 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04426 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04427 }
04428 ast_config_destroy(msg_cfg);
04429 }
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04440 {
04441 const char *ptr;
04442
04443
04444 ast_str_set(buf, maxlen, "\"");
04445 for (ptr = from; *ptr; ptr++) {
04446 if (*ptr == '"' || *ptr == '\\') {
04447 ast_str_append(buf, maxlen, "\\%c", *ptr);
04448 } else {
04449 ast_str_append(buf, maxlen, "%c", *ptr);
04450 }
04451 }
04452 ast_str_append(buf, maxlen, "\"");
04453
04454 return ast_str_buffer(*buf);
04455 }
04456
04457
04458
04459
04460
04461 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04462 {
04463 const struct vm_zone *z = NULL;
04464 struct timeval t = ast_tvnow();
04465
04466
04467 if (!ast_strlen_zero(vmu->zonetag)) {
04468
04469 AST_LIST_LOCK(&zones);
04470 AST_LIST_TRAVERSE(&zones, z, list) {
04471 if (!strcmp(z->name, vmu->zonetag))
04472 break;
04473 }
04474 AST_LIST_UNLOCK(&zones);
04475 }
04476 ast_localtime(&t, tm, z ? z->timezone : NULL);
04477 return tm;
04478 }
04479
04480
04481
04482
04483
04484 static int check_mime(const char *str)
04485 {
04486 for (; *str; str++) {
04487 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04488 return 1;
04489 }
04490 }
04491 return 0;
04492 }
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04512 {
04513 struct ast_str *tmp = ast_str_alloca(80);
04514 int first_section = 1;
04515
04516 ast_str_reset(*end);
04517 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04518 for (; *start; start++) {
04519 int need_encoding = 0;
04520 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04521 need_encoding = 1;
04522 }
04523 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04524 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04525 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04526 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04527
04528 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04529 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04530 first_section = 0;
04531 }
04532 if (need_encoding && *start == ' ') {
04533 ast_str_append(&tmp, -1, "_");
04534 } else if (need_encoding) {
04535 ast_str_append(&tmp, -1, "=%hhX", *start);
04536 } else {
04537 ast_str_append(&tmp, -1, "%c", *start);
04538 }
04539 }
04540 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04541 return ast_str_buffer(*end);
04542 }
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566
04567 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
04568 {
04569 char date[256];
04570 char host[MAXHOSTNAMELEN] = "";
04571 char who[256];
04572 char bound[256];
04573 char dur[256];
04574 struct ast_tm tm;
04575 char enc_cidnum[256] = "", enc_cidname[256] = "";
04576 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04577 char *greeting_attachment;
04578 char filename[256];
04579
04580 if (!str1 || !str2) {
04581 ast_free(str1);
04582 ast_free(str2);
04583 return;
04584 }
04585
04586 if (cidnum) {
04587 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04588 }
04589 if (cidname) {
04590 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04591 }
04592 gethostname(host, sizeof(host) - 1);
04593
04594 if (strchr(srcemail, '@')) {
04595 ast_copy_string(who, srcemail, sizeof(who));
04596 } else {
04597 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04598 }
04599
04600 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04601 if (greeting_attachment) {
04602 *greeting_attachment++ = '\0';
04603 }
04604
04605 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04606 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04607 fprintf(p, "Date: %s" ENDL, date);
04608
04609
04610 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04611
04612 if (!ast_strlen_zero(fromstring)) {
04613 struct ast_channel *ast;
04614 if ((ast = ast_dummy_channel_alloc())) {
04615 char *ptr;
04616 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04617 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04618
04619 if (check_mime(ast_str_buffer(str1))) {
04620 int first_line = 1;
04621 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04622 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04623 *ptr = '\0';
04624 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04625 first_line = 0;
04626
04627 ast_str_set(&str2, 0, "%s", ptr + 1);
04628 }
04629 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04630 } else {
04631 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04632 }
04633 ast = ast_channel_unref(ast);
04634 } else {
04635 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04636 }
04637 } else {
04638 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04639 }
04640
04641 if (check_mime(vmu->fullname)) {
04642 int first_line = 1;
04643 char *ptr;
04644 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04645 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04646 *ptr = '\0';
04647 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04648 first_line = 0;
04649
04650 ast_str_set(&str2, 0, "%s", ptr + 1);
04651 }
04652 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04653 } else {
04654 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04655 }
04656
04657 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04658 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04659 struct ast_channel *ast;
04660 if ((ast = ast_dummy_channel_alloc())) {
04661 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04662 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04663 if (check_mime(ast_str_buffer(str1))) {
04664 int first_line = 1;
04665 char *ptr;
04666 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04667 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04668 *ptr = '\0';
04669 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04670 first_line = 0;
04671
04672 ast_str_set(&str2, 0, "%s", ptr + 1);
04673 }
04674 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04675 } else {
04676 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04677 }
04678 ast = ast_channel_unref(ast);
04679 } else {
04680 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04681 }
04682 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04683 if (ast_strlen_zero(flag)) {
04684 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04685 } else {
04686 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04687 }
04688 } else {
04689 if (ast_strlen_zero(flag)) {
04690 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04691 } else {
04692 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04693 }
04694 }
04695
04696 fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
04697 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04698 if (imap) {
04699
04700 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04701
04702 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04703 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04704 #ifdef IMAP_STORAGE
04705 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04706 #else
04707 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04708 #endif
04709
04710 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04711 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04712 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04713 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04714 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04715 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04716 if (!ast_strlen_zero(category)) {
04717 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04718 } else {
04719 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04720 }
04721 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04722 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04723 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04724 }
04725 if (!ast_strlen_zero(cidnum)) {
04726 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04727 }
04728 if (!ast_strlen_zero(cidname)) {
04729 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04730 }
04731 fprintf(p, "MIME-Version: 1.0" ENDL);
04732 if (attach_user_voicemail) {
04733
04734 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
04735 (int) getpid(), (unsigned int) ast_random());
04736
04737 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04738 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04739 fprintf(p, "--%s" ENDL, bound);
04740 }
04741 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04742 if (emailbody || vmu->emailbody) {
04743 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04744 struct ast_channel *ast;
04745 if ((ast = ast_dummy_channel_alloc())) {
04746 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04747 ast_str_substitute_variables(&str1, 0, ast, e_body);
04748 #ifdef IMAP_STORAGE
04749 {
04750
04751 char *line = ast_str_buffer(str1), *next;
04752 do {
04753
04754 if ((next = strchr(line, '\n'))) {
04755 *next++ = '\0';
04756 }
04757 fprintf(p, "%s" ENDL, line);
04758 line = next;
04759 } while (!ast_strlen_zero(line));
04760 }
04761 #else
04762 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04763 #endif
04764 ast = ast_channel_unref(ast);
04765 } else {
04766 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04767 }
04768 } else if (msgnum > -1) {
04769 if (strcmp(vmu->mailbox, mailbox)) {
04770
04771 struct ast_config *msg_cfg;
04772 const char *v;
04773 int inttime;
04774 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04775 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04776
04777 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04778 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04779 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04780 strcat(fromfile, ".txt");
04781 }
04782 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
04783 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04784 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04785 }
04786
04787
04788
04789 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04790 struct timeval tv = { inttime, };
04791 struct ast_tm tm;
04792 ast_localtime(&tv, &tm, NULL);
04793 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04794 }
04795 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04796 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04797 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04798 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04799 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04800 date, origcallerid, origdate);
04801 ast_config_destroy(msg_cfg);
04802 } else {
04803 goto plain_message;
04804 }
04805 } else {
04806 plain_message:
04807 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04808 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04809 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04810 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04811 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04812 }
04813 } else {
04814 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04815 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04816 }
04817
04818 if (imap || attach_user_voicemail) {
04819 if (!ast_strlen_zero(attach2)) {
04820 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04821 ast_debug(5, "creating second attachment filename %s\n", filename);
04822 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04823 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04824 ast_debug(5, "creating attachment filename %s\n", filename);
04825 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04826 } else {
04827 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04828 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04829 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04830 }
04831 }
04832 ast_free(str1);
04833 ast_free(str2);
04834 }
04835
04836 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
04837 {
04838 char tmpdir[256], newtmp[256];
04839 char fname[256];
04840 char tmpcmd[256];
04841 int tmpfd = -1;
04842 int soxstatus = 0;
04843
04844
04845 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04846
04847 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04848 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04849 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04850 tmpfd = mkstemp(newtmp);
04851 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04852 ast_debug(3, "newtmp: %s\n", newtmp);
04853 if (tmpfd > -1) {
04854 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04855 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04856 attach = newtmp;
04857 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04858 } else {
04859 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04860 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04861 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04862 }
04863 }
04864 }
04865 fprintf(p, "--%s" ENDL, bound);
04866 if (msgnum > -1)
04867 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04868 else
04869 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04870 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04871 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04872 if (msgnum > -1)
04873 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04874 else
04875 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04876 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04877 base_encode(fname, p);
04878 if (last)
04879 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04880 if (tmpfd > -1) {
04881 if (soxstatus == 0) {
04882 unlink(fname);
04883 }
04884 close(tmpfd);
04885 unlink(newtmp);
04886 }
04887 return 0;
04888 }
04889
04890 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
04891 {
04892 FILE *p = NULL;
04893 char tmp[80] = "/tmp/astmail-XXXXXX";
04894 char tmp2[256];
04895 char *stringp;
04896
04897 if (vmu && ast_strlen_zero(vmu->email)) {
04898 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04899 return(0);
04900 }
04901
04902
04903 format = ast_strdupa(format);
04904 stringp = format;
04905 strsep(&stringp, "|");
04906
04907 if (!strcmp(format, "wav49"))
04908 format = "WAV";
04909 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04910
04911
04912 if ((p = vm_mkftemp(tmp)) == NULL) {
04913 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04914 return -1;
04915 } else {
04916 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04917 fclose(p);
04918 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04919 ast_safe_system(tmp2);
04920 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04921 }
04922 return 0;
04923 }
04924
04925 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
04926 {
04927 char enc_cidnum[256], enc_cidname[256];
04928 char date[256];
04929 char host[MAXHOSTNAMELEN] = "";
04930 char who[256];
04931 char dur[PATH_MAX];
04932 char tmp[80] = "/tmp/astmail-XXXXXX";
04933 char tmp2[PATH_MAX];
04934 struct ast_tm tm;
04935 FILE *p;
04936 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04937
04938 if (!str1 || !str2) {
04939 ast_free(str1);
04940 ast_free(str2);
04941 return -1;
04942 }
04943
04944 if (cidnum) {
04945 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04946 }
04947 if (cidname) {
04948 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04949 }
04950
04951 if ((p = vm_mkftemp(tmp)) == NULL) {
04952 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04953 ast_free(str1);
04954 ast_free(str2);
04955 return -1;
04956 }
04957 gethostname(host, sizeof(host)-1);
04958 if (strchr(srcemail, '@')) {
04959 ast_copy_string(who, srcemail, sizeof(who));
04960 } else {
04961 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04962 }
04963 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04964 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04965 fprintf(p, "Date: %s\n", date);
04966
04967
04968 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04969
04970 if (!ast_strlen_zero(pagerfromstring)) {
04971 struct ast_channel *ast;
04972 if ((ast = ast_dummy_channel_alloc())) {
04973 char *ptr;
04974 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04975 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04976
04977 if (check_mime(ast_str_buffer(str1))) {
04978 int first_line = 1;
04979 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04980 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04981 *ptr = '\0';
04982 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04983 first_line = 0;
04984
04985 ast_str_set(&str2, 0, "%s", ptr + 1);
04986 }
04987 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04988 } else {
04989 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04990 }
04991 ast = ast_channel_unref(ast);
04992 } else {
04993 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04994 }
04995 } else {
04996 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04997 }
04998
04999 if (check_mime(vmu->fullname)) {
05000 int first_line = 1;
05001 char *ptr;
05002 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
05003 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05004 *ptr = '\0';
05005 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
05006 first_line = 0;
05007
05008 ast_str_set(&str2, 0, "%s", ptr + 1);
05009 }
05010 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
05011 } else {
05012 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05013 }
05014
05015 if (!ast_strlen_zero(pagersubject)) {
05016 struct ast_channel *ast;
05017 if ((ast = ast_dummy_channel_alloc())) {
05018 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05019 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05020 if (check_mime(ast_str_buffer(str1))) {
05021 int first_line = 1;
05022 char *ptr;
05023 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05024 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05025 *ptr = '\0';
05026 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05027 first_line = 0;
05028
05029 ast_str_set(&str2, 0, "%s", ptr + 1);
05030 }
05031 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05032 } else {
05033 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05034 }
05035 ast = ast_channel_unref(ast);
05036 } else {
05037 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05038 }
05039 } else {
05040 if (ast_strlen_zero(flag)) {
05041 fprintf(p, "Subject: New VM\n\n");
05042 } else {
05043 fprintf(p, "Subject: New %s VM\n\n", flag);
05044 }
05045 }
05046
05047 if (pagerbody) {
05048 struct ast_channel *ast;
05049 if ((ast = ast_dummy_channel_alloc())) {
05050 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05051 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05052 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05053 ast = ast_channel_unref(ast);
05054 } else {
05055 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05056 }
05057 } else {
05058 fprintf(p, "New %s long %s msg in box %s\n"
05059 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05060 }
05061
05062 fclose(p);
05063 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05064 ast_safe_system(tmp2);
05065 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05066 ast_free(str1);
05067 ast_free(str2);
05068 return 0;
05069 }
05070
05071
05072
05073
05074
05075
05076
05077
05078
05079
05080 static int get_date(char *s, int len)
05081 {
05082 struct ast_tm tm;
05083 struct timeval t = ast_tvnow();
05084
05085 ast_localtime(&t, &tm, "UTC");
05086
05087 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05088 }
05089
05090 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05091 {
05092 int res;
05093 char fn[PATH_MAX];
05094 char dest[PATH_MAX];
05095
05096 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05097
05098 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05099 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05100 return -1;
05101 }
05102
05103 RETRIEVE(fn, -1, ext, context);
05104 if (ast_fileexists(fn, NULL, NULL) > 0) {
05105 res = ast_stream_and_wait(chan, fn, ecodes);
05106 if (res) {
05107 DISPOSE(fn, -1);
05108 return res;
05109 }
05110 } else {
05111
05112 DISPOSE(fn, -1);
05113 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05114 if (res)
05115 return res;
05116 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05117 if (res)
05118 return res;
05119 }
05120 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05121 return res;
05122 }
05123
05124 static void free_zone(struct vm_zone *z)
05125 {
05126 ast_free(z);
05127 }
05128
05129 #ifdef ODBC_STORAGE
05130 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05131 {
05132 int x = -1;
05133 int res;
05134 SQLHSTMT stmt = NULL;
05135 char sql[PATH_MAX];
05136 char rowdata[20];
05137 char tmp[PATH_MAX] = "";
05138 struct odbc_obj *obj = NULL;
05139 char *context;
05140 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05141
05142 if (newmsgs)
05143 *newmsgs = 0;
05144 if (oldmsgs)
05145 *oldmsgs = 0;
05146 if (urgentmsgs)
05147 *urgentmsgs = 0;
05148
05149
05150 if (ast_strlen_zero(mailbox))
05151 return 0;
05152
05153 ast_copy_string(tmp, mailbox, sizeof(tmp));
05154
05155 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05156 int u, n, o;
05157 char *next, *remaining = tmp;
05158 while ((next = strsep(&remaining, " ,"))) {
05159 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05160 return -1;
05161 }
05162 if (urgentmsgs) {
05163 *urgentmsgs += u;
05164 }
05165 if (newmsgs) {
05166 *newmsgs += n;
05167 }
05168 if (oldmsgs) {
05169 *oldmsgs += o;
05170 }
05171 }
05172 return 0;
05173 }
05174
05175 context = strchr(tmp, '@');
05176 if (context) {
05177 *context = '\0';
05178 context++;
05179 } else
05180 context = "default";
05181
05182 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05183 do {
05184 if (newmsgs) {
05185 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05186 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05187 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05188 break;
05189 }
05190 res = SQLFetch(stmt);
05191 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05192 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05193 break;
05194 }
05195 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05196 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05197 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05198 break;
05199 }
05200 *newmsgs = atoi(rowdata);
05201 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05202 }
05203
05204 if (oldmsgs) {
05205 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05206 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05207 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05208 break;
05209 }
05210 res = SQLFetch(stmt);
05211 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05212 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05213 break;
05214 }
05215 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05216 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05217 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05218 break;
05219 }
05220 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05221 *oldmsgs = atoi(rowdata);
05222 }
05223
05224 if (urgentmsgs) {
05225 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05226 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05227 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05228 break;
05229 }
05230 res = SQLFetch(stmt);
05231 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05232 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05233 break;
05234 }
05235 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05236 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05237 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05238 break;
05239 }
05240 *urgentmsgs = atoi(rowdata);
05241 }
05242
05243 x = 0;
05244 } while (0);
05245 } else {
05246 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05247 }
05248
05249 if (stmt) {
05250 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05251 }
05252 if (obj) {
05253 ast_odbc_release_obj(obj);
05254 }
05255 return x;
05256 }
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266
05267 static int messagecount(const char *context, const char *mailbox, const char *folder)
05268 {
05269 struct odbc_obj *obj = NULL;
05270 int nummsgs = 0;
05271 int res;
05272 SQLHSTMT stmt = NULL;
05273 char sql[PATH_MAX];
05274 char rowdata[20];
05275 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05276 if (!folder)
05277 folder = "INBOX";
05278
05279 if (ast_strlen_zero(mailbox))
05280 return 0;
05281
05282 obj = ast_odbc_request_obj(odbc_database, 0);
05283 if (obj) {
05284 if (!strcmp(folder, "INBOX")) {
05285 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
05286 } else {
05287 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05288 }
05289 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05290 if (!stmt) {
05291 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05292 goto yuck;
05293 }
05294 res = SQLFetch(stmt);
05295 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05296 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05297 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05298 goto yuck;
05299 }
05300 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05301 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05302 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05303 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05304 goto yuck;
05305 }
05306 nummsgs = atoi(rowdata);
05307 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05308 } else
05309 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05310
05311 yuck:
05312 if (obj)
05313 ast_odbc_release_obj(obj);
05314 return nummsgs;
05315 }
05316
05317
05318
05319
05320
05321
05322
05323
05324
05325 static int has_voicemail(const char *mailbox, const char *folder)
05326 {
05327 char tmp[256], *tmp2 = tmp, *box, *context;
05328 ast_copy_string(tmp, mailbox, sizeof(tmp));
05329 while ((context = box = strsep(&tmp2, ",&"))) {
05330 strsep(&context, "@");
05331 if (ast_strlen_zero(context))
05332 context = "default";
05333 if (messagecount(context, box, folder))
05334 return 1;
05335 }
05336 return 0;
05337 }
05338 #endif
05339 #ifndef IMAP_STORAGE
05340
05341
05342
05343
05344
05345
05346
05347
05348
05349
05350
05351
05352
05353
05354
05355
05356 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, const char *flag)
05357 {
05358 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05359 const char *frombox = mbox(vmu, imbox);
05360 const char *userfolder;
05361 int recipmsgnum;
05362 int res = 0;
05363
05364 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05365
05366 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05367 userfolder = "Urgent";
05368 } else {
05369 userfolder = "INBOX";
05370 }
05371
05372 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05373
05374 if (!dir)
05375 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05376 else
05377 ast_copy_string(fromdir, dir, sizeof(fromdir));
05378
05379 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05380 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05381
05382 if (vm_lock_path(todir))
05383 return ERROR_LOCK_PATH;
05384
05385 recipmsgnum = last_message_index(recip, todir) + 1;
05386 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05387 make_file(topath, sizeof(topath), todir, recipmsgnum);
05388 #ifndef ODBC_STORAGE
05389 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05390 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05391 } else {
05392 #endif
05393
05394
05395
05396 copy_plain_file(frompath, topath);
05397 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05398 vm_delete(topath);
05399 #ifndef ODBC_STORAGE
05400 }
05401 #endif
05402 } else {
05403 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05404 res = -1;
05405 }
05406 ast_unlock_path(todir);
05407 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05408 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05409 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05410 flag);
05411
05412 return res;
05413 }
05414 #endif
05415 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05416
05417 static int messagecount(const char *context, const char *mailbox, const char *folder)
05418 {
05419 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05420 }
05421
05422 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05423 {
05424 DIR *dir;
05425 struct dirent *de;
05426 char fn[256];
05427 int ret = 0;
05428
05429
05430 if (ast_strlen_zero(mailbox))
05431 return 0;
05432
05433 if (ast_strlen_zero(folder))
05434 folder = "INBOX";
05435 if (ast_strlen_zero(context))
05436 context = "default";
05437
05438 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05439
05440 if (!(dir = opendir(fn)))
05441 return 0;
05442
05443 while ((de = readdir(dir))) {
05444 if (!strncasecmp(de->d_name, "msg", 3)) {
05445 if (shortcircuit) {
05446 ret = 1;
05447 break;
05448 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05449 ret++;
05450 }
05451 }
05452 }
05453
05454 closedir(dir);
05455
05456 return ret;
05457 }
05458
05459
05460
05461
05462
05463
05464
05465
05466
05467
05468 static int has_voicemail(const char *mailbox, const char *folder)
05469 {
05470 char tmp[256], *tmp2 = tmp, *box, *context;
05471 ast_copy_string(tmp, mailbox, sizeof(tmp));
05472 if (ast_strlen_zero(folder)) {
05473 folder = "INBOX";
05474 }
05475 while ((box = strsep(&tmp2, ",&"))) {
05476 if ((context = strchr(box, '@')))
05477 *context++ = '\0';
05478 else
05479 context = "default";
05480 if (__has_voicemail(context, box, folder, 1))
05481 return 1;
05482
05483 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05484 return 1;
05485 }
05486 }
05487 return 0;
05488 }
05489
05490
05491 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05492 {
05493 char tmp[256];
05494 char *context;
05495
05496
05497 if (ast_strlen_zero(mailbox))
05498 return 0;
05499
05500 if (newmsgs)
05501 *newmsgs = 0;
05502 if (oldmsgs)
05503 *oldmsgs = 0;
05504 if (urgentmsgs)
05505 *urgentmsgs = 0;
05506
05507 if (strchr(mailbox, ',')) {
05508 int tmpnew, tmpold, tmpurgent;
05509 char *mb, *cur;
05510
05511 ast_copy_string(tmp, mailbox, sizeof(tmp));
05512 mb = tmp;
05513 while ((cur = strsep(&mb, ", "))) {
05514 if (!ast_strlen_zero(cur)) {
05515 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05516 return -1;
05517 else {
05518 if (newmsgs)
05519 *newmsgs += tmpnew;
05520 if (oldmsgs)
05521 *oldmsgs += tmpold;
05522 if (urgentmsgs)
05523 *urgentmsgs += tmpurgent;
05524 }
05525 }
05526 }
05527 return 0;
05528 }
05529
05530 ast_copy_string(tmp, mailbox, sizeof(tmp));
05531
05532 if ((context = strchr(tmp, '@')))
05533 *context++ = '\0';
05534 else
05535 context = "default";
05536
05537 if (newmsgs)
05538 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05539 if (oldmsgs)
05540 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05541 if (urgentmsgs)
05542 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05543
05544 return 0;
05545 }
05546
05547 #endif
05548
05549
05550 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05551 {
05552 int urgentmsgs = 0;
05553 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05554 if (newmsgs) {
05555 *newmsgs += urgentmsgs;
05556 }
05557 return res;
05558 }
05559
05560 static void run_externnotify(char *context, char *extension, const char *flag)
05561 {
05562 char arguments[255];
05563 char ext_context[256] = "";
05564 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05565 struct ast_smdi_mwi_message *mwi_msg;
05566
05567 if (!ast_strlen_zero(context))
05568 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05569 else
05570 ast_copy_string(ext_context, extension, sizeof(ext_context));
05571
05572 if (smdi_iface) {
05573 if (ast_app_has_voicemail(ext_context, NULL))
05574 ast_smdi_mwi_set(smdi_iface, extension);
05575 else
05576 ast_smdi_mwi_unset(smdi_iface, extension);
05577
05578 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05579 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05580 if (!strncmp(mwi_msg->cause, "INV", 3))
05581 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05582 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05583 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05584 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05585 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05586 } else {
05587 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05588 }
05589 }
05590
05591 if (!ast_strlen_zero(externnotify)) {
05592 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05593 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05594 } else {
05595 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05596 externnotify, S_OR(context, "\"\""),
05597 extension, newvoicemails,
05598 oldvoicemails, urgentvoicemails);
05599 ast_debug(1, "Executing %s\n", arguments);
05600 ast_safe_system(arguments);
05601 }
05602 }
05603 }
05604
05605
05606
05607
05608
05609
05610 struct leave_vm_options {
05611 unsigned int flags;
05612 signed char record_gain;
05613 char *exitcontext;
05614 };
05615
05616
05617
05618
05619
05620
05621
05622
05623
05624
05625
05626 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05627 {
05628 #ifdef IMAP_STORAGE
05629 int newmsgs, oldmsgs;
05630 #else
05631 char urgdir[PATH_MAX];
05632 #endif
05633 char txtfile[PATH_MAX];
05634 char tmptxtfile[PATH_MAX];
05635 struct vm_state *vms = NULL;
05636 char callerid[256];
05637 FILE *txt;
05638 char date[256];
05639 int txtdes;
05640 int res = 0;
05641 int msgnum;
05642 int duration = 0;
05643 int sound_duration = 0;
05644 int ausemacro = 0;
05645 int ousemacro = 0;
05646 int ouseexten = 0;
05647 char tmpdur[16];
05648 char priority[16];
05649 char origtime[16];
05650 char dir[PATH_MAX];
05651 char tmpdir[PATH_MAX];
05652 char fn[PATH_MAX];
05653 char prefile[PATH_MAX] = "";
05654 char tempfile[PATH_MAX] = "";
05655 char ext_context[256] = "";
05656 char fmt[80];
05657 char *context;
05658 char ecodes[17] = "#";
05659 struct ast_str *tmp = ast_str_create(16);
05660 char *tmpptr;
05661 struct ast_vm_user *vmu;
05662 struct ast_vm_user svm;
05663 const char *category = NULL;
05664 const char *code;
05665 const char *alldtmf = "0123456789ABCD*#";
05666 char flag[80];
05667
05668 if (!tmp) {
05669 return -1;
05670 }
05671
05672 ast_str_set(&tmp, 0, "%s", ext);
05673 ext = ast_str_buffer(tmp);
05674 if ((context = strchr(ext, '@'))) {
05675 *context++ = '\0';
05676 tmpptr = strchr(context, '&');
05677 } else {
05678 tmpptr = strchr(ext, '&');
05679 }
05680
05681 if (tmpptr)
05682 *tmpptr++ = '\0';
05683
05684 ast_channel_lock(chan);
05685 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05686 category = ast_strdupa(category);
05687 }
05688 ast_channel_unlock(chan);
05689
05690 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05691 ast_copy_string(flag, "Urgent", sizeof(flag));
05692 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05693 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05694 } else {
05695 flag[0] = '\0';
05696 }
05697
05698 ast_debug(3, "Before find_user\n");
05699 if (!(vmu = find_user(&svm, context, ext))) {
05700 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05701 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05702 ast_free(tmp);
05703 return res;
05704 }
05705
05706 if (strcmp(vmu->context, "default"))
05707 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05708 else
05709 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05710
05711
05712
05713
05714
05715
05716 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05717 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05718 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05719 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05720 }
05721
05722
05723
05724
05725 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05726 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05727 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05728 ast_free(tmp);
05729 return -1;
05730 }
05731 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05732 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05733 ast_copy_string(prefile, tempfile, sizeof(prefile));
05734
05735 DISPOSE(tempfile, -1);
05736
05737 #ifndef IMAP_STORAGE
05738 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05739 #else
05740 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05741 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05742 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05743 }
05744 #endif
05745
05746
05747 if (ast_test_flag(vmu, VM_OPERATOR)) {
05748 if (!ast_strlen_zero(vmu->exit)) {
05749 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05750 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05751 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05752 ouseexten = 1;
05753 }
05754 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05755 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05756 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05757 ouseexten = 1;
05758 } else if (!ast_strlen_zero(chan->macrocontext)
05759 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05760 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05761 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05762 ousemacro = 1;
05763 }
05764 }
05765
05766 if (!ast_strlen_zero(vmu->exit)) {
05767 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05768 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05769 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05770 }
05771 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05772 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05773 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05774 } else if (!ast_strlen_zero(chan->macrocontext)
05775 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05776 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05777 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05778 ausemacro = 1;
05779 }
05780
05781 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05782 for (code = alldtmf; *code; code++) {
05783 char e[2] = "";
05784 e[0] = *code;
05785 if (strchr(ecodes, e[0]) == NULL
05786 && ast_canmatch_extension(chan,
05787 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05788 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05789 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05790 }
05791 }
05792 }
05793
05794
05795 if (!ast_strlen_zero(prefile)) {
05796 #ifdef ODBC_STORAGE
05797 int success =
05798 #endif
05799 RETRIEVE(prefile, -1, ext, context);
05800 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05801 if (ast_streamfile(chan, prefile, chan->language) > -1)
05802 res = ast_waitstream(chan, ecodes);
05803 #ifdef ODBC_STORAGE
05804 if (success == -1) {
05805
05806 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05807 store_file(prefile, vmu->mailbox, vmu->context, -1);
05808 }
05809 #endif
05810 } else {
05811 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05812 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05813 }
05814 DISPOSE(prefile, -1);
05815 if (res < 0) {
05816 ast_debug(1, "Hang up during prefile playback\n");
05817 free_user(vmu);
05818 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05819 ast_free(tmp);
05820 return -1;
05821 }
05822 }
05823 if (res == '#') {
05824
05825 ast_set_flag(options, OPT_SILENT);
05826 res = 0;
05827 }
05828
05829 if (vmu->maxmsg == 0) {
05830 if (option_debug > 2)
05831 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05832 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05833 goto leave_vm_out;
05834 }
05835 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05836 res = ast_stream_and_wait(chan, INTRO, ecodes);
05837 if (res == '#') {
05838 ast_set_flag(options, OPT_SILENT);
05839 res = 0;
05840 }
05841 }
05842 if (res > 0)
05843 ast_stopstream(chan);
05844
05845
05846 if (res == '*') {
05847 chan->exten[0] = 'a';
05848 chan->exten[1] = '\0';
05849 if (!ast_strlen_zero(vmu->exit)) {
05850 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05851 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05852 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05853 }
05854 chan->priority = 0;
05855 free_user(vmu);
05856 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05857 ast_free(tmp);
05858 return 0;
05859 }
05860
05861
05862 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05863 transfer:
05864 if (ouseexten || ousemacro) {
05865 chan->exten[0] = 'o';
05866 chan->exten[1] = '\0';
05867 if (!ast_strlen_zero(vmu->exit)) {
05868 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05869 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05870 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05871 }
05872 ast_play_and_wait(chan, "transfer");
05873 chan->priority = 0;
05874 free_user(vmu);
05875 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05876 }
05877 ast_free(tmp);
05878 return OPERATOR_EXIT;
05879 }
05880
05881
05882 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05883 if (!ast_strlen_zero(options->exitcontext)) {
05884 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05885 }
05886 free_user(vmu);
05887 ast_free(tmp);
05888 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05889 return res;
05890 }
05891
05892 if (res < 0) {
05893 free_user(vmu);
05894 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05895 ast_free(tmp);
05896 return -1;
05897 }
05898
05899 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05900 if (!ast_strlen_zero(fmt)) {
05901 msgnum = 0;
05902
05903 #ifdef IMAP_STORAGE
05904
05905
05906 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05907 if (res < 0) {
05908 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05909 ast_free(tmp);
05910 return -1;
05911 }
05912 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05913
05914
05915
05916
05917 if (!(vms = create_vm_state_from_user(vmu))) {
05918 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05919 ast_free(tmp);
05920 return -1;
05921 }
05922 }
05923 vms->newmessages++;
05924
05925
05926 msgnum = newmsgs + oldmsgs;
05927 ast_debug(3, "Messagecount set to %d\n", msgnum);
05928 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05929
05930 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05931
05932 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05933 goto leave_vm_out;
05934 }
05935 #else
05936 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05937 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05938 if (!res)
05939 res = ast_waitstream(chan, "");
05940 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05941 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05942 inprocess_count(vmu->mailbox, vmu->context, -1);
05943 goto leave_vm_out;
05944 }
05945
05946 #endif
05947 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05948 txtdes = mkstemp(tmptxtfile);
05949 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05950 if (txtdes < 0) {
05951 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05952 if (!res)
05953 res = ast_waitstream(chan, "");
05954 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05955 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05956 inprocess_count(vmu->mailbox, vmu->context, -1);
05957 goto leave_vm_out;
05958 }
05959
05960
05961 if (res >= 0) {
05962
05963 res = ast_stream_and_wait(chan, "beep", "");
05964 }
05965
05966
05967 if (ast_check_realtime("voicemail_data")) {
05968 snprintf(priority, sizeof(priority), "%d", chan->priority);
05969 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05970 get_date(date, sizeof(date));
05971 ast_callerid_merge(callerid, sizeof(callerid),
05972 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05973 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05974 "Unknown");
05975 ast_store_realtime("voicemail_data",
05976 "origmailbox", ext,
05977 "context", chan->context,
05978 "macrocontext", chan->macrocontext,
05979 "exten", chan->exten,
05980 "priority", priority,
05981 "callerchan", chan->name,
05982 "callerid", callerid,
05983 "origdate", date,
05984 "origtime", origtime,
05985 "category", S_OR(category, ""),
05986 "filename", tmptxtfile,
05987 SENTINEL);
05988 }
05989
05990
05991 txt = fdopen(txtdes, "w+");
05992 if (txt) {
05993 get_date(date, sizeof(date));
05994 ast_callerid_merge(callerid, sizeof(callerid),
05995 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05996 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05997 "Unknown");
05998 fprintf(txt,
05999 ";\n"
06000 "; Message Information file\n"
06001 ";\n"
06002 "[message]\n"
06003 "origmailbox=%s\n"
06004 "context=%s\n"
06005 "macrocontext=%s\n"
06006 "exten=%s\n"
06007 "rdnis=%s\n"
06008 "priority=%d\n"
06009 "callerchan=%s\n"
06010 "callerid=%s\n"
06011 "origdate=%s\n"
06012 "origtime=%ld\n"
06013 "category=%s\n",
06014 ext,
06015 chan->context,
06016 chan->macrocontext,
06017 chan->exten,
06018 S_COR(chan->redirecting.from.number.valid,
06019 chan->redirecting.from.number.str, "unknown"),
06020 chan->priority,
06021 chan->name,
06022 callerid,
06023 date, (long) time(NULL),
06024 category ? category : "");
06025 } else {
06026 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06027 inprocess_count(vmu->mailbox, vmu->context, -1);
06028 if (ast_check_realtime("voicemail_data")) {
06029 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06030 }
06031 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06032 goto leave_vm_out;
06033 }
06034 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06035
06036 if (txt) {
06037 fprintf(txt, "flag=%s\n", flag);
06038 if (sound_duration < vmu->minsecs) {
06039 fclose(txt);
06040 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06041 ast_filedelete(tmptxtfile, NULL);
06042 unlink(tmptxtfile);
06043 if (ast_check_realtime("voicemail_data")) {
06044 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06045 }
06046 inprocess_count(vmu->mailbox, vmu->context, -1);
06047 } else {
06048 fprintf(txt, "duration=%d\n", duration);
06049 fclose(txt);
06050 if (vm_lock_path(dir)) {
06051 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06052
06053 ast_filedelete(tmptxtfile, NULL);
06054 unlink(tmptxtfile);
06055 inprocess_count(vmu->mailbox, vmu->context, -1);
06056 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06057 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06058 unlink(tmptxtfile);
06059 ast_unlock_path(dir);
06060 inprocess_count(vmu->mailbox, vmu->context, -1);
06061 if (ast_check_realtime("voicemail_data")) {
06062 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06063 }
06064 } else {
06065 #ifndef IMAP_STORAGE
06066 msgnum = last_message_index(vmu, dir) + 1;
06067 #endif
06068 make_file(fn, sizeof(fn), dir, msgnum);
06069
06070
06071 #ifndef IMAP_STORAGE
06072 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06073 #else
06074 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06075 #endif
06076
06077 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06078 ast_filerename(tmptxtfile, fn, NULL);
06079 rename(tmptxtfile, txtfile);
06080 inprocess_count(vmu->mailbox, vmu->context, -1);
06081
06082
06083
06084 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06085 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06086
06087 ast_unlock_path(dir);
06088 if (ast_check_realtime("voicemail_data")) {
06089 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06090 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06091 }
06092
06093
06094
06095 if (ast_fileexists(fn, NULL, NULL) > 0) {
06096 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06097 }
06098
06099
06100 while (tmpptr) {
06101 struct ast_vm_user recipu, *recip;
06102 char *exten, *cntx;
06103
06104 exten = strsep(&tmpptr, "&");
06105 cntx = strchr(exten, '@');
06106 if (cntx) {
06107 *cntx = '\0';
06108 cntx++;
06109 }
06110 if ((recip = find_user(&recipu, cntx, exten))) {
06111 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06112 free_user(recip);
06113 }
06114 }
06115 #ifndef IMAP_STORAGE
06116 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06117
06118 char sfn[PATH_MAX];
06119 char dfn[PATH_MAX];
06120 int x;
06121
06122 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06123 x = last_message_index(vmu, urgdir) + 1;
06124 make_file(sfn, sizeof(sfn), dir, msgnum);
06125 make_file(dfn, sizeof(dfn), urgdir, x);
06126 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06127 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06128
06129 ast_copy_string(fn, dfn, sizeof(fn));
06130 msgnum = x;
06131 }
06132 #endif
06133
06134 if (ast_fileexists(fn, NULL, NULL)) {
06135 #ifdef IMAP_STORAGE
06136 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06137 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06138 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06139 flag);
06140 #else
06141 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06142 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06143 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06144 flag);
06145 #endif
06146 }
06147
06148
06149 if (ast_fileexists(fn, NULL, NULL)) {
06150 DISPOSE(dir, msgnum);
06151 }
06152 }
06153 }
06154 } else {
06155 inprocess_count(vmu->mailbox, vmu->context, -1);
06156 }
06157 if (res == '0') {
06158 goto transfer;
06159 } else if (res > 0 && res != 't')
06160 res = 0;
06161
06162 if (sound_duration < vmu->minsecs)
06163
06164 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06165 else
06166 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06167 } else
06168 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06169 leave_vm_out:
06170 free_user(vmu);
06171
06172 #ifdef IMAP_STORAGE
06173
06174 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06175 if (expungeonhangup == 1) {
06176 ast_mutex_lock(&vms->lock);
06177 #ifdef HAVE_IMAP_TK2006
06178 if (LEVELUIDPLUS (vms->mailstream)) {
06179 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06180 } else
06181 #endif
06182 mail_expunge(vms->mailstream);
06183 ast_mutex_unlock(&vms->lock);
06184 }
06185 #endif
06186
06187 ast_free(tmp);
06188 return res;
06189 }
06190
06191 #if !defined(IMAP_STORAGE)
06192 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06193 {
06194
06195
06196 int x, dest;
06197 char sfn[PATH_MAX];
06198 char dfn[PATH_MAX];
06199
06200 if (vm_lock_path(dir)) {
06201 return ERROR_LOCK_PATH;
06202 }
06203
06204 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06205 make_file(sfn, sizeof(sfn), dir, x);
06206 if (EXISTS(dir, x, sfn, NULL)) {
06207
06208 if (x != dest) {
06209 make_file(dfn, sizeof(dfn), dir, dest);
06210 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06211 }
06212
06213 dest++;
06214 }
06215 }
06216 ast_unlock_path(dir);
06217
06218 return dest;
06219 }
06220 #endif
06221
06222 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06223 {
06224 int d;
06225 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06226 return d;
06227 }
06228
06229 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06230 {
06231 #ifdef IMAP_STORAGE
06232
06233
06234 char sequence[10];
06235 char mailbox[256];
06236 int res;
06237
06238
06239 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06240
06241 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06242 ast_mutex_lock(&vms->lock);
06243
06244 if (box == OLD_FOLDER) {
06245 mail_setflag(vms->mailstream, sequence, "\\Seen");
06246 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06247 } else if (box == NEW_FOLDER) {
06248 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06249 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06250 }
06251 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06252 ast_mutex_unlock(&vms->lock);
06253 return 0;
06254 }
06255
06256 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06257 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06258 if (mail_create(vms->mailstream, mailbox) == NIL)
06259 ast_debug(5, "Folder exists.\n");
06260 else
06261 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06262 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06263 ast_mutex_unlock(&vms->lock);
06264 return res;
06265 #else
06266 char *dir = vms->curdir;
06267 char *username = vms->username;
06268 char *context = vmu->context;
06269 char sfn[PATH_MAX];
06270 char dfn[PATH_MAX];
06271 char ddir[PATH_MAX];
06272 const char *dbox = mbox(vmu, box);
06273 int x, i;
06274 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06275
06276 if (vm_lock_path(ddir))
06277 return ERROR_LOCK_PATH;
06278
06279 x = last_message_index(vmu, ddir) + 1;
06280
06281 if (box == 10 && x >= vmu->maxdeletedmsg) {
06282 x--;
06283 for (i = 1; i <= x; i++) {
06284
06285 make_file(sfn, sizeof(sfn), ddir, i);
06286 make_file(dfn, sizeof(dfn), ddir, i - 1);
06287 if (EXISTS(ddir, i, sfn, NULL)) {
06288 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06289 } else
06290 break;
06291 }
06292 } else {
06293 if (x >= vmu->maxmsg) {
06294 ast_unlock_path(ddir);
06295 return -1;
06296 }
06297 }
06298 make_file(sfn, sizeof(sfn), dir, msg);
06299 make_file(dfn, sizeof(dfn), ddir, x);
06300 if (strcmp(sfn, dfn)) {
06301 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06302 }
06303 ast_unlock_path(ddir);
06304 #endif
06305 return 0;
06306 }
06307
06308 static int adsi_logo(unsigned char *buf)
06309 {
06310 int bytes = 0;
06311 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06312 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06313 return bytes;
06314 }
06315
06316 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06317 {
06318 unsigned char buf[256];
06319 int bytes = 0;
06320 int x;
06321 char num[5];
06322
06323 *useadsi = 0;
06324 bytes += ast_adsi_data_mode(buf + bytes);
06325 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06326
06327 bytes = 0;
06328 bytes += adsi_logo(buf);
06329 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06330 #ifdef DISPLAY
06331 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06332 #endif
06333 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06334 bytes += ast_adsi_data_mode(buf + bytes);
06335 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06336
06337 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06338 bytes = 0;
06339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06340 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06341 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06342 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06344 return 0;
06345 }
06346
06347 #ifdef DISPLAY
06348
06349 bytes = 0;
06350 bytes += ast_adsi_logo(buf);
06351 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06352 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06353 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06354 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06355 #endif
06356 bytes = 0;
06357 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06358 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06359 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06360 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06361 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06362 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06363 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06364
06365 #ifdef DISPLAY
06366
06367 bytes = 0;
06368 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06369 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06370
06371 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06372 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06373 #endif
06374
06375 bytes = 0;
06376
06377 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06378 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06379 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06380 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06381 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06382 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06383 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06384
06385 #ifdef DISPLAY
06386
06387 bytes = 0;
06388 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06389 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06390 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06391 #endif
06392
06393 bytes = 0;
06394 for (x = 0; x < 5; x++) {
06395 snprintf(num, sizeof(num), "%d", x);
06396 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06397 }
06398 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06399 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06400
06401 #ifdef DISPLAY
06402
06403 bytes = 0;
06404 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06405 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06406 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06407 #endif
06408
06409 if (ast_adsi_end_download(chan)) {
06410 bytes = 0;
06411 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06412 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06413 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06414 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06415 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06416 return 0;
06417 }
06418 bytes = 0;
06419 bytes += ast_adsi_download_disconnect(buf + bytes);
06420 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06421 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06422
06423 ast_debug(1, "Done downloading scripts...\n");
06424
06425 #ifdef DISPLAY
06426
06427 bytes = 0;
06428 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06429 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06430 #endif
06431 ast_debug(1, "Restarting session...\n");
06432
06433 bytes = 0;
06434
06435 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06436 *useadsi = 1;
06437 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06438 } else
06439 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06440
06441 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06442 return 0;
06443 }
06444
06445 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06446 {
06447 int x;
06448 if (!ast_adsi_available(chan))
06449 return;
06450 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06451 if (x < 0)
06452 return;
06453 if (!x) {
06454 if (adsi_load_vmail(chan, useadsi)) {
06455 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06456 return;
06457 }
06458 } else
06459 *useadsi = 1;
06460 }
06461
06462 static void adsi_login(struct ast_channel *chan)
06463 {
06464 unsigned char buf[256];
06465 int bytes = 0;
06466 unsigned char keys[8];
06467 int x;
06468 if (!ast_adsi_available(chan))
06469 return;
06470
06471 for (x = 0; x < 8; x++)
06472 keys[x] = 0;
06473
06474 keys[3] = ADSI_KEY_APPS + 3;
06475
06476 bytes += adsi_logo(buf + bytes);
06477 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06478 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06479 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06480 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06481 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06482 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06483 bytes += ast_adsi_set_keys(buf + bytes, keys);
06484 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06485 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06486 }
06487
06488 static void adsi_password(struct ast_channel *chan)
06489 {
06490 unsigned char buf[256];
06491 int bytes = 0;
06492 unsigned char keys[8];
06493 int x;
06494 if (!ast_adsi_available(chan))
06495 return;
06496
06497 for (x = 0; x < 8; x++)
06498 keys[x] = 0;
06499
06500 keys[3] = ADSI_KEY_APPS + 3;
06501
06502 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06503 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06504 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06505 bytes += ast_adsi_set_keys(buf + bytes, keys);
06506 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06507 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06508 }
06509
06510 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06511 {
06512 unsigned char buf[256];
06513 int bytes = 0;
06514 unsigned char keys[8];
06515 int x, y;
06516
06517 if (!ast_adsi_available(chan))
06518 return;
06519
06520 for (x = 0; x < 5; x++) {
06521 y = ADSI_KEY_APPS + 12 + start + x;
06522 if (y > ADSI_KEY_APPS + 12 + 4)
06523 y = 0;
06524 keys[x] = ADSI_KEY_SKT | y;
06525 }
06526 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06527 keys[6] = 0;
06528 keys[7] = 0;
06529
06530 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06531 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06532 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06533 bytes += ast_adsi_set_keys(buf + bytes, keys);
06534 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06535
06536 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06537 }
06538
06539 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06540 {
06541 int bytes = 0;
06542 unsigned char buf[256];
06543 char buf1[256], buf2[256];
06544 char fn2[PATH_MAX];
06545
06546 char cid[256] = "";
06547 char *val;
06548 char *name, *num;
06549 char datetime[21] = "";
06550 FILE *f;
06551
06552 unsigned char keys[8];
06553
06554 int x;
06555
06556 if (!ast_adsi_available(chan))
06557 return;
06558
06559
06560 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06561 f = fopen(fn2, "r");
06562 if (f) {
06563 while (!feof(f)) {
06564 if (!fgets((char *) buf, sizeof(buf), f)) {
06565 continue;
06566 }
06567 if (!feof(f)) {
06568 char *stringp = NULL;
06569 stringp = (char *) buf;
06570 strsep(&stringp, "=");
06571 val = strsep(&stringp, "=");
06572 if (!ast_strlen_zero(val)) {
06573 if (!strcmp((char *) buf, "callerid"))
06574 ast_copy_string(cid, val, sizeof(cid));
06575 if (!strcmp((char *) buf, "origdate"))
06576 ast_copy_string(datetime, val, sizeof(datetime));
06577 }
06578 }
06579 }
06580 fclose(f);
06581 }
06582
06583 for (x = 0; x < 5; x++)
06584 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06585 keys[6] = 0x0;
06586 keys[7] = 0x0;
06587
06588 if (!vms->curmsg) {
06589
06590 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06591 }
06592 if (vms->curmsg >= vms->lastmsg) {
06593
06594 if (vms->curmsg) {
06595
06596 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06597 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06598
06599 } else {
06600
06601 keys[3] = 1;
06602 }
06603 }
06604
06605 if (!ast_strlen_zero(cid)) {
06606 ast_callerid_parse(cid, &name, &num);
06607 if (!name)
06608 name = num;
06609 } else
06610 name = "Unknown Caller";
06611
06612
06613 #ifdef IMAP_STORAGE
06614 ast_mutex_lock(&vms->lock);
06615 #endif
06616 if (vms->deleted[vms->curmsg]) {
06617 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06618 }
06619 #ifdef IMAP_STORAGE
06620 ast_mutex_unlock(&vms->lock);
06621 #endif
06622
06623
06624 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06625 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06626 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06627 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06628
06629 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06630 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06631 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06632 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06633 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06634 bytes += ast_adsi_set_keys(buf + bytes, keys);
06635 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06636
06637 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06638 }
06639
06640 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06641 {
06642 int bytes = 0;
06643 unsigned char buf[256];
06644 unsigned char keys[8];
06645
06646 int x;
06647
06648 if (!ast_adsi_available(chan))
06649 return;
06650
06651
06652 for (x = 0; x < 5; x++)
06653 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06654
06655 keys[6] = 0x0;
06656 keys[7] = 0x0;
06657
06658 if (!vms->curmsg) {
06659
06660 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06661 }
06662 if (vms->curmsg >= vms->lastmsg) {
06663
06664 if (vms->curmsg) {
06665
06666 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06667 } else {
06668
06669 keys[3] = 1;
06670 }
06671 }
06672
06673
06674 #ifdef IMAP_STORAGE
06675 ast_mutex_lock(&vms->lock);
06676 #endif
06677 if (vms->deleted[vms->curmsg]) {
06678 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06679 }
06680 #ifdef IMAP_STORAGE
06681 ast_mutex_unlock(&vms->lock);
06682 #endif
06683
06684
06685 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06686 bytes += ast_adsi_set_keys(buf + bytes, keys);
06687 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06688
06689 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06690 }
06691
06692 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06693 {
06694 unsigned char buf[256] = "";
06695 char buf1[256] = "", buf2[256] = "";
06696 int bytes = 0;
06697 unsigned char keys[8];
06698 int x;
06699
06700 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06701 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06702 if (!ast_adsi_available(chan))
06703 return;
06704 if (vms->newmessages) {
06705 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06706 if (vms->oldmessages) {
06707 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06708 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06709 } else {
06710 snprintf(buf2, sizeof(buf2), "%s.", newm);
06711 }
06712 } else if (vms->oldmessages) {
06713 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06714 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06715 } else {
06716 strcpy(buf1, "You have no messages.");
06717 buf2[0] = ' ';
06718 buf2[1] = '\0';
06719 }
06720 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06721 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06722 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06723
06724 for (x = 0; x < 6; x++)
06725 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06726 keys[6] = 0;
06727 keys[7] = 0;
06728
06729
06730 if (vms->lastmsg < 0)
06731 keys[0] = 1;
06732 bytes += ast_adsi_set_keys(buf + bytes, keys);
06733
06734 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06735
06736 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06737 }
06738
06739 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06740 {
06741 unsigned char buf[256] = "";
06742 char buf1[256] = "", buf2[256] = "";
06743 int bytes = 0;
06744 unsigned char keys[8];
06745 int x;
06746
06747 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06748
06749 if (!ast_adsi_available(chan))
06750 return;
06751
06752
06753 for (x = 0; x < 6; x++)
06754 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06755
06756 keys[6] = 0;
06757 keys[7] = 0;
06758
06759 if ((vms->lastmsg + 1) < 1)
06760 keys[0] = 0;
06761
06762 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06763 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06764
06765 if (vms->lastmsg + 1)
06766 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06767 else
06768 strcpy(buf2, "no messages.");
06769 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06770 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06771 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06772 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06773 bytes += ast_adsi_set_keys(buf + bytes, keys);
06774
06775 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06776
06777 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06778
06779 }
06780
06781
06782
06783
06784
06785
06786
06787
06788
06789
06790
06791
06792
06793
06794
06795 static void adsi_goodbye(struct ast_channel *chan)
06796 {
06797 unsigned char buf[256];
06798 int bytes = 0;
06799
06800 if (!ast_adsi_available(chan))
06801 return;
06802 bytes += adsi_logo(buf + bytes);
06803 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06804 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06805 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06806 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06807
06808 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06809 }
06810
06811
06812
06813
06814
06815 static int get_folder(struct ast_channel *chan, int start)
06816 {
06817 int x;
06818 int d;
06819 char fn[PATH_MAX];
06820 d = ast_play_and_wait(chan, "vm-press");
06821 if (d)
06822 return d;
06823 for (x = start; x < 5; x++) {
06824 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06825 return d;
06826 d = ast_play_and_wait(chan, "vm-for");
06827 if (d)
06828 return d;
06829 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06830
06831
06832
06833
06834 if (x == 0) {
06835 if (ast_fileexists(fn, NULL, NULL)) {
06836 d = vm_play_folder_name(chan, fn);
06837 } else {
06838 ast_verb(1, "failed to find %s\n", fn);
06839 d = vm_play_folder_name(chan, "vm-INBOX");
06840 }
06841 } else {
06842 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06843 d = vm_play_folder_name(chan, fn);
06844 }
06845
06846 if (d)
06847 return d;
06848 d = ast_waitfordigit(chan, 500);
06849 if (d)
06850 return d;
06851 }
06852
06853 d = ast_play_and_wait(chan, "vm-tocancel");
06854 if (d)
06855 return d;
06856 d = ast_waitfordigit(chan, 4000);
06857 return d;
06858 }
06859
06860
06861
06862
06863
06864
06865
06866
06867
06868
06869
06870
06871
06872 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06873 {
06874 int res = 0;
06875 int loops = 0;
06876
06877 res = ast_play_and_wait(chan, fn);
06878 while (((res < '0') || (res > '9')) &&
06879 (res != '#') && (res >= 0) &&
06880 loops < 4) {
06881 res = get_folder(chan, 0);
06882 loops++;
06883 }
06884 if (loops == 4) {
06885 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06886 return '#';
06887 }
06888 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06889 return res;
06890 }
06891
06892
06893
06894
06895
06896
06897
06898
06899
06900
06901
06902
06903
06904
06905
06906
06907
06908
06909
06910 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06911 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06912 {
06913 int cmd = 0;
06914 int retries = 0, prepend_duration = 0, already_recorded = 0;
06915 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06916 char textfile[PATH_MAX];
06917 struct ast_config *msg_cfg;
06918 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06919 #ifndef IMAP_STORAGE
06920 signed char zero_gain = 0;
06921 #endif
06922 const char *duration_str;
06923
06924
06925 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06926 strcpy(textfile, msgfile);
06927 strcpy(backup, msgfile);
06928 strcpy(backup_textfile, msgfile);
06929 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06930 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06931 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06932
06933 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06934 *duration = atoi(duration_str);
06935 } else {
06936 *duration = 0;
06937 }
06938
06939 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06940 if (cmd)
06941 retries = 0;
06942 switch (cmd) {
06943 case '1':
06944
06945 #ifdef IMAP_STORAGE
06946
06947 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06948 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06949 ast_play_and_wait(chan, INTRO);
06950 ast_play_and_wait(chan, "beep");
06951 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06952 if (cmd == -1) {
06953 break;
06954 }
06955 cmd = 't';
06956 #else
06957
06958
06959
06960 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06961 strcpy(textfile, msgfile);
06962 strncat(textfile, ".txt", sizeof(textfile) - 1);
06963 *duration = 0;
06964
06965
06966 if (!valid_config(msg_cfg)) {
06967 cmd = 0;
06968 break;
06969 }
06970
06971
06972 #ifndef IMAP_STORAGE
06973 if (already_recorded) {
06974 ast_filecopy(backup, msgfile, NULL);
06975 copy(backup_textfile, textfile);
06976 }
06977 else {
06978 ast_filecopy(msgfile, backup, NULL);
06979 copy(textfile, backup_textfile);
06980 }
06981 #endif
06982 already_recorded = 1;
06983
06984 if (record_gain)
06985 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06986
06987 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06988
06989 if (cmd == 'S') {
06990 ast_stream_and_wait(chan, vm_pls_try_again, "");
06991 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06992 ast_filerename(backup, msgfile, NULL);
06993 }
06994
06995 if (record_gain)
06996 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06997
06998
06999 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
07000 *duration = atoi(duration_str);
07001
07002 if (prepend_duration) {
07003 struct ast_category *msg_cat;
07004
07005 char duration_buf[12];
07006
07007 *duration += prepend_duration;
07008 msg_cat = ast_category_get(msg_cfg, "message");
07009 snprintf(duration_buf, 11, "%ld", *duration);
07010 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
07011 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
07012 }
07013 }
07014
07015 #endif
07016 break;
07017 case '2':
07018
07019 #ifdef IMAP_STORAGE
07020 *vms->introfn = '\0';
07021 #endif
07022 cmd = 't';
07023 break;
07024 case '*':
07025 cmd = '*';
07026 break;
07027 default:
07028
07029 already_recorded = 0;
07030
07031 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07032
07033 if (!cmd) {
07034 cmd = ast_play_and_wait(chan, "vm-starmain");
07035
07036 }
07037 if (!cmd) {
07038 cmd = ast_waitfordigit(chan, 6000);
07039 }
07040 if (!cmd) {
07041 retries++;
07042 }
07043 if (retries > 3) {
07044 cmd = '*';
07045 }
07046 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07047 }
07048 }
07049
07050 if (valid_config(msg_cfg))
07051 ast_config_destroy(msg_cfg);
07052 if (prepend_duration)
07053 *duration = prepend_duration;
07054
07055 if (already_recorded && cmd == -1) {
07056
07057 ast_filerename(backup, msgfile, NULL);
07058 rename(backup_textfile, textfile);
07059 }
07060
07061 if (cmd == 't' || cmd == 'S')
07062 cmd = 0;
07063 return cmd;
07064 }
07065
07066 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07067 {
07068 struct ast_event *event;
07069 char *mailbox, *context;
07070
07071
07072 context = mailbox = ast_strdupa(box);
07073 strsep(&context, "@");
07074 if (ast_strlen_zero(context))
07075 context = "default";
07076
07077 if (!(event = ast_event_new(AST_EVENT_MWI,
07078 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07079 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07080 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07081 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07082 AST_EVENT_IE_END))) {
07083 return;
07084 }
07085
07086 ast_event_queue_and_cache(event);
07087 }
07088
07089
07090
07091
07092
07093
07094
07095
07096
07097
07098
07099
07100
07101
07102
07103 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
07104 {
07105 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07106 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07107 const char *category;
07108 char *myserveremail = serveremail;
07109
07110 ast_channel_lock(chan);
07111 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07112 category = ast_strdupa(category);
07113 }
07114 ast_channel_unlock(chan);
07115
07116 #ifndef IMAP_STORAGE
07117 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07118 #else
07119 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07120 #endif
07121 make_file(fn, sizeof(fn), todir, msgnum);
07122 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07123
07124 if (!ast_strlen_zero(vmu->attachfmt)) {
07125 if (strstr(fmt, vmu->attachfmt))
07126 fmt = vmu->attachfmt;
07127 else
07128 ast_log(AST_LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
07129 }
07130
07131
07132 fmt = ast_strdupa(fmt);
07133 stringp = fmt;
07134 strsep(&stringp, "|");
07135
07136 if (!ast_strlen_zero(vmu->serveremail))
07137 myserveremail = vmu->serveremail;
07138
07139 if (!ast_strlen_zero(vmu->email)) {
07140 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07141
07142 if (attach_user_voicemail)
07143 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07144
07145
07146 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07147
07148 if (attach_user_voicemail)
07149 DISPOSE(todir, msgnum);
07150 }
07151
07152 if (!ast_strlen_zero(vmu->pager)) {
07153 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07154 }
07155
07156 if (ast_test_flag(vmu, VM_DELETE))
07157 DELETE(todir, msgnum, fn, vmu);
07158
07159
07160 if (ast_app_has_voicemail(ext_context, NULL))
07161 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07162
07163 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07164
07165 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
07166 run_externnotify(vmu->context, vmu->mailbox, flag);
07167
07168 #ifdef IMAP_STORAGE
07169 vm_delete(fn);
07170 if (ast_test_flag(vmu, VM_DELETE)) {
07171 vm_imap_delete(NULL, vms->curmsg, vmu);
07172 vms->newmessages--;
07173 }
07174 #endif
07175
07176 return 0;
07177 }
07178
07179
07180
07181
07182
07183
07184
07185
07186
07187
07188
07189
07190
07191
07192
07193
07194
07195
07196
07197
07198
07199
07200
07201
07202
07203
07204
07205
07206 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
07207 {
07208 #ifdef IMAP_STORAGE
07209 int todircount = 0;
07210 struct vm_state *dstvms;
07211 #endif
07212 char username[70]="";
07213 char fn[PATH_MAX];
07214 char ecodes[16] = "#";
07215 int res = 0, cmd = 0;
07216 struct ast_vm_user *receiver = NULL, *vmtmp;
07217 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07218 char *stringp;
07219 const char *s;
07220 int saved_messages = 0;
07221 int valid_extensions = 0;
07222 char *dir;
07223 int curmsg;
07224 char urgent_str[7] = "";
07225 int prompt_played = 0;
07226 #ifndef IMAP_STORAGE
07227 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07228 #endif
07229 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07230 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07231 }
07232
07233 if (vms == NULL) return -1;
07234 dir = vms->curdir;
07235 curmsg = vms->curmsg;
07236
07237 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07238 while (!res && !valid_extensions) {
07239 int use_directory = 0;
07240 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07241 int done = 0;
07242 int retries = 0;
07243 cmd = 0;
07244 while ((cmd >= 0) && !done ){
07245 if (cmd)
07246 retries = 0;
07247 switch (cmd) {
07248 case '1':
07249 use_directory = 0;
07250 done = 1;
07251 break;
07252 case '2':
07253 use_directory = 1;
07254 done = 1;
07255 break;
07256 case '*':
07257 cmd = 't';
07258 done = 1;
07259 break;
07260 default:
07261
07262 cmd = ast_play_and_wait(chan, "vm-forward");
07263 if (!cmd) {
07264 cmd = ast_waitfordigit(chan, 3000);
07265 }
07266 if (!cmd) {
07267 retries++;
07268 }
07269 if (retries > 3) {
07270 cmd = 't';
07271 done = 1;
07272 }
07273 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07274 }
07275 }
07276 if (cmd < 0 || cmd == 't')
07277 break;
07278 }
07279
07280 if (use_directory) {
07281
07282
07283 char old_context[sizeof(chan->context)];
07284 char old_exten[sizeof(chan->exten)];
07285 int old_priority;
07286 struct ast_app* directory_app;
07287
07288 directory_app = pbx_findapp("Directory");
07289 if (directory_app) {
07290 char vmcontext[256];
07291
07292 memcpy(old_context, chan->context, sizeof(chan->context));
07293 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07294 old_priority = chan->priority;
07295
07296
07297 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07298 res = pbx_exec(chan, directory_app, vmcontext);
07299
07300 ast_copy_string(username, chan->exten, sizeof(username));
07301
07302
07303 memcpy(chan->context, old_context, sizeof(chan->context));
07304 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07305 chan->priority = old_priority;
07306 } else {
07307 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07308 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07309 }
07310 } else {
07311
07312 res = ast_streamfile(chan, "vm-extension", chan->language);
07313 prompt_played++;
07314 if (res || prompt_played > 4)
07315 break;
07316 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07317 break;
07318 }
07319
07320
07321 if (ast_strlen_zero(username))
07322 continue;
07323 stringp = username;
07324 s = strsep(&stringp, "*");
07325
07326 valid_extensions = 1;
07327 while (s) {
07328 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07329 int oldmsgs;
07330 int newmsgs;
07331 int capacity;
07332 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07333 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07334
07335 res = ast_play_and_wait(chan, "pbx-invalid");
07336 valid_extensions = 0;
07337 break;
07338 }
07339 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07340 if ((newmsgs + oldmsgs) >= capacity) {
07341 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07342 res = ast_play_and_wait(chan, "vm-mailboxfull");
07343 valid_extensions = 0;
07344 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07345 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07346 free_user(vmtmp);
07347 }
07348 inprocess_count(receiver->mailbox, receiver->context, -1);
07349 break;
07350 }
07351 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07352 } else {
07353
07354
07355
07356
07357
07358 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07359 free_user(receiver);
07360 }
07361 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07362
07363 res = ast_play_and_wait(chan, "pbx-invalid");
07364 valid_extensions = 0;
07365 break;
07366 }
07367
07368
07369 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07370 RETRIEVE(fn, -1, s, receiver->context);
07371 if (ast_fileexists(fn, NULL, NULL) > 0) {
07372 res = ast_stream_and_wait(chan, fn, ecodes);
07373 if (res) {
07374 DISPOSE(fn, -1);
07375 return res;
07376 }
07377 } else {
07378 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07379 }
07380 DISPOSE(fn, -1);
07381
07382 s = strsep(&stringp, "*");
07383 }
07384
07385 if (valid_extensions)
07386 break;
07387 }
07388
07389 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07390 return res;
07391 if (is_new_message == 1) {
07392 struct leave_vm_options leave_options;
07393 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07394 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07395
07396
07397 memset(&leave_options, 0, sizeof(leave_options));
07398 leave_options.record_gain = record_gain;
07399 cmd = leave_voicemail(chan, mailbox, &leave_options);
07400 } else {
07401
07402 long duration = 0;
07403 struct vm_state vmstmp;
07404 int copy_msg_result = 0;
07405 memcpy(&vmstmp, vms, sizeof(vmstmp));
07406
07407 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07408
07409 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07410 if (!cmd) {
07411 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07412 #ifdef IMAP_STORAGE
07413 int attach_user_voicemail;
07414 char *myserveremail = serveremail;
07415
07416
07417 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07418 if (!dstvms) {
07419 dstvms = create_vm_state_from_user(vmtmp);
07420 }
07421 if (dstvms) {
07422 init_mailstream(dstvms, 0);
07423 if (!dstvms->mailstream) {
07424 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07425 } else {
07426 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07427 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07428 }
07429 } else {
07430 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07431 }
07432 if (!ast_strlen_zero(vmtmp->serveremail))
07433 myserveremail = vmtmp->serveremail;
07434 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07435
07436 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07437 dstvms->curbox,
07438 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07439 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07440 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07441 NULL, urgent_str);
07442 #else
07443 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07444 #endif
07445 saved_messages++;
07446 AST_LIST_REMOVE_CURRENT(list);
07447 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07448 free_user(vmtmp);
07449 if (res)
07450 break;
07451 }
07452 AST_LIST_TRAVERSE_SAFE_END;
07453 if (saved_messages > 0 && !copy_msg_result) {
07454
07455
07456
07457
07458
07459
07460
07461
07462 #ifdef IMAP_STORAGE
07463
07464 if (ast_strlen_zero(vmstmp.introfn))
07465 #endif
07466 res = ast_play_and_wait(chan, "vm-msgsaved");
07467 }
07468 #ifndef IMAP_STORAGE
07469 else {
07470
07471 res = ast_play_and_wait(chan, "vm-mailboxfull");
07472 }
07473
07474 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07475 strcpy(textfile, msgfile);
07476 strcpy(backup, msgfile);
07477 strcpy(backup_textfile, msgfile);
07478 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07479 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07480 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07481 if (ast_fileexists(backup, NULL, NULL) > 0) {
07482 ast_filerename(backup, msgfile, NULL);
07483 rename(backup_textfile, textfile);
07484 }
07485 #endif
07486 }
07487 DISPOSE(dir, curmsg);
07488 #ifndef IMAP_STORAGE
07489 if (cmd) {
07490 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07491 strcpy(textfile, msgfile);
07492 strcpy(backup_textfile, msgfile);
07493 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07494 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07495 rename(backup_textfile, textfile);
07496 }
07497 #endif
07498 }
07499
07500
07501 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07502 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07503 free_user(vmtmp);
07504 }
07505 return res ? res : cmd;
07506 }
07507
07508 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07509 {
07510 int res;
07511 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07512 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07513 return res;
07514 }
07515
07516 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07517 {
07518 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07519 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
07520 }
07521
07522 static int play_message_category(struct ast_channel *chan, const char *category)
07523 {
07524 int res = 0;
07525
07526 if (!ast_strlen_zero(category))
07527 res = ast_play_and_wait(chan, category);
07528
07529 if (res) {
07530 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07531 res = 0;
07532 }
07533
07534 return res;
07535 }
07536
07537 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07538 {
07539 int res = 0;
07540 struct vm_zone *the_zone = NULL;
07541 time_t t;
07542
07543 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07544 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07545 return 0;
07546 }
07547
07548
07549 if (!ast_strlen_zero(vmu->zonetag)) {
07550
07551 struct vm_zone *z;
07552 AST_LIST_LOCK(&zones);
07553 AST_LIST_TRAVERSE(&zones, z, list) {
07554 if (!strcmp(z->name, vmu->zonetag)) {
07555 the_zone = z;
07556 break;
07557 }
07558 }
07559 AST_LIST_UNLOCK(&zones);
07560 }
07561
07562
07563 #if 0
07564
07565 ast_localtime(&t, &time_now, NULL);
07566 tv_now = ast_tvnow();
07567 ast_localtime(&tv_now, &time_then, NULL);
07568
07569
07570 if (time_now.tm_year == time_then.tm_year)
07571 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07572 else
07573 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07574 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07575
07576
07577 #endif
07578 if (the_zone) {
07579 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07580 } else if (!strncasecmp(chan->language, "de", 2)) {
07581 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07582 } else if (!strncasecmp(chan->language, "gr", 2)) {
07583 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07584 } else if (!strncasecmp(chan->language, "it", 2)) {
07585 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
07586 } else if (!strncasecmp(chan->language, "nl", 2)) {
07587 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07588 } else if (!strncasecmp(chan->language, "no", 2)) {
07589 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07590 } else if (!strncasecmp(chan->language, "pl", 2)) {
07591 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07592 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07593 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
07594 } else if (!strncasecmp(chan->language, "se", 2)) {
07595 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07596 } else if (!strncasecmp(chan->language, "zh", 2)) {
07597 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07598 } else if (!strncasecmp(chan->language, "vi", 2)) {
07599 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
07600 } else {
07601 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07602 }
07603 #if 0
07604 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07605 #endif
07606 return res;
07607 }
07608
07609
07610
07611 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07612 {
07613 int res = 0;
07614 int i;
07615 char *callerid, *name;
07616 char prefile[PATH_MAX] = "";
07617
07618
07619
07620
07621
07622
07623
07624
07625
07626 if ((cid == NULL)||(context == NULL))
07627 return res;
07628
07629
07630 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07631 ast_callerid_parse(cid, &name, &callerid);
07632 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07633
07634
07635 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07636 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07637 if ((strcmp(cidinternalcontexts[i], context) == 0))
07638 break;
07639 }
07640 if (i != MAX_NUM_CID_CONTEXTS){
07641 if (!res) {
07642 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07643 if (!ast_strlen_zero(prefile)) {
07644
07645 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07646 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07647 if (!callback)
07648 res = wait_file2(chan, vms, "vm-from");
07649 res = ast_stream_and_wait(chan, prefile, "");
07650 } else {
07651 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07652
07653 if (!callback)
07654 res = wait_file2(chan, vms, "vm-from-extension");
07655 res = ast_say_digit_str(chan, callerid, "", chan->language);
07656 }
07657 }
07658 }
07659 } else if (!res) {
07660 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07661
07662 if (!callback)
07663 res = wait_file2(chan, vms, "vm-from-phonenumber");
07664 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07665 }
07666 } else {
07667
07668 ast_debug(1, "VM-CID: From an unknown number\n");
07669
07670 res = wait_file2(chan, vms, "vm-unknown-caller");
07671 }
07672 return res;
07673 }
07674
07675 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07676 {
07677 int res = 0;
07678 int durationm;
07679 int durations;
07680
07681 if (duration == NULL)
07682 return res;
07683
07684
07685 durations = atoi(duration);
07686 durationm = (durations / 60);
07687
07688 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07689
07690 if ((!res) && (durationm >= minduration)) {
07691 res = wait_file2(chan, vms, "vm-duration");
07692
07693
07694 if (!strncasecmp(chan->language, "pl", 2)) {
07695 div_t num = div(durationm, 10);
07696
07697 if (durationm == 1) {
07698 res = ast_play_and_wait(chan, "digits/1z");
07699 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07700 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07701 if (num.rem == 2) {
07702 if (!num.quot) {
07703 res = ast_play_and_wait(chan, "digits/2-ie");
07704 } else {
07705 res = say_and_wait(chan, durationm - 2 , chan->language);
07706 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07707 }
07708 } else {
07709 res = say_and_wait(chan, durationm, chan->language);
07710 }
07711 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07712 } else {
07713 res = say_and_wait(chan, durationm, chan->language);
07714 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07715 }
07716
07717 } else {
07718 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07719 res = wait_file2(chan, vms, "vm-minutes");
07720 }
07721 }
07722 return res;
07723 }
07724
07725 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07726 {
07727 int res = 0;
07728 char filename[256], *cid;
07729 const char *origtime, *context, *category, *duration, *flag;
07730 struct ast_config *msg_cfg;
07731 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07732
07733 vms->starting = 0;
07734 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07735 adsi_message(chan, vms);
07736 if (!vms->curmsg) {
07737 res = wait_file2(chan, vms, "vm-first");
07738 } else if (vms->curmsg == vms->lastmsg) {
07739 res = wait_file2(chan, vms, "vm-last");
07740 }
07741
07742 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07743 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07744 msg_cfg = ast_config_load(filename, config_flags);
07745 if (!valid_config(msg_cfg)) {
07746 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07747 return 0;
07748 }
07749 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07750
07751
07752 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07753 res = wait_file2(chan, vms, "vm-Urgent");
07754 }
07755
07756 if (!res) {
07757
07758
07759 if (!strncasecmp(chan->language, "pl", 2)) {
07760 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07761 int ten, one;
07762 char nextmsg[256];
07763 ten = (vms->curmsg + 1) / 10;
07764 one = (vms->curmsg + 1) % 10;
07765
07766 if (vms->curmsg < 20) {
07767 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07768 res = wait_file2(chan, vms, nextmsg);
07769 } else {
07770 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07771 res = wait_file2(chan, vms, nextmsg);
07772 if (one > 0) {
07773 if (!res) {
07774 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07775 res = wait_file2(chan, vms, nextmsg);
07776 }
07777 }
07778 }
07779 }
07780 if (!res)
07781 res = wait_file2(chan, vms, "vm-message");
07782
07783 } else if (!strncasecmp(chan->language, "he", 2)) {
07784 if (!vms->curmsg) {
07785 res = wait_file2(chan, vms, "vm-message");
07786 res = wait_file2(chan, vms, "vm-first");
07787 } else if (vms->curmsg == vms->lastmsg) {
07788 res = wait_file2(chan, vms, "vm-message");
07789 res = wait_file2(chan, vms, "vm-last");
07790 } else {
07791 res = wait_file2(chan, vms, "vm-message");
07792 res = wait_file2(chan, vms, "vm-number");
07793 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07794 }
07795
07796 } else if (!strncasecmp(chan->language, "vi", 2)) {
07797 if (!vms->curmsg) {
07798 res = wait_file2(chan, vms, "vm-message");
07799 res = wait_file2(chan, vms, "vm-first");
07800 } else if (vms->curmsg == vms->lastmsg) {
07801 res = wait_file2(chan, vms, "vm-message");
07802 res = wait_file2(chan, vms, "vm-last");
07803 } else {
07804 res = wait_file2(chan, vms, "vm-message");
07805 res = wait_file2(chan, vms, "vm-number");
07806 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07807 }
07808 } else {
07809 if (!strncasecmp(chan->language, "se", 2)) {
07810 res = wait_file2(chan, vms, "vm-meddelandet");
07811 } else {
07812 res = wait_file2(chan, vms, "vm-message");
07813 }
07814 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07815 if (!res) {
07816 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07817 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07818 }
07819 }
07820 }
07821 }
07822
07823 if (!valid_config(msg_cfg)) {
07824 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07825 return 0;
07826 }
07827
07828 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07829 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07830 DISPOSE(vms->curdir, vms->curmsg);
07831 ast_config_destroy(msg_cfg);
07832 return 0;
07833 }
07834
07835 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07836 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07837 category = ast_variable_retrieve(msg_cfg, "message", "category");
07838
07839 context = ast_variable_retrieve(msg_cfg, "message", "context");
07840 if (!strncasecmp("macro", context, 5))
07841 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07842 if (!res) {
07843 res = play_message_category(chan, category);
07844 }
07845 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07846 res = play_message_datetime(chan, vmu, origtime, filename);
07847 }
07848 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07849 res = play_message_callerid(chan, vms, cid, context, 0);
07850 }
07851 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07852 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07853 }
07854
07855 if (res == '1') {
07856 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07857 res = 0;
07858 }
07859 ast_config_destroy(msg_cfg);
07860
07861 if (!res) {
07862 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07863 #ifdef IMAP_STORAGE
07864 ast_mutex_lock(&vms->lock);
07865 #endif
07866 vms->heard[vms->curmsg] = 1;
07867 #ifdef IMAP_STORAGE
07868 ast_mutex_unlock(&vms->lock);
07869
07870
07871
07872 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07873 wait_file(chan, vms, vms->introfn);
07874 }
07875 #endif
07876 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07877 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07878 res = 0;
07879 }
07880 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07881 }
07882 DISPOSE(vms->curdir, vms->curmsg);
07883 return res;
07884 }
07885
07886 #ifdef IMAP_STORAGE
07887 static int imap_remove_file(char *dir, int msgnum)
07888 {
07889 char fn[PATH_MAX];
07890 char full_fn[PATH_MAX];
07891 char intro[PATH_MAX] = {0,};
07892
07893 if (msgnum > -1) {
07894 make_file(fn, sizeof(fn), dir, msgnum);
07895 snprintf(intro, sizeof(intro), "%sintro", fn);
07896 } else
07897 ast_copy_string(fn, dir, sizeof(fn));
07898
07899 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07900 ast_filedelete(fn, NULL);
07901 if (!ast_strlen_zero(intro)) {
07902 ast_filedelete(intro, NULL);
07903 }
07904 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07905 unlink(full_fn);
07906 }
07907 return 0;
07908 }
07909
07910
07911
07912 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07913 {
07914 char *file, *filename;
07915 char *attachment;
07916 char arg[10];
07917 int i;
07918 BODY* body;
07919
07920 file = strrchr(ast_strdupa(dir), '/');
07921 if (file) {
07922 *file++ = '\0';
07923 } else {
07924 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07925 return -1;
07926 }
07927
07928 ast_mutex_lock(&vms->lock);
07929 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07930 mail_fetchstructure(vms->mailstream, i + 1, &body);
07931
07932 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07933 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07934 } else {
07935 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07936 ast_mutex_unlock(&vms->lock);
07937 return -1;
07938 }
07939 filename = strsep(&attachment, ".");
07940 if (!strcmp(filename, file)) {
07941 sprintf(arg, "%d", i + 1);
07942 mail_setflag(vms->mailstream, arg, "\\DELETED");
07943 }
07944 }
07945 mail_expunge(vms->mailstream);
07946 ast_mutex_unlock(&vms->lock);
07947 return 0;
07948 }
07949
07950 #elif !defined(IMAP_STORAGE)
07951 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07952 {
07953 int count_msg, last_msg;
07954
07955 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07956
07957
07958
07959
07960 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07961
07962
07963 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07964
07965
07966 count_msg = count_messages(vmu, vms->curdir);
07967 if (count_msg < 0) {
07968 return count_msg;
07969 } else {
07970 vms->lastmsg = count_msg - 1;
07971 }
07972
07973 if (vm_allocate_dh(vms, vmu, count_msg)) {
07974 return -1;
07975 }
07976
07977
07978
07979
07980
07981
07982
07983
07984 if (vm_lock_path(vms->curdir)) {
07985 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07986 return ERROR_LOCK_PATH;
07987 }
07988
07989
07990 last_msg = last_message_index(vmu, vms->curdir);
07991 ast_unlock_path(vms->curdir);
07992
07993 if (last_msg < -1) {
07994 return last_msg;
07995 } else if (vms->lastmsg != last_msg) {
07996 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
07997 resequence_mailbox(vmu, vms->curdir, count_msg);
07998 }
07999
08000 return 0;
08001 }
08002 #endif
08003
08004 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
08005 {
08006 int x = 0;
08007 int last_msg_idx = 0;
08008
08009 #ifndef IMAP_STORAGE
08010 int res = 0, nummsg;
08011 char fn2[PATH_MAX];
08012 #endif
08013
08014 if (vms->lastmsg <= -1) {
08015 goto done;
08016 }
08017
08018 vms->curmsg = -1;
08019 #ifndef IMAP_STORAGE
08020
08021 if (vm_lock_path(vms->curdir)) {
08022 return ERROR_LOCK_PATH;
08023 }
08024
08025
08026 last_msg_idx = last_message_index(vmu, vms->curdir);
08027 if (last_msg_idx != vms->lastmsg) {
08028 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08029 }
08030
08031
08032 for (x = 0; x < last_msg_idx + 1; x++) {
08033 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08034
08035 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08036 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08037 break;
08038 }
08039 vms->curmsg++;
08040 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08041 if (strcmp(vms->fn, fn2)) {
08042 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08043 }
08044 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08045
08046 res = save_to_folder(vmu, vms, x, 1);
08047 if (res == ERROR_LOCK_PATH) {
08048
08049 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08050 vms->deleted[x] = 0;
08051 vms->heard[x] = 0;
08052 --x;
08053 }
08054 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08055
08056 res = save_to_folder(vmu, vms, x, 10);
08057 if (res == ERROR_LOCK_PATH) {
08058
08059 vms->deleted[x] = 0;
08060 vms->heard[x] = 0;
08061 --x;
08062 }
08063 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08064
08065
08066 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08067 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08068 DELETE(vms->curdir, x, vms->fn, vmu);
08069 }
08070 }
08071 }
08072
08073
08074 nummsg = x - 1;
08075 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08076 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08077 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08078 DELETE(vms->curdir, x, vms->fn, vmu);
08079 }
08080 }
08081 ast_unlock_path(vms->curdir);
08082 #else
08083 ast_mutex_lock(&vms->lock);
08084 if (vms->deleted) {
08085
08086
08087 last_msg_idx = vms->dh_arraysize;
08088 for (x = last_msg_idx - 1; x >= 0; x--) {
08089 if (vms->deleted[x]) {
08090 ast_debug(3, "IMAP delete of %d\n", x);
08091 DELETE(vms->curdir, x, vms->fn, vmu);
08092 }
08093 }
08094 }
08095 #endif
08096
08097 done:
08098 if (vms->deleted) {
08099 ast_free(vms->deleted);
08100 vms->deleted = NULL;
08101 }
08102 if (vms->heard) {
08103 ast_free(vms->heard);
08104 vms->heard = NULL;
08105 }
08106 vms->dh_arraysize = 0;
08107 #ifdef IMAP_STORAGE
08108 ast_mutex_unlock(&vms->lock);
08109 #endif
08110
08111 return 0;
08112 }
08113
08114
08115
08116
08117
08118
08119
08120 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08121 {
08122 int cmd;
08123 char *buf;
08124
08125 buf = ast_alloca(strlen(box) + 2);
08126 strcpy(buf, box);
08127 strcat(buf, "s");
08128
08129 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08130 cmd = ast_play_and_wait(chan, buf);
08131 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08132 } else {
08133 cmd = ast_play_and_wait(chan, "vm-messages");
08134 return cmd ? cmd : ast_play_and_wait(chan, box);
08135 }
08136 }
08137
08138 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08139 {
08140 int cmd;
08141
08142 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08143 if (!strcasecmp(box, "vm-INBOX"))
08144 cmd = ast_play_and_wait(chan, "vm-new-e");
08145 else
08146 cmd = ast_play_and_wait(chan, "vm-old-e");
08147 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08148 } else {
08149 cmd = ast_play_and_wait(chan, "vm-messages");
08150 return cmd ? cmd : ast_play_and_wait(chan, box);
08151 }
08152 }
08153
08154 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08155 {
08156 int cmd;
08157
08158 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08159 cmd = ast_play_and_wait(chan, "vm-messages");
08160 return cmd ? cmd : ast_play_and_wait(chan, box);
08161 } else {
08162 cmd = ast_play_and_wait(chan, box);
08163 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08164 }
08165 }
08166
08167 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08168 {
08169 int cmd;
08170
08171 if ( !strncasecmp(chan->language, "it", 2) ||
08172 !strncasecmp(chan->language, "es", 2) ||
08173 !strncasecmp(chan->language, "pt", 2)) {
08174 cmd = ast_play_and_wait(chan, "vm-messages");
08175 return cmd ? cmd : ast_play_and_wait(chan, box);
08176 } else if (!strncasecmp(chan->language, "gr", 2)) {
08177 return vm_play_folder_name_gr(chan, box);
08178 } else if (!strncasecmp(chan->language, "he", 2)) {
08179 return ast_play_and_wait(chan, box);
08180 } else if (!strncasecmp(chan->language, "pl", 2)) {
08181 return vm_play_folder_name_pl(chan, box);
08182 } else if (!strncasecmp(chan->language, "ua", 2)) {
08183 return vm_play_folder_name_ua(chan, box);
08184 } else if (!strncasecmp(chan->language, "vi", 2)) {
08185 return ast_play_and_wait(chan, box);
08186 } else {
08187 cmd = ast_play_and_wait(chan, box);
08188 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08189 }
08190 }
08191
08192
08193
08194
08195
08196
08197
08198
08199
08200
08201
08202
08203
08204 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08205 {
08206 int res = 0;
08207
08208 if (vms->newmessages) {
08209 res = ast_play_and_wait(chan, "vm-youhave");
08210 if (!res)
08211 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08212 if (!res) {
08213 if ((vms->newmessages == 1)) {
08214 res = ast_play_and_wait(chan, "vm-INBOX");
08215 if (!res)
08216 res = ast_play_and_wait(chan, "vm-message");
08217 } else {
08218 res = ast_play_and_wait(chan, "vm-INBOXs");
08219 if (!res)
08220 res = ast_play_and_wait(chan, "vm-messages");
08221 }
08222 }
08223 } else if (vms->oldmessages){
08224 res = ast_play_and_wait(chan, "vm-youhave");
08225 if (!res)
08226 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08227 if ((vms->oldmessages == 1)){
08228 res = ast_play_and_wait(chan, "vm-Old");
08229 if (!res)
08230 res = ast_play_and_wait(chan, "vm-message");
08231 } else {
08232 res = ast_play_and_wait(chan, "vm-Olds");
08233 if (!res)
08234 res = ast_play_and_wait(chan, "vm-messages");
08235 }
08236 } else if (!vms->oldmessages && !vms->newmessages)
08237 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08238 return res;
08239 }
08240
08241
08242
08243
08244
08245
08246
08247
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257
08258
08259
08260
08261
08262
08263
08264
08265
08266
08267
08268
08269
08270
08271
08272
08273
08274
08275
08276
08277
08278
08279
08280
08281
08282
08283
08284
08285
08286
08287
08288
08289
08290
08291
08292
08293
08294
08295
08296
08297
08298 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08299 {
08300 int res;
08301 int lastnum = 0;
08302
08303 res = ast_play_and_wait(chan, "vm-youhave");
08304
08305 if (!res && vms->newmessages) {
08306 lastnum = vms->newmessages;
08307
08308 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08309 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08310 }
08311
08312 if (!res && vms->oldmessages) {
08313 res = ast_play_and_wait(chan, "vm-and");
08314 }
08315 }
08316
08317 if (!res && vms->oldmessages) {
08318 lastnum = vms->oldmessages;
08319
08320 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08321 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08322 }
08323 }
08324
08325 if (!res) {
08326 if (lastnum == 0) {
08327 res = ast_play_and_wait(chan, "vm-no");
08328 }
08329 if (!res) {
08330 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08331 }
08332 }
08333
08334 return res;
08335 }
08336
08337
08338 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08339 {
08340 int res = 0;
08341
08342
08343 if (!res) {
08344 if ((vms->newmessages) || (vms->oldmessages)) {
08345 res = ast_play_and_wait(chan, "vm-youhave");
08346 }
08347
08348
08349
08350
08351
08352 if (vms->newmessages) {
08353 if (!res) {
08354 if (vms->newmessages == 1) {
08355 res = ast_play_and_wait(chan, "vm-INBOX1");
08356 } else {
08357 if (vms->newmessages == 2) {
08358 res = ast_play_and_wait(chan, "vm-shtei");
08359 } else {
08360 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08361 }
08362 res = ast_play_and_wait(chan, "vm-INBOX");
08363 }
08364 }
08365 if (vms->oldmessages && !res) {
08366 res = ast_play_and_wait(chan, "vm-and");
08367 if (vms->oldmessages == 1) {
08368 res = ast_play_and_wait(chan, "vm-Old1");
08369 } else {
08370 if (vms->oldmessages == 2) {
08371 res = ast_play_and_wait(chan, "vm-shtei");
08372 } else {
08373 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08374 }
08375 res = ast_play_and_wait(chan, "vm-Old");
08376 }
08377 }
08378 }
08379 if (!res && vms->oldmessages && !vms->newmessages) {
08380 if (!res) {
08381 if (vms->oldmessages == 1) {
08382 res = ast_play_and_wait(chan, "vm-Old1");
08383 } else {
08384 if (vms->oldmessages == 2) {
08385 res = ast_play_and_wait(chan, "vm-shtei");
08386 } else {
08387 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08388 }
08389 res = ast_play_and_wait(chan, "vm-Old");
08390 }
08391 }
08392 }
08393 if (!res) {
08394 if (!vms->oldmessages && !vms->newmessages) {
08395 if (!res) {
08396 res = ast_play_and_wait(chan, "vm-nomessages");
08397 }
08398 }
08399 }
08400 }
08401 return res;
08402 }
08403
08404
08405 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08406 {
08407 int res;
08408
08409
08410 res = ast_play_and_wait(chan, "vm-youhave");
08411 if (!res) {
08412 if (vms->urgentmessages) {
08413 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08414 if (!res)
08415 res = ast_play_and_wait(chan, "vm-Urgent");
08416 if ((vms->oldmessages || vms->newmessages) && !res) {
08417 res = ast_play_and_wait(chan, "vm-and");
08418 } else if (!res) {
08419 if ((vms->urgentmessages == 1))
08420 res = ast_play_and_wait(chan, "vm-message");
08421 else
08422 res = ast_play_and_wait(chan, "vm-messages");
08423 }
08424 }
08425 if (vms->newmessages) {
08426 res = say_and_wait(chan, vms->newmessages, chan->language);
08427 if (!res)
08428 res = ast_play_and_wait(chan, "vm-INBOX");
08429 if (vms->oldmessages && !res)
08430 res = ast_play_and_wait(chan, "vm-and");
08431 else if (!res) {
08432 if ((vms->newmessages == 1))
08433 res = ast_play_and_wait(chan, "vm-message");
08434 else
08435 res = ast_play_and_wait(chan, "vm-messages");
08436 }
08437
08438 }
08439 if (!res && vms->oldmessages) {
08440 res = say_and_wait(chan, vms->oldmessages, chan->language);
08441 if (!res)
08442 res = ast_play_and_wait(chan, "vm-Old");
08443 if (!res) {
08444 if (vms->oldmessages == 1)
08445 res = ast_play_and_wait(chan, "vm-message");
08446 else
08447 res = ast_play_and_wait(chan, "vm-messages");
08448 }
08449 }
08450 if (!res) {
08451 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08452 res = ast_play_and_wait(chan, "vm-no");
08453 if (!res)
08454 res = ast_play_and_wait(chan, "vm-messages");
08455 }
08456 }
08457 }
08458 return res;
08459 }
08460
08461
08462 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08463 {
08464
08465 int res;
08466 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08467 res = ast_play_and_wait(chan, "vm-no") ||
08468 ast_play_and_wait(chan, "vm-message");
08469 else
08470 res = ast_play_and_wait(chan, "vm-youhave");
08471 if (!res && vms->newmessages) {
08472 res = (vms->newmessages == 1) ?
08473 ast_play_and_wait(chan, "digits/un") ||
08474 ast_play_and_wait(chan, "vm-nuovo") ||
08475 ast_play_and_wait(chan, "vm-message") :
08476
08477 say_and_wait(chan, vms->newmessages, chan->language) ||
08478 ast_play_and_wait(chan, "vm-nuovi") ||
08479 ast_play_and_wait(chan, "vm-messages");
08480 if (!res && vms->oldmessages)
08481 res = ast_play_and_wait(chan, "vm-and");
08482 }
08483 if (!res && vms->oldmessages) {
08484 res = (vms->oldmessages == 1) ?
08485 ast_play_and_wait(chan, "digits/un") ||
08486 ast_play_and_wait(chan, "vm-vecchio") ||
08487 ast_play_and_wait(chan, "vm-message") :
08488
08489 say_and_wait(chan, vms->oldmessages, chan->language) ||
08490 ast_play_and_wait(chan, "vm-vecchi") ||
08491 ast_play_and_wait(chan, "vm-messages");
08492 }
08493 return res;
08494 }
08495
08496
08497 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08498 {
08499
08500 int res;
08501 div_t num;
08502
08503 if (!vms->oldmessages && !vms->newmessages) {
08504 res = ast_play_and_wait(chan, "vm-no");
08505 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08506 return res;
08507 } else {
08508 res = ast_play_and_wait(chan, "vm-youhave");
08509 }
08510
08511 if (vms->newmessages) {
08512 num = div(vms->newmessages, 10);
08513 if (vms->newmessages == 1) {
08514 res = ast_play_and_wait(chan, "digits/1-a");
08515 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08516 res = res ? res : ast_play_and_wait(chan, "vm-message");
08517 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08518 if (num.rem == 2) {
08519 if (!num.quot) {
08520 res = ast_play_and_wait(chan, "digits/2-ie");
08521 } else {
08522 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08523 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08524 }
08525 } else {
08526 res = say_and_wait(chan, vms->newmessages, chan->language);
08527 }
08528 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08529 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08530 } else {
08531 res = say_and_wait(chan, vms->newmessages, chan->language);
08532 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08533 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08534 }
08535 if (!res && vms->oldmessages)
08536 res = ast_play_and_wait(chan, "vm-and");
08537 }
08538 if (!res && vms->oldmessages) {
08539 num = div(vms->oldmessages, 10);
08540 if (vms->oldmessages == 1) {
08541 res = ast_play_and_wait(chan, "digits/1-a");
08542 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08543 res = res ? res : ast_play_and_wait(chan, "vm-message");
08544 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08545 if (num.rem == 2) {
08546 if (!num.quot) {
08547 res = ast_play_and_wait(chan, "digits/2-ie");
08548 } else {
08549 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08550 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08551 }
08552 } else {
08553 res = say_and_wait(chan, vms->oldmessages, chan->language);
08554 }
08555 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08556 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08557 } else {
08558 res = say_and_wait(chan, vms->oldmessages, chan->language);
08559 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08560 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08561 }
08562 }
08563
08564 return res;
08565 }
08566
08567
08568 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08569 {
08570
08571 int res;
08572
08573 res = ast_play_and_wait(chan, "vm-youhave");
08574 if (res)
08575 return res;
08576
08577 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08578 res = ast_play_and_wait(chan, "vm-no");
08579 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08580 return res;
08581 }
08582
08583 if (vms->newmessages) {
08584 if ((vms->newmessages == 1)) {
08585 res = ast_play_and_wait(chan, "digits/ett");
08586 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08587 res = res ? res : ast_play_and_wait(chan, "vm-message");
08588 } else {
08589 res = say_and_wait(chan, vms->newmessages, chan->language);
08590 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08591 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08592 }
08593 if (!res && vms->oldmessages)
08594 res = ast_play_and_wait(chan, "vm-and");
08595 }
08596 if (!res && vms->oldmessages) {
08597 if (vms->oldmessages == 1) {
08598 res = ast_play_and_wait(chan, "digits/ett");
08599 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08600 res = res ? res : ast_play_and_wait(chan, "vm-message");
08601 } else {
08602 res = say_and_wait(chan, vms->oldmessages, chan->language);
08603 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08604 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08605 }
08606 }
08607
08608 return res;
08609 }
08610
08611
08612 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08613 {
08614
08615 int res;
08616
08617 res = ast_play_and_wait(chan, "vm-youhave");
08618 if (res)
08619 return res;
08620
08621 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08622 res = ast_play_and_wait(chan, "vm-no");
08623 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08624 return res;
08625 }
08626
08627 if (vms->newmessages) {
08628 if ((vms->newmessages == 1)) {
08629 res = ast_play_and_wait(chan, "digits/1");
08630 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08631 res = res ? res : ast_play_and_wait(chan, "vm-message");
08632 } else {
08633 res = say_and_wait(chan, vms->newmessages, chan->language);
08634 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08635 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08636 }
08637 if (!res && vms->oldmessages)
08638 res = ast_play_and_wait(chan, "vm-and");
08639 }
08640 if (!res && vms->oldmessages) {
08641 if (vms->oldmessages == 1) {
08642 res = ast_play_and_wait(chan, "digits/1");
08643 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08644 res = res ? res : ast_play_and_wait(chan, "vm-message");
08645 } else {
08646 res = say_and_wait(chan, vms->oldmessages, chan->language);
08647 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08648 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08649 }
08650 }
08651
08652 return res;
08653 }
08654
08655
08656 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08657 {
08658
08659 int res;
08660 res = ast_play_and_wait(chan, "vm-youhave");
08661 if (!res) {
08662 if (vms->newmessages) {
08663 if ((vms->newmessages == 1))
08664 res = ast_play_and_wait(chan, "digits/1F");
08665 else
08666 res = say_and_wait(chan, vms->newmessages, chan->language);
08667 if (!res)
08668 res = ast_play_and_wait(chan, "vm-INBOX");
08669 if (vms->oldmessages && !res)
08670 res = ast_play_and_wait(chan, "vm-and");
08671 else if (!res) {
08672 if ((vms->newmessages == 1))
08673 res = ast_play_and_wait(chan, "vm-message");
08674 else
08675 res = ast_play_and_wait(chan, "vm-messages");
08676 }
08677
08678 }
08679 if (!res && vms->oldmessages) {
08680 if (vms->oldmessages == 1)
08681 res = ast_play_and_wait(chan, "digits/1F");
08682 else
08683 res = say_and_wait(chan, vms->oldmessages, chan->language);
08684 if (!res)
08685 res = ast_play_and_wait(chan, "vm-Old");
08686 if (!res) {
08687 if (vms->oldmessages == 1)
08688 res = ast_play_and_wait(chan, "vm-message");
08689 else
08690 res = ast_play_and_wait(chan, "vm-messages");
08691 }
08692 }
08693 if (!res) {
08694 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08695 res = ast_play_and_wait(chan, "vm-no");
08696 if (!res)
08697 res = ast_play_and_wait(chan, "vm-messages");
08698 }
08699 }
08700 }
08701 return res;
08702 }
08703
08704
08705 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08706 {
08707
08708 int res;
08709 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08710 res = ast_play_and_wait(chan, "vm-youhaveno");
08711 if (!res)
08712 res = ast_play_and_wait(chan, "vm-messages");
08713 } else {
08714 res = ast_play_and_wait(chan, "vm-youhave");
08715 }
08716 if (!res) {
08717 if (vms->newmessages) {
08718 if (!res) {
08719 if ((vms->newmessages == 1)) {
08720 res = ast_play_and_wait(chan, "digits/1");
08721 if (!res)
08722 res = ast_play_and_wait(chan, "vm-message");
08723 if (!res)
08724 res = ast_play_and_wait(chan, "vm-INBOXs");
08725 } else {
08726 res = say_and_wait(chan, vms->newmessages, chan->language);
08727 if (!res)
08728 res = ast_play_and_wait(chan, "vm-messages");
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-INBOX");
08731 }
08732 }
08733 if (vms->oldmessages && !res)
08734 res = ast_play_and_wait(chan, "vm-and");
08735 }
08736 if (vms->oldmessages) {
08737 if (!res) {
08738 if (vms->oldmessages == 1) {
08739 res = ast_play_and_wait(chan, "digits/1");
08740 if (!res)
08741 res = ast_play_and_wait(chan, "vm-message");
08742 if (!res)
08743 res = ast_play_and_wait(chan, "vm-Olds");
08744 } else {
08745 res = say_and_wait(chan, vms->oldmessages, chan->language);
08746 if (!res)
08747 res = ast_play_and_wait(chan, "vm-messages");
08748 if (!res)
08749 res = ast_play_and_wait(chan, "vm-Old");
08750 }
08751 }
08752 }
08753 }
08754 return res;
08755 }
08756
08757
08758 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08759
08760 int res;
08761 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08762 res = ast_play_and_wait(chan, "vm-nomessages");
08763 return res;
08764 } else {
08765 res = ast_play_and_wait(chan, "vm-youhave");
08766 }
08767 if (vms->newmessages) {
08768 if (!res)
08769 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08770 if ((vms->newmessages == 1)) {
08771 if (!res)
08772 res = ast_play_and_wait(chan, "vm-message");
08773 if (!res)
08774 res = ast_play_and_wait(chan, "vm-INBOXs");
08775 } else {
08776 if (!res)
08777 res = ast_play_and_wait(chan, "vm-messages");
08778 if (!res)
08779 res = ast_play_and_wait(chan, "vm-INBOX");
08780 }
08781 if (vms->oldmessages && !res)
08782 res = ast_play_and_wait(chan, "vm-and");
08783 }
08784 if (vms->oldmessages) {
08785 if (!res)
08786 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08787 if (vms->oldmessages == 1) {
08788 if (!res)
08789 res = ast_play_and_wait(chan, "vm-message");
08790 if (!res)
08791 res = ast_play_and_wait(chan, "vm-Olds");
08792 } else {
08793 if (!res)
08794 res = ast_play_and_wait(chan, "vm-messages");
08795 if (!res)
08796 res = ast_play_and_wait(chan, "vm-Old");
08797 }
08798 }
08799 return res;
08800 }
08801
08802
08803 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08804 {
08805
08806 int res;
08807 res = ast_play_and_wait(chan, "vm-youhave");
08808 if (!res) {
08809 if (vms->newmessages) {
08810 res = say_and_wait(chan, vms->newmessages, chan->language);
08811 if (!res)
08812 res = ast_play_and_wait(chan, "vm-INBOX");
08813 if (vms->oldmessages && !res)
08814 res = ast_play_and_wait(chan, "vm-and");
08815 else if (!res) {
08816 if ((vms->newmessages == 1))
08817 res = ast_play_and_wait(chan, "vm-message");
08818 else
08819 res = ast_play_and_wait(chan, "vm-messages");
08820 }
08821
08822 }
08823 if (!res && vms->oldmessages) {
08824 res = say_and_wait(chan, vms->oldmessages, chan->language);
08825 if (!res)
08826 res = ast_play_and_wait(chan, "vm-Old");
08827 if (!res) {
08828 if (vms->oldmessages == 1)
08829 res = ast_play_and_wait(chan, "vm-message");
08830 else
08831 res = ast_play_and_wait(chan, "vm-messages");
08832 }
08833 }
08834 if (!res) {
08835 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08836 res = ast_play_and_wait(chan, "vm-no");
08837 if (!res)
08838 res = ast_play_and_wait(chan, "vm-messages");
08839 }
08840 }
08841 }
08842 return res;
08843 }
08844
08845
08846 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08847 {
08848
08849 int res;
08850 res = ast_play_and_wait(chan, "vm-youhave");
08851 if (!res) {
08852 if (vms->newmessages) {
08853 res = say_and_wait(chan, vms->newmessages, chan->language);
08854 if (!res) {
08855 if (vms->newmessages == 1)
08856 res = ast_play_and_wait(chan, "vm-INBOXs");
08857 else
08858 res = ast_play_and_wait(chan, "vm-INBOX");
08859 }
08860 if (vms->oldmessages && !res)
08861 res = ast_play_and_wait(chan, "vm-and");
08862 else if (!res) {
08863 if ((vms->newmessages == 1))
08864 res = ast_play_and_wait(chan, "vm-message");
08865 else
08866 res = ast_play_and_wait(chan, "vm-messages");
08867 }
08868
08869 }
08870 if (!res && vms->oldmessages) {
08871 res = say_and_wait(chan, vms->oldmessages, chan->language);
08872 if (!res) {
08873 if (vms->oldmessages == 1)
08874 res = ast_play_and_wait(chan, "vm-Olds");
08875 else
08876 res = ast_play_and_wait(chan, "vm-Old");
08877 }
08878 if (!res) {
08879 if (vms->oldmessages == 1)
08880 res = ast_play_and_wait(chan, "vm-message");
08881 else
08882 res = ast_play_and_wait(chan, "vm-messages");
08883 }
08884 }
08885 if (!res) {
08886 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08887 res = ast_play_and_wait(chan, "vm-no");
08888 if (!res)
08889 res = ast_play_and_wait(chan, "vm-messages");
08890 }
08891 }
08892 }
08893 return res;
08894 }
08895
08896
08897 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08898 {
08899
08900 int res;
08901 res = ast_play_and_wait(chan, "vm-youhave");
08902 if (!res) {
08903 if (vms->newmessages) {
08904 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08905 if (!res) {
08906 if ((vms->newmessages == 1)) {
08907 res = ast_play_and_wait(chan, "vm-message");
08908 if (!res)
08909 res = ast_play_and_wait(chan, "vm-INBOXs");
08910 } else {
08911 res = ast_play_and_wait(chan, "vm-messages");
08912 if (!res)
08913 res = ast_play_and_wait(chan, "vm-INBOX");
08914 }
08915 }
08916 if (vms->oldmessages && !res)
08917 res = ast_play_and_wait(chan, "vm-and");
08918 }
08919 if (!res && vms->oldmessages) {
08920 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08921 if (!res) {
08922 if (vms->oldmessages == 1) {
08923 res = ast_play_and_wait(chan, "vm-message");
08924 if (!res)
08925 res = ast_play_and_wait(chan, "vm-Olds");
08926 } else {
08927 res = ast_play_and_wait(chan, "vm-messages");
08928 if (!res)
08929 res = ast_play_and_wait(chan, "vm-Old");
08930 }
08931 }
08932 }
08933 if (!res) {
08934 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08935 res = ast_play_and_wait(chan, "vm-no");
08936 if (!res)
08937 res = ast_play_and_wait(chan, "vm-messages");
08938 }
08939 }
08940 }
08941 return res;
08942 }
08943
08944
08945
08946
08947
08948
08949
08950
08951
08952
08953
08954
08955
08956
08957
08958
08959
08960 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08961 {
08962 int res;
08963 res = ast_play_and_wait(chan, "vm-youhave");
08964 if (!res) {
08965 if (vms->newmessages) {
08966 if (vms->newmessages == 1) {
08967 res = ast_play_and_wait(chan, "digits/jednu");
08968 } else {
08969 res = say_and_wait(chan, vms->newmessages, chan->language);
08970 }
08971 if (!res) {
08972 if ((vms->newmessages == 1))
08973 res = ast_play_and_wait(chan, "vm-novou");
08974 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08975 res = ast_play_and_wait(chan, "vm-nove");
08976 if (vms->newmessages > 4)
08977 res = ast_play_and_wait(chan, "vm-novych");
08978 }
08979 if (vms->oldmessages && !res)
08980 res = ast_play_and_wait(chan, "vm-and");
08981 else if (!res) {
08982 if ((vms->newmessages == 1))
08983 res = ast_play_and_wait(chan, "vm-zpravu");
08984 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08985 res = ast_play_and_wait(chan, "vm-zpravy");
08986 if (vms->newmessages > 4)
08987 res = ast_play_and_wait(chan, "vm-zprav");
08988 }
08989 }
08990 if (!res && vms->oldmessages) {
08991 res = say_and_wait(chan, vms->oldmessages, chan->language);
08992 if (!res) {
08993 if ((vms->oldmessages == 1))
08994 res = ast_play_and_wait(chan, "vm-starou");
08995 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08996 res = ast_play_and_wait(chan, "vm-stare");
08997 if (vms->oldmessages > 4)
08998 res = ast_play_and_wait(chan, "vm-starych");
08999 }
09000 if (!res) {
09001 if ((vms->oldmessages == 1))
09002 res = ast_play_and_wait(chan, "vm-zpravu");
09003 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09004 res = ast_play_and_wait(chan, "vm-zpravy");
09005 if (vms->oldmessages > 4)
09006 res = ast_play_and_wait(chan, "vm-zprav");
09007 }
09008 }
09009 if (!res) {
09010 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09011 res = ast_play_and_wait(chan, "vm-no");
09012 if (!res)
09013 res = ast_play_and_wait(chan, "vm-zpravy");
09014 }
09015 }
09016 }
09017 return res;
09018 }
09019
09020
09021 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09022 {
09023 int res;
09024
09025 res = ast_play_and_wait(chan, "vm-you");
09026
09027 if (!res && vms->newmessages) {
09028 res = ast_play_and_wait(chan, "vm-have");
09029 if (!res)
09030 res = say_and_wait(chan, vms->newmessages, chan->language);
09031 if (!res)
09032 res = ast_play_and_wait(chan, "vm-tong");
09033 if (!res)
09034 res = ast_play_and_wait(chan, "vm-INBOX");
09035 if (vms->oldmessages && !res)
09036 res = ast_play_and_wait(chan, "vm-and");
09037 else if (!res)
09038 res = ast_play_and_wait(chan, "vm-messages");
09039 }
09040 if (!res && vms->oldmessages) {
09041 res = ast_play_and_wait(chan, "vm-have");
09042 if (!res)
09043 res = say_and_wait(chan, vms->oldmessages, chan->language);
09044 if (!res)
09045 res = ast_play_and_wait(chan, "vm-tong");
09046 if (!res)
09047 res = ast_play_and_wait(chan, "vm-Old");
09048 if (!res)
09049 res = ast_play_and_wait(chan, "vm-messages");
09050 }
09051 if (!res && !vms->oldmessages && !vms->newmessages) {
09052 res = ast_play_and_wait(chan, "vm-haveno");
09053 if (!res)
09054 res = ast_play_and_wait(chan, "vm-messages");
09055 }
09056 return res;
09057 }
09058
09059
09060 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09061 {
09062 int res;
09063
09064
09065 res = ast_play_and_wait(chan, "vm-youhave");
09066 if (!res) {
09067 if (vms->newmessages) {
09068 res = say_and_wait(chan, vms->newmessages, chan->language);
09069 if (!res)
09070 res = ast_play_and_wait(chan, "vm-INBOX");
09071 if (vms->oldmessages && !res)
09072 res = ast_play_and_wait(chan, "vm-and");
09073 }
09074 if (!res && vms->oldmessages) {
09075 res = say_and_wait(chan, vms->oldmessages, chan->language);
09076 if (!res)
09077 res = ast_play_and_wait(chan, "vm-Old");
09078 }
09079 if (!res) {
09080 if (!vms->oldmessages && !vms->newmessages) {
09081 res = ast_play_and_wait(chan, "vm-no");
09082 if (!res)
09083 res = ast_play_and_wait(chan, "vm-message");
09084 }
09085 }
09086 }
09087 return res;
09088 }
09089
09090 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09091 {
09092 char prefile[256];
09093
09094
09095 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09096 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09097 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09098 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09099 ast_play_and_wait(chan, "vm-tempgreetactive");
09100 }
09101 DISPOSE(prefile, -1);
09102 }
09103
09104
09105 if (0) {
09106 return 0;
09107 } else if (!strncasecmp(chan->language, "cs", 2)) {
09108 return vm_intro_cs(chan, vms);
09109 } else if (!strncasecmp(chan->language, "cz", 2)) {
09110 static int deprecation_warning = 0;
09111 if (deprecation_warning++ % 10 == 0) {
09112 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09113 }
09114 return vm_intro_cs(chan, vms);
09115 } else if (!strncasecmp(chan->language, "de", 2)) {
09116 return vm_intro_de(chan, vms);
09117 } else if (!strncasecmp(chan->language, "es", 2)) {
09118 return vm_intro_es(chan, vms);
09119 } else if (!strncasecmp(chan->language, "fr", 2)) {
09120 return vm_intro_fr(chan, vms);
09121 } else if (!strncasecmp(chan->language, "gr", 2)) {
09122 return vm_intro_gr(chan, vms);
09123 } else if (!strncasecmp(chan->language, "he", 2)) {
09124 return vm_intro_he(chan, vms);
09125 } else if (!strncasecmp(chan->language, "it", 2)) {
09126 return vm_intro_it(chan, vms);
09127 } else if (!strncasecmp(chan->language, "nl", 2)) {
09128 return vm_intro_nl(chan, vms);
09129 } else if (!strncasecmp(chan->language, "no", 2)) {
09130 return vm_intro_no(chan, vms);
09131 } else if (!strncasecmp(chan->language, "pl", 2)) {
09132 return vm_intro_pl(chan, vms);
09133 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09134 return vm_intro_pt_BR(chan, vms);
09135 } else if (!strncasecmp(chan->language, "pt", 2)) {
09136 return vm_intro_pt(chan, vms);
09137 } else if (!strncasecmp(chan->language, "ru", 2)) {
09138 return vm_intro_multilang(chan, vms, "n");
09139 } else if (!strncasecmp(chan->language, "se", 2)) {
09140 return vm_intro_se(chan, vms);
09141 } else if (!strncasecmp(chan->language, "ua", 2)) {
09142 return vm_intro_multilang(chan, vms, "n");
09143 } else if (!strncasecmp(chan->language, "vi", 2)) {
09144 return vm_intro_vi(chan, vms);
09145 } else if (!strncasecmp(chan->language, "zh", 2)) {
09146 return vm_intro_zh(chan, vms);
09147 } else {
09148 return vm_intro_en(chan, vms);
09149 }
09150 }
09151
09152 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09153 {
09154 int res = 0;
09155
09156 while (!res) {
09157 if (vms->starting) {
09158 if (vms->lastmsg > -1) {
09159 if (skipadvanced)
09160 res = ast_play_and_wait(chan, "vm-onefor-full");
09161 else
09162 res = ast_play_and_wait(chan, "vm-onefor");
09163 if (!res)
09164 res = vm_play_folder_name(chan, vms->vmbox);
09165 }
09166 if (!res) {
09167 if (skipadvanced)
09168 res = ast_play_and_wait(chan, "vm-opts-full");
09169 else
09170 res = ast_play_and_wait(chan, "vm-opts");
09171 }
09172 } else {
09173
09174 if (skipadvanced) {
09175 res = ast_play_and_wait(chan, "vm-onefor-full");
09176 if (!res)
09177 res = vm_play_folder_name(chan, vms->vmbox);
09178 res = ast_play_and_wait(chan, "vm-opts-full");
09179 }
09180
09181
09182
09183
09184
09185
09186 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09187 res = ast_play_and_wait(chan, "vm-prev");
09188 }
09189 if (!res && !skipadvanced)
09190 res = ast_play_and_wait(chan, "vm-advopts");
09191 if (!res)
09192 res = ast_play_and_wait(chan, "vm-repeat");
09193
09194
09195
09196
09197
09198
09199 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09200 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09201 res = ast_play_and_wait(chan, "vm-next");
09202 }
09203 if (!res) {
09204 int curmsg_deleted;
09205 #ifdef IMAP_STORAGE
09206 ast_mutex_lock(&vms->lock);
09207 #endif
09208 curmsg_deleted = vms->deleted[vms->curmsg];
09209 #ifdef IMAP_STORAGE
09210 ast_mutex_unlock(&vms->lock);
09211 #endif
09212 if (!curmsg_deleted) {
09213 res = ast_play_and_wait(chan, "vm-delete");
09214 } else {
09215 res = ast_play_and_wait(chan, "vm-undelete");
09216 }
09217 if (!res) {
09218 res = ast_play_and_wait(chan, "vm-toforward");
09219 }
09220 if (!res) {
09221 res = ast_play_and_wait(chan, "vm-savemessage");
09222 }
09223 }
09224 }
09225 if (!res) {
09226 res = ast_play_and_wait(chan, "vm-helpexit");
09227 }
09228 if (!res)
09229 res = ast_waitfordigit(chan, 6000);
09230 if (!res) {
09231 vms->repeats++;
09232 if (vms->repeats > 2) {
09233 res = 't';
09234 }
09235 }
09236 }
09237 return res;
09238 }
09239
09240 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09241 {
09242 int res = 0;
09243
09244 while (!res) {
09245 if (vms->lastmsg > -1) {
09246 res = ast_play_and_wait(chan, "vm-listen");
09247 if (!res)
09248 res = vm_play_folder_name(chan, vms->vmbox);
09249 if (!res)
09250 res = ast_play_and_wait(chan, "press");
09251 if (!res)
09252 res = ast_play_and_wait(chan, "digits/1");
09253 }
09254 if (!res)
09255 res = ast_play_and_wait(chan, "vm-opts");
09256 if (!res) {
09257 vms->starting = 0;
09258 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09259 }
09260 }
09261 return res;
09262 }
09263
09264 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09265 {
09266 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09267 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09268 } else {
09269 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09270 }
09271 }
09272
09273
09274 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09275 {
09276 int cmd = 0;
09277 int duration = 0;
09278 int tries = 0;
09279 char newpassword[80] = "";
09280 char newpassword2[80] = "";
09281 char prefile[PATH_MAX] = "";
09282 unsigned char buf[256];
09283 int bytes = 0;
09284
09285 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09286 if (ast_adsi_available(chan)) {
09287 bytes += adsi_logo(buf + bytes);
09288 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09289 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09290 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09291 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09292 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09293 }
09294
09295
09296 if (ast_test_flag(vmu, VM_FORCENAME)) {
09297 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09298 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09299 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09300 if (cmd < 0 || cmd == 't' || cmd == '#')
09301 return cmd;
09302 }
09303 }
09304
09305
09306 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09307 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09308 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09309 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09310 if (cmd < 0 || cmd == 't' || cmd == '#')
09311 return cmd;
09312 }
09313
09314 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09315 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09316 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09317 if (cmd < 0 || cmd == 't' || cmd == '#')
09318 return cmd;
09319 }
09320 }
09321
09322
09323
09324
09325
09326 for (;;) {
09327 newpassword[1] = '\0';
09328 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09329 if (cmd == '#')
09330 newpassword[0] = '\0';
09331 if (cmd < 0 || cmd == 't' || cmd == '#')
09332 return cmd;
09333 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09334 if (cmd < 0 || cmd == 't' || cmd == '#')
09335 return cmd;
09336 cmd = check_password(vmu, newpassword);
09337 if (cmd != 0) {
09338 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09339 cmd = ast_play_and_wait(chan, vm_invalid_password);
09340 } else {
09341 newpassword2[1] = '\0';
09342 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09343 if (cmd == '#')
09344 newpassword2[0] = '\0';
09345 if (cmd < 0 || cmd == 't' || cmd == '#')
09346 return cmd;
09347 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09348 if (cmd < 0 || cmd == 't' || cmd == '#')
09349 return cmd;
09350 if (!strcmp(newpassword, newpassword2))
09351 break;
09352 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09353 cmd = ast_play_and_wait(chan, vm_mismatch);
09354 }
09355 if (++tries == 3)
09356 return -1;
09357 if (cmd != 0) {
09358 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09359 }
09360 }
09361 if (pwdchange & PWDCHANGE_INTERNAL)
09362 vm_change_password(vmu, newpassword);
09363 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09364 vm_change_password_shell(vmu, newpassword);
09365
09366 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09367 cmd = ast_play_and_wait(chan, vm_passchanged);
09368
09369 return cmd;
09370 }
09371
09372 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09373 {
09374 int cmd = 0;
09375 int retries = 0;
09376 int duration = 0;
09377 char newpassword[80] = "";
09378 char newpassword2[80] = "";
09379 char prefile[PATH_MAX] = "";
09380 unsigned char buf[256];
09381 int bytes = 0;
09382
09383 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09384 if (ast_adsi_available(chan)) {
09385 bytes += adsi_logo(buf + bytes);
09386 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09387 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09388 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09389 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09390 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09391 }
09392 while ((cmd >= 0) && (cmd != 't')) {
09393 if (cmd)
09394 retries = 0;
09395 switch (cmd) {
09396 case '1':
09397 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09398 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09399 break;
09400 case '2':
09401 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09402 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09403 break;
09404 case '3':
09405 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09406 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09407 break;
09408 case '4':
09409 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09410 break;
09411 case '5':
09412 if (vmu->password[0] == '-') {
09413 cmd = ast_play_and_wait(chan, "vm-no");
09414 break;
09415 }
09416 newpassword[1] = '\0';
09417 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09418 if (cmd == '#')
09419 newpassword[0] = '\0';
09420 else {
09421 if (cmd < 0)
09422 break;
09423 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09424 break;
09425 }
09426 }
09427 cmd = check_password(vmu, newpassword);
09428 if (cmd != 0) {
09429 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09430 cmd = ast_play_and_wait(chan, vm_invalid_password);
09431 if (!cmd) {
09432 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09433 }
09434 break;
09435 }
09436 newpassword2[1] = '\0';
09437 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09438 if (cmd == '#')
09439 newpassword2[0] = '\0';
09440 else {
09441 if (cmd < 0)
09442 break;
09443
09444 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09445 break;
09446 }
09447 }
09448 if (strcmp(newpassword, newpassword2)) {
09449 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09450 cmd = ast_play_and_wait(chan, vm_mismatch);
09451 if (!cmd) {
09452 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09453 }
09454 break;
09455 }
09456
09457 if (pwdchange & PWDCHANGE_INTERNAL) {
09458 vm_change_password(vmu, newpassword);
09459 }
09460 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09461 vm_change_password_shell(vmu, newpassword);
09462 }
09463
09464 ast_debug(1, "User %s set password to %s of length %d\n",
09465 vms->username, newpassword, (int) strlen(newpassword));
09466 cmd = ast_play_and_wait(chan, vm_passchanged);
09467 break;
09468 case '*':
09469 cmd = 't';
09470 break;
09471 default:
09472 cmd = 0;
09473 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09474 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09475 if (ast_fileexists(prefile, NULL, NULL)) {
09476 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09477 }
09478 DISPOSE(prefile, -1);
09479 if (!cmd) {
09480 cmd = ast_play_and_wait(chan, "vm-options");
09481 }
09482 if (!cmd) {
09483 cmd = ast_waitfordigit(chan, 6000);
09484 }
09485 if (!cmd) {
09486 retries++;
09487 }
09488 if (retries > 3) {
09489 cmd = 't';
09490 }
09491 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09492 }
09493 }
09494 if (cmd == 't')
09495 cmd = 0;
09496 return cmd;
09497 }
09498
09499
09500
09501
09502
09503
09504
09505
09506
09507
09508
09509
09510
09511
09512
09513
09514
09515 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09516 {
09517 int cmd = 0;
09518 int retries = 0;
09519 int duration = 0;
09520 char prefile[PATH_MAX] = "";
09521 unsigned char buf[256];
09522 int bytes = 0;
09523
09524 if (ast_adsi_available(chan)) {
09525 bytes += adsi_logo(buf + bytes);
09526 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09527 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09528 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09529 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09530 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09531 }
09532
09533 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09534 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09535 while ((cmd >= 0) && (cmd != 't')) {
09536 if (cmd)
09537 retries = 0;
09538 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09539 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09540 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09541 if (cmd == -1) {
09542 break;
09543 }
09544 cmd = 't';
09545 } else {
09546 switch (cmd) {
09547 case '1':
09548 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09549 break;
09550 case '2':
09551 DELETE(prefile, -1, prefile, vmu);
09552 ast_play_and_wait(chan, "vm-tempremoved");
09553 cmd = 't';
09554 break;
09555 case '*':
09556 cmd = 't';
09557 break;
09558 default:
09559 cmd = ast_play_and_wait(chan,
09560 ast_fileexists(prefile, NULL, NULL) > 0 ?
09561 "vm-tempgreeting2" : "vm-tempgreeting");
09562 if (!cmd) {
09563 cmd = ast_waitfordigit(chan, 6000);
09564 }
09565 if (!cmd) {
09566 retries++;
09567 }
09568 if (retries > 3) {
09569 cmd = 't';
09570 }
09571 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09572 }
09573 }
09574 DISPOSE(prefile, -1);
09575 }
09576 if (cmd == 't')
09577 cmd = 0;
09578 return cmd;
09579 }
09580
09581
09582
09583 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09584 {
09585 int cmd = 0;
09586
09587 if (vms->lastmsg > -1) {
09588 cmd = play_message(chan, vmu, vms);
09589 } else {
09590 if (!strcasecmp(vms->fn, "INBOX")) {
09591 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09592 } else {
09593 cmd = ast_play_and_wait(chan, "vm-nomessages");
09594 }
09595 }
09596 return cmd;
09597 }
09598
09599
09600
09601
09602
09603
09604
09605
09606
09607 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09608 {
09609 int cmd = 0;
09610
09611 if (vms->lastmsg > -1) {
09612 cmd = play_message(chan, vmu, vms);
09613 } else {
09614 cmd = ast_play_and_wait(chan, "vm-youhave");
09615 if (!cmd)
09616 cmd = ast_play_and_wait(chan, "vm-no");
09617 if (!cmd) {
09618 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09619 cmd = ast_play_and_wait(chan, vms->fn);
09620 }
09621 if (!cmd)
09622 cmd = ast_play_and_wait(chan, "vm-messages");
09623 }
09624 return cmd;
09625 }
09626
09627
09628
09629
09630
09631
09632
09633
09634
09635
09636 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09637 {
09638 int cmd;
09639
09640 if (vms->lastmsg > -1) {
09641 cmd = play_message(chan, vmu, vms);
09642 } else {
09643 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09644 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09645 if (!cmd) {
09646 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09647 cmd = ast_play_and_wait(chan, vms->fn);
09648 }
09649 if (!cmd)
09650 cmd = ast_play_and_wait(chan, "vm-messages");
09651 } else {
09652 if (!cmd)
09653 cmd = ast_play_and_wait(chan, "vm-messages");
09654 if (!cmd) {
09655 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09656 cmd = ast_play_and_wait(chan, vms->fn);
09657 }
09658 }
09659 }
09660 return cmd;
09661 }
09662
09663
09664
09665
09666
09667
09668
09669
09670
09671 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09672 {
09673 int cmd;
09674
09675 if (vms->lastmsg > -1) {
09676 cmd = play_message(chan, vmu, vms);
09677 } else {
09678 cmd = ast_play_and_wait(chan, "vm-you");
09679 if (!cmd)
09680 cmd = ast_play_and_wait(chan, "vm-haveno");
09681 if (!cmd)
09682 cmd = ast_play_and_wait(chan, "vm-messages");
09683 if (!cmd) {
09684 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09685 cmd = ast_play_and_wait(chan, vms->fn);
09686 }
09687 }
09688 return cmd;
09689 }
09690
09691
09692
09693
09694
09695
09696
09697
09698
09699 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09700 {
09701 int cmd = 0;
09702
09703 if (vms->lastmsg > -1) {
09704 cmd = play_message(chan, vmu, vms);
09705 } else {
09706 cmd = ast_play_and_wait(chan, "vm-no");
09707 if (!cmd) {
09708 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09709 cmd = ast_play_and_wait(chan, vms->fn);
09710 }
09711 }
09712 return cmd;
09713 }
09714
09715
09716
09717
09718
09719
09720
09721
09722
09723
09724
09725
09726 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09727 {
09728 if (!strncasecmp(chan->language, "es", 2) ||
09729 !strncasecmp(chan->language, "it", 2) ||
09730 !strncasecmp(chan->language, "pt", 2) ||
09731 !strncasecmp(chan->language, "gr", 2)) {
09732 return vm_browse_messages_latin(chan, vms, vmu);
09733 } else if (!strncasecmp(chan->language, "he", 2)) {
09734 return vm_browse_messages_he(chan, vms, vmu);
09735 } else if (!strncasecmp(chan->language, "vi", 2)) {
09736 return vm_browse_messages_vi(chan, vms, vmu);
09737 } else if (!strncasecmp(chan->language, "zh", 2)) {
09738 return vm_browse_messages_zh(chan, vms, vmu);
09739 } else {
09740 return vm_browse_messages_en(chan, vms, vmu);
09741 }
09742 }
09743
09744 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09745 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09746 int skipuser, int max_logins, int silent)
09747 {
09748 int useadsi = 0, valid = 0, logretries = 0;
09749 char password[AST_MAX_EXTENSION]="", *passptr;
09750 struct ast_vm_user vmus, *vmu = NULL;
09751
09752
09753 adsi_begin(chan, &useadsi);
09754 if (!skipuser && useadsi)
09755 adsi_login(chan);
09756 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09757 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09758 return -1;
09759 }
09760
09761
09762
09763 while (!valid && (logretries < max_logins)) {
09764
09765 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09766 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09767 return -1;
09768 }
09769 if (ast_strlen_zero(mailbox)) {
09770 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09771 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09772 } else {
09773 ast_verb(3, "Username not entered\n");
09774 return -1;
09775 }
09776 } else if (mailbox[0] == '*') {
09777
09778 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09779 if (ast_exists_extension(chan, chan->context, "a", 1,
09780 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09781 return -1;
09782 }
09783 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09784 mailbox[0] = '\0';
09785 }
09786
09787 if (useadsi)
09788 adsi_password(chan);
09789
09790 if (!ast_strlen_zero(prefix)) {
09791 char fullusername[80] = "";
09792 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09793 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09794 ast_copy_string(mailbox, fullusername, mailbox_size);
09795 }
09796
09797 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09798 vmu = find_user(&vmus, context, mailbox);
09799 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09800
09801 password[0] = '\0';
09802 } else {
09803 if (ast_streamfile(chan, vm_password, chan->language)) {
09804 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09805 return -1;
09806 }
09807 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09808 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09809 return -1;
09810 } else if (password[0] == '*') {
09811
09812 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09813 if (ast_exists_extension(chan, chan->context, "a", 1,
09814 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09815 mailbox[0] = '*';
09816 return -1;
09817 }
09818 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09819 mailbox[0] = '\0';
09820
09821 vmu = NULL;
09822 }
09823 }
09824
09825 if (vmu) {
09826 passptr = vmu->password;
09827 if (passptr[0] == '-') passptr++;
09828 }
09829 if (vmu && !strcmp(passptr, password))
09830 valid++;
09831 else {
09832 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09833 if (!ast_strlen_zero(prefix))
09834 mailbox[0] = '\0';
09835 }
09836 logretries++;
09837 if (!valid) {
09838 if (skipuser || logretries >= max_logins) {
09839 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09840 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09841 return -1;
09842 }
09843 } else {
09844 if (useadsi)
09845 adsi_login(chan);
09846 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09847 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09848 return -1;
09849 }
09850 }
09851 if (ast_waitstream(chan, ""))
09852 return -1;
09853 }
09854 }
09855 if (!valid && (logretries >= max_logins)) {
09856 ast_stopstream(chan);
09857 ast_play_and_wait(chan, "vm-goodbye");
09858 return -1;
09859 }
09860 if (vmu && !skipuser) {
09861 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09862 }
09863 return 0;
09864 }
09865
09866 static int vm_execmain(struct ast_channel *chan, const char *data)
09867 {
09868
09869
09870
09871 int res = -1;
09872 int cmd = 0;
09873 int valid = 0;
09874 char prefixstr[80] ="";
09875 char ext_context[256]="";
09876 int box;
09877 int useadsi = 0;
09878 int skipuser = 0;
09879 struct vm_state vms;
09880 struct ast_vm_user *vmu = NULL, vmus;
09881 char *context = NULL;
09882 int silentexit = 0;
09883 struct ast_flags flags = { 0 };
09884 signed char record_gain = 0;
09885 int play_auto = 0;
09886 int play_folder = 0;
09887 int in_urgent = 0;
09888 #ifdef IMAP_STORAGE
09889 int deleted = 0;
09890 #endif
09891
09892
09893 memset(&vms, 0, sizeof(vms));
09894
09895 vms.lastmsg = -1;
09896
09897 memset(&vmus, 0, sizeof(vmus));
09898
09899 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09900 if (chan->_state != AST_STATE_UP) {
09901 ast_debug(1, "Before ast_answer\n");
09902 ast_answer(chan);
09903 }
09904
09905 if (!ast_strlen_zero(data)) {
09906 char *opts[OPT_ARG_ARRAY_SIZE];
09907 char *parse;
09908 AST_DECLARE_APP_ARGS(args,
09909 AST_APP_ARG(argv0);
09910 AST_APP_ARG(argv1);
09911 );
09912
09913 parse = ast_strdupa(data);
09914
09915 AST_STANDARD_APP_ARGS(args, parse);
09916
09917 if (args.argc == 2) {
09918 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09919 return -1;
09920 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09921 int gain;
09922 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09923 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09924 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09925 return -1;
09926 } else {
09927 record_gain = (signed char) gain;
09928 }
09929 } else {
09930 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09931 }
09932 }
09933 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09934 play_auto = 1;
09935 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09936
09937 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09938 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09939 play_folder = -1;
09940 }
09941 } else {
09942 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09943 }
09944 } else {
09945 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09946 }
09947 if (play_folder > 9 || play_folder < 0) {
09948 ast_log(AST_LOG_WARNING,
09949 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09950 opts[OPT_ARG_PLAYFOLDER]);
09951 play_folder = 0;
09952 }
09953 }
09954 } else {
09955
09956 while (*(args.argv0)) {
09957 if (*(args.argv0) == 's')
09958 ast_set_flag(&flags, OPT_SILENT);
09959 else if (*(args.argv0) == 'p')
09960 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09961 else
09962 break;
09963 (args.argv0)++;
09964 }
09965
09966 }
09967
09968 valid = ast_test_flag(&flags, OPT_SILENT);
09969
09970 if ((context = strchr(args.argv0, '@')))
09971 *context++ = '\0';
09972
09973 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09974 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09975 else
09976 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09977
09978 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09979 skipuser++;
09980 else
09981 valid = 0;
09982 }
09983
09984 if (!valid)
09985 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09986
09987 ast_debug(1, "After vm_authenticate\n");
09988
09989 if (vms.username[0] == '*') {
09990 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09991
09992
09993 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09994 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
09995 res = 0;
09996 goto out;
09997 }
09998 }
09999
10000 if (!res) {
10001 valid = 1;
10002 if (!skipuser)
10003 vmu = &vmus;
10004 } else {
10005 res = 0;
10006 }
10007
10008
10009 adsi_begin(chan, &useadsi);
10010
10011 ast_test_suite_assert(valid);
10012 if (!valid) {
10013 goto out;
10014 }
10015 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10016
10017 #ifdef IMAP_STORAGE
10018 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10019 pthread_setspecific(ts_vmstate.key, &vms);
10020
10021 vms.interactive = 1;
10022 vms.updated = 1;
10023 if (vmu)
10024 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10025 vmstate_insert(&vms);
10026 init_vm_state(&vms);
10027 #endif
10028
10029
10030 if (!ast_strlen_zero(vmu->language))
10031 ast_string_field_set(chan, language, vmu->language);
10032
10033
10034 ast_debug(1, "Before open_mailbox\n");
10035 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10036 if (res < 0)
10037 goto out;
10038 vms.oldmessages = vms.lastmsg + 1;
10039 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10040
10041 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10042 if (res < 0)
10043 goto out;
10044 vms.newmessages = vms.lastmsg + 1;
10045 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10046
10047 in_urgent = 1;
10048 res = open_mailbox(&vms, vmu, 11);
10049 if (res < 0)
10050 goto out;
10051 vms.urgentmessages = vms.lastmsg + 1;
10052 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10053
10054
10055 if (play_auto) {
10056 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10057 if (vms.urgentmessages) {
10058 in_urgent = 1;
10059 res = open_mailbox(&vms, vmu, 11);
10060 } else {
10061 in_urgent = 0;
10062 res = open_mailbox(&vms, vmu, play_folder);
10063 }
10064 if (res < 0)
10065 goto out;
10066
10067
10068 if (vms.lastmsg == -1) {
10069 in_urgent = 0;
10070 cmd = vm_browse_messages(chan, &vms, vmu);
10071 res = 0;
10072 goto out;
10073 }
10074 } else {
10075 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10076
10077 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10078 in_urgent = 0;
10079 play_folder = 1;
10080 if (res < 0)
10081 goto out;
10082 } else if (!vms.urgentmessages && vms.newmessages) {
10083
10084 in_urgent = 0;
10085 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10086 if (res < 0)
10087 goto out;
10088 }
10089 }
10090
10091 if (useadsi)
10092 adsi_status(chan, &vms);
10093 res = 0;
10094
10095
10096 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10097 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10098 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10099 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10100 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10101 if ((cmd == 't') || (cmd == '#')) {
10102
10103 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10104 res = 0;
10105 goto out;
10106 } else if (cmd < 0) {
10107
10108 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10109 res = -1;
10110 goto out;
10111 }
10112 }
10113 #ifdef IMAP_STORAGE
10114 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10115 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10116 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10117 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10118 }
10119 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10120 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10121 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10122 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10123 }
10124 #endif
10125
10126 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10127 if (play_auto) {
10128 cmd = '1';
10129 } else {
10130 cmd = vm_intro(chan, vmu, &vms);
10131 }
10132 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10133
10134 vms.repeats = 0;
10135 vms.starting = 1;
10136 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10137
10138 switch (cmd) {
10139 case '1':
10140 vms.curmsg = 0;
10141
10142 case '5':
10143 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10144 cmd = vm_browse_messages(chan, &vms, vmu);
10145 break;
10146 case '2':
10147 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10148 if (useadsi)
10149 adsi_folders(chan, 0, "Change to folder...");
10150
10151 cmd = get_folder2(chan, "vm-changeto", 0);
10152 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10153 if (cmd == '#') {
10154 cmd = 0;
10155 } else if (cmd > 0) {
10156 cmd = cmd - '0';
10157 res = close_mailbox(&vms, vmu);
10158 if (res == ERROR_LOCK_PATH)
10159 goto out;
10160
10161 if (cmd != 11) in_urgent = 0;
10162 res = open_mailbox(&vms, vmu, cmd);
10163 if (res < 0)
10164 goto out;
10165 play_folder = cmd;
10166 cmd = 0;
10167 }
10168 if (useadsi)
10169 adsi_status2(chan, &vms);
10170
10171 if (!cmd) {
10172 cmd = vm_play_folder_name(chan, vms.vmbox);
10173 }
10174
10175 vms.starting = 1;
10176 vms.curmsg = 0;
10177 break;
10178 case '3':
10179 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10180 cmd = 0;
10181 vms.repeats = 0;
10182 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10183 switch (cmd) {
10184 case '1':
10185 if (vms.lastmsg > -1 && !vms.starting) {
10186 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10187 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10188 res = cmd;
10189 goto out;
10190 }
10191 } else {
10192 cmd = ast_play_and_wait(chan, "vm-sorry");
10193 }
10194 cmd = 't';
10195 break;
10196 case '2':
10197 if (!vms.starting)
10198 ast_verb(3, "Callback Requested\n");
10199 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10200 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10201 if (cmd == 9) {
10202 silentexit = 1;
10203 goto out;
10204 } else if (cmd == ERROR_LOCK_PATH) {
10205 res = cmd;
10206 goto out;
10207 }
10208 } else {
10209 cmd = ast_play_and_wait(chan, "vm-sorry");
10210 }
10211 cmd = 't';
10212 break;
10213 case '3':
10214 if (vms.lastmsg > -1 && !vms.starting) {
10215 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10216 if (cmd == ERROR_LOCK_PATH) {
10217 res = cmd;
10218 goto out;
10219 }
10220 } else {
10221 cmd = ast_play_and_wait(chan, "vm-sorry");
10222 }
10223 cmd = 't';
10224 break;
10225 case '4':
10226 if (!ast_strlen_zero(vmu->dialout)) {
10227 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10228 if (cmd == 9) {
10229 silentexit = 1;
10230 goto out;
10231 }
10232 } else {
10233 cmd = ast_play_and_wait(chan, "vm-sorry");
10234 }
10235 cmd = 't';
10236 break;
10237
10238 case '5':
10239 if (ast_test_flag(vmu, VM_SVMAIL)) {
10240 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10241 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10242 res = cmd;
10243 goto out;
10244 }
10245 } else {
10246 cmd = ast_play_and_wait(chan, "vm-sorry");
10247 }
10248 cmd = 't';
10249 break;
10250
10251 case '*':
10252 cmd = 't';
10253 break;
10254
10255 default:
10256 cmd = 0;
10257 if (!vms.starting) {
10258 cmd = ast_play_and_wait(chan, "vm-toreply");
10259 }
10260 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10261 cmd = ast_play_and_wait(chan, "vm-tocallback");
10262 }
10263 if (!cmd && !vms.starting) {
10264 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10265 }
10266 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10267 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10268 }
10269 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10270 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10271 }
10272 if (!cmd) {
10273 cmd = ast_play_and_wait(chan, "vm-starmain");
10274 }
10275 if (!cmd) {
10276 cmd = ast_waitfordigit(chan, 6000);
10277 }
10278 if (!cmd) {
10279 vms.repeats++;
10280 }
10281 if (vms.repeats > 3) {
10282 cmd = 't';
10283 }
10284 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10285 }
10286 }
10287 if (cmd == 't') {
10288 cmd = 0;
10289 vms.repeats = 0;
10290 }
10291 break;
10292 case '4':
10293 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10294 if (vms.curmsg > 0) {
10295 vms.curmsg--;
10296 cmd = play_message(chan, vmu, &vms);
10297 } else {
10298
10299
10300
10301
10302 if (in_urgent == 0 && vms.urgentmessages > 0) {
10303
10304 in_urgent = 1;
10305 res = close_mailbox(&vms, vmu);
10306 if (res == ERROR_LOCK_PATH)
10307 goto out;
10308 res = open_mailbox(&vms, vmu, 11);
10309 if (res < 0)
10310 goto out;
10311 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10312 vms.curmsg = vms.lastmsg;
10313 if (vms.lastmsg < 0) {
10314 cmd = ast_play_and_wait(chan, "vm-nomore");
10315 }
10316 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10317 vms.curmsg = vms.lastmsg;
10318 cmd = play_message(chan, vmu, &vms);
10319 } else {
10320 cmd = ast_play_and_wait(chan, "vm-nomore");
10321 }
10322 }
10323 break;
10324 case '6':
10325 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10326 if (vms.curmsg < vms.lastmsg) {
10327 vms.curmsg++;
10328 cmd = play_message(chan, vmu, &vms);
10329 } else {
10330 if (in_urgent && vms.newmessages > 0) {
10331
10332
10333
10334
10335 in_urgent = 0;
10336 res = close_mailbox(&vms, vmu);
10337 if (res == ERROR_LOCK_PATH)
10338 goto out;
10339 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10340 if (res < 0)
10341 goto out;
10342 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10343 vms.curmsg = -1;
10344 if (vms.lastmsg < 0) {
10345 cmd = ast_play_and_wait(chan, "vm-nomore");
10346 }
10347 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10348 vms.curmsg = 0;
10349 cmd = play_message(chan, vmu, &vms);
10350 } else {
10351 cmd = ast_play_and_wait(chan, "vm-nomore");
10352 }
10353 }
10354 break;
10355 case '7':
10356 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10357 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10358 if (useadsi)
10359 adsi_delete(chan, &vms);
10360 if (vms.deleted[vms.curmsg]) {
10361 if (play_folder == 0) {
10362 if (in_urgent) {
10363 vms.urgentmessages--;
10364 } else {
10365 vms.newmessages--;
10366 }
10367 }
10368 else if (play_folder == 1)
10369 vms.oldmessages--;
10370 cmd = ast_play_and_wait(chan, "vm-deleted");
10371 } else {
10372 if (play_folder == 0) {
10373 if (in_urgent) {
10374 vms.urgentmessages++;
10375 } else {
10376 vms.newmessages++;
10377 }
10378 }
10379 else if (play_folder == 1)
10380 vms.oldmessages++;
10381 cmd = ast_play_and_wait(chan, "vm-undeleted");
10382 }
10383 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10384 if (vms.curmsg < vms.lastmsg) {
10385 vms.curmsg++;
10386 cmd = play_message(chan, vmu, &vms);
10387 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10388 vms.curmsg = 0;
10389 cmd = play_message(chan, vmu, &vms);
10390 } else {
10391
10392
10393
10394
10395 if (in_urgent == 1) {
10396
10397 in_urgent = 0;
10398 res = close_mailbox(&vms, vmu);
10399 if (res == ERROR_LOCK_PATH)
10400 goto out;
10401 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10402 if (res < 0)
10403 goto out;
10404 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10405 vms.curmsg = -1;
10406 if (vms.lastmsg < 0) {
10407 cmd = ast_play_and_wait(chan, "vm-nomore");
10408 }
10409 } else {
10410 cmd = ast_play_and_wait(chan, "vm-nomore");
10411 }
10412 }
10413 }
10414 } else
10415 cmd = 0;
10416 #ifdef IMAP_STORAGE
10417 deleted = 1;
10418 #endif
10419 break;
10420
10421 case '8':
10422 if (vms.lastmsg > -1) {
10423 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10424 if (cmd == ERROR_LOCK_PATH) {
10425 res = cmd;
10426 goto out;
10427 }
10428 } else {
10429
10430
10431
10432
10433 if (in_urgent == 1 && vms.newmessages > 0) {
10434
10435 in_urgent = 0;
10436 res = close_mailbox(&vms, vmu);
10437 if (res == ERROR_LOCK_PATH)
10438 goto out;
10439 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10440 if (res < 0)
10441 goto out;
10442 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10443 vms.curmsg = -1;
10444 if (vms.lastmsg < 0) {
10445 cmd = ast_play_and_wait(chan, "vm-nomore");
10446 }
10447 } else {
10448 cmd = ast_play_and_wait(chan, "vm-nomore");
10449 }
10450 }
10451 break;
10452 case '9':
10453 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10454 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10455
10456 cmd = 0;
10457 break;
10458 }
10459 if (useadsi)
10460 adsi_folders(chan, 1, "Save to folder...");
10461 cmd = get_folder2(chan, "vm-savefolder", 1);
10462 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10463 box = 0;
10464 if (cmd == '#') {
10465 cmd = 0;
10466 break;
10467 } else if (cmd > 0) {
10468 box = cmd = cmd - '0';
10469 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10470 if (cmd == ERROR_LOCK_PATH) {
10471 res = cmd;
10472 goto out;
10473 #ifndef IMAP_STORAGE
10474 } else if (!cmd) {
10475 vms.deleted[vms.curmsg] = 1;
10476 #endif
10477 } else {
10478 vms.deleted[vms.curmsg] = 0;
10479 vms.heard[vms.curmsg] = 0;
10480 }
10481 }
10482 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10483 if (useadsi)
10484 adsi_message(chan, &vms);
10485 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10486 if (!cmd) {
10487 cmd = ast_play_and_wait(chan, "vm-message");
10488 if (!cmd)
10489 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10490 if (!cmd)
10491 cmd = ast_play_and_wait(chan, "vm-savedto");
10492 if (!cmd)
10493 cmd = vm_play_folder_name(chan, vms.fn);
10494 } else {
10495 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10496 }
10497 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10498 if (vms.curmsg < vms.lastmsg) {
10499 vms.curmsg++;
10500 cmd = play_message(chan, vmu, &vms);
10501 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10502 vms.curmsg = 0;
10503 cmd = play_message(chan, vmu, &vms);
10504 } else {
10505
10506
10507
10508
10509 if (in_urgent == 1 && vms.newmessages > 0) {
10510
10511 in_urgent = 0;
10512 res = close_mailbox(&vms, vmu);
10513 if (res == ERROR_LOCK_PATH)
10514 goto out;
10515 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10516 if (res < 0)
10517 goto out;
10518 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10519 vms.curmsg = -1;
10520 if (vms.lastmsg < 0) {
10521 cmd = ast_play_and_wait(chan, "vm-nomore");
10522 }
10523 } else {
10524 cmd = ast_play_and_wait(chan, "vm-nomore");
10525 }
10526 }
10527 }
10528 break;
10529 case '*':
10530 if (!vms.starting) {
10531 cmd = ast_play_and_wait(chan, "vm-onefor");
10532 if (!strncasecmp(chan->language, "he", 2)) {
10533 cmd = ast_play_and_wait(chan, "vm-for");
10534 }
10535 if (!cmd)
10536 cmd = vm_play_folder_name(chan, vms.vmbox);
10537 if (!cmd)
10538 cmd = ast_play_and_wait(chan, "vm-opts");
10539 if (!cmd)
10540 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10541 } else
10542 cmd = 0;
10543 break;
10544 case '0':
10545 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10546 if (useadsi)
10547 adsi_status(chan, &vms);
10548 break;
10549 default:
10550 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10551 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10552 break;
10553 }
10554 }
10555 if ((cmd == 't') || (cmd == '#')) {
10556
10557 res = 0;
10558 } else {
10559
10560 res = -1;
10561 }
10562
10563 out:
10564 if (res > -1) {
10565 ast_stopstream(chan);
10566 adsi_goodbye(chan);
10567 if (valid && res != OPERATOR_EXIT) {
10568 if (silentexit)
10569 res = ast_play_and_wait(chan, "vm-dialout");
10570 else
10571 res = ast_play_and_wait(chan, "vm-goodbye");
10572 }
10573 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10574 res = 0;
10575 }
10576 if (useadsi)
10577 ast_adsi_unload_session(chan);
10578 }
10579 if (vmu)
10580 close_mailbox(&vms, vmu);
10581 if (valid) {
10582 int new = 0, old = 0, urgent = 0;
10583 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10584 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10585
10586 run_externnotify(vmu->context, vmu->mailbox, NULL);
10587 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10588 queue_mwi_event(ext_context, urgent, new, old);
10589 }
10590 #ifdef IMAP_STORAGE
10591
10592 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10593 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10594 ast_mutex_lock(&vms.lock);
10595 #ifdef HAVE_IMAP_TK2006
10596 if (LEVELUIDPLUS (vms.mailstream)) {
10597 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10598 } else
10599 #endif
10600 mail_expunge(vms.mailstream);
10601 ast_mutex_unlock(&vms.lock);
10602 }
10603
10604
10605 if (vmu) {
10606 vmstate_delete(&vms);
10607 }
10608 #endif
10609 if (vmu)
10610 free_user(vmu);
10611
10612 #ifdef IMAP_STORAGE
10613 pthread_setspecific(ts_vmstate.key, NULL);
10614 #endif
10615 return res;
10616 }
10617
10618 static int vm_exec(struct ast_channel *chan, const char *data)
10619 {
10620 int res = 0;
10621 char *tmp;
10622 struct leave_vm_options leave_options;
10623 struct ast_flags flags = { 0 };
10624 char *opts[OPT_ARG_ARRAY_SIZE];
10625 AST_DECLARE_APP_ARGS(args,
10626 AST_APP_ARG(argv0);
10627 AST_APP_ARG(argv1);
10628 );
10629
10630 memset(&leave_options, 0, sizeof(leave_options));
10631
10632 if (chan->_state != AST_STATE_UP)
10633 ast_answer(chan);
10634
10635 if (!ast_strlen_zero(data)) {
10636 tmp = ast_strdupa(data);
10637 AST_STANDARD_APP_ARGS(args, tmp);
10638 if (args.argc == 2) {
10639 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10640 return -1;
10641 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10642 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10643 int gain;
10644
10645 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10646 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10647 return -1;
10648 } else {
10649 leave_options.record_gain = (signed char) gain;
10650 }
10651 }
10652 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10653 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10654 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10655 }
10656 }
10657 } else {
10658 char temp[256];
10659 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10660 if (res < 0)
10661 return res;
10662 if (ast_strlen_zero(temp))
10663 return 0;
10664 args.argv0 = ast_strdupa(temp);
10665 }
10666
10667 res = leave_voicemail(chan, args.argv0, &leave_options);
10668 if (res == 't') {
10669 ast_play_and_wait(chan, "vm-goodbye");
10670 res = 0;
10671 }
10672
10673 if (res == OPERATOR_EXIT) {
10674 res = 0;
10675 }
10676
10677 if (res == ERROR_LOCK_PATH) {
10678 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10679 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10680 res = 0;
10681 }
10682
10683 return res;
10684 }
10685
10686 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10687 {
10688 struct ast_vm_user *vmu;
10689
10690 if (!ast_strlen_zero(box) && box[0] == '*') {
10691 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10692 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10693 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10694 "\n\tand will be ignored.\n", box, context);
10695 return NULL;
10696 }
10697
10698 AST_LIST_TRAVERSE(&users, vmu, list) {
10699 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10700 if (strcasecmp(vmu->context, context)) {
10701 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10702 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10703 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10704 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10705 }
10706 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10707 return NULL;
10708 }
10709 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10710 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10711 return NULL;
10712 }
10713 }
10714
10715 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10716 return NULL;
10717
10718 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10719 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10720
10721 AST_LIST_INSERT_TAIL(&users, vmu, list);
10722
10723 return vmu;
10724 }
10725
10726 static int append_mailbox(const char *context, const char *box, const char *data)
10727 {
10728
10729 char *tmp;
10730 char *stringp;
10731 char *s;
10732 struct ast_vm_user *vmu;
10733 char *mailbox_full;
10734 int new = 0, old = 0, urgent = 0;
10735 char secretfn[PATH_MAX] = "";
10736
10737 tmp = ast_strdupa(data);
10738
10739 if (!(vmu = find_or_create(context, box)))
10740 return -1;
10741
10742 populate_defaults(vmu);
10743
10744 stringp = tmp;
10745 if ((s = strsep(&stringp, ","))) {
10746 if (!ast_strlen_zero(s) && s[0] == '*') {
10747 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10748 "\n\tmust be reset in voicemail.conf.\n", box);
10749 }
10750
10751 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10752 }
10753 if (stringp && (s = strsep(&stringp, ","))) {
10754 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10755 }
10756 if (stringp && (s = strsep(&stringp, ","))) {
10757 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10758 }
10759 if (stringp && (s = strsep(&stringp, ","))) {
10760 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10761 }
10762 if (stringp && (s = strsep(&stringp, ","))) {
10763 apply_options(vmu, s);
10764 }
10765
10766 switch (vmu->passwordlocation) {
10767 case OPT_PWLOC_SPOOLDIR:
10768 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10769 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10770 }
10771
10772 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10773 strcpy(mailbox_full, box);
10774 strcat(mailbox_full, "@");
10775 strcat(mailbox_full, context);
10776
10777 inboxcount2(mailbox_full, &urgent, &new, &old);
10778 queue_mwi_event(mailbox_full, urgent, new, old);
10779
10780 return 0;
10781 }
10782
10783 AST_TEST_DEFINE(test_voicemail_vmuser)
10784 {
10785 int res = 0;
10786 struct ast_vm_user *vmu;
10787
10788 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10789 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10790 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10791 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10792 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10793 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10794 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10795 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10796 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10797 #ifdef IMAP_STORAGE
10798 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10799 "imapfolder=INBOX|imapvmshareid=6000";
10800 #endif
10801
10802 switch (cmd) {
10803 case TEST_INIT:
10804 info->name = "vmuser";
10805 info->category = "/apps/app_voicemail/";
10806 info->summary = "Vmuser unit test";
10807 info->description =
10808 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10809 return AST_TEST_NOT_RUN;
10810 case TEST_EXECUTE:
10811 break;
10812 }
10813
10814 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10815 return AST_TEST_NOT_RUN;
10816 }
10817 populate_defaults(vmu);
10818 ast_set_flag(vmu, VM_ALLOCED);
10819
10820 apply_options(vmu, options_string);
10821
10822 if (!ast_test_flag(vmu, VM_ATTACH)) {
10823 ast_test_status_update(test, "Parse failure for attach option\n");
10824 res = 1;
10825 }
10826 if (strcasecmp(vmu->attachfmt, "wav49")) {
10827 ast_test_status_update(test, "Parse failure for attachftm option\n");
10828 res = 1;
10829 }
10830 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10831 ast_test_status_update(test, "Parse failure for serveremail option\n");
10832 res = 1;
10833 }
10834 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10835 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10836 res = 1;
10837 }
10838 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10839 ast_test_status_update(test, "Parse failure for emailbody option\n");
10840 res = 1;
10841 }
10842 if (strcasecmp(vmu->zonetag, "central")) {
10843 ast_test_status_update(test, "Parse failure for tz option\n");
10844 res = 1;
10845 }
10846 if (!ast_test_flag(vmu, VM_DELETE)) {
10847 ast_test_status_update(test, "Parse failure for delete option\n");
10848 res = 1;
10849 }
10850 if (!ast_test_flag(vmu, VM_SAYCID)) {
10851 ast_test_status_update(test, "Parse failure for saycid option\n");
10852 res = 1;
10853 }
10854 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10855 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10856 res = 1;
10857 }
10858 if (!ast_test_flag(vmu, VM_REVIEW)) {
10859 ast_test_status_update(test, "Parse failure for review option\n");
10860 res = 1;
10861 }
10862 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10863 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10864 res = 1;
10865 }
10866 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10867 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10868 res = 1;
10869 }
10870 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10871 ast_test_status_update(test, "Parse failure for operator option\n");
10872 res = 1;
10873 }
10874 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10875 ast_test_status_update(test, "Parse failure for envelope option\n");
10876 res = 1;
10877 }
10878 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10879 ast_test_status_update(test, "Parse failure for moveheard option\n");
10880 res = 1;
10881 }
10882 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10883 ast_test_status_update(test, "Parse failure for sayduration option\n");
10884 res = 1;
10885 }
10886 if (vmu->saydurationm != 5) {
10887 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10888 res = 1;
10889 }
10890 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10891 ast_test_status_update(test, "Parse failure for forcename option\n");
10892 res = 1;
10893 }
10894 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10895 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10896 res = 1;
10897 }
10898 if (strcasecmp(vmu->callback, "somecontext")) {
10899 ast_test_status_update(test, "Parse failure for callbacks option\n");
10900 res = 1;
10901 }
10902 if (strcasecmp(vmu->dialout, "somecontext2")) {
10903 ast_test_status_update(test, "Parse failure for dialout option\n");
10904 res = 1;
10905 }
10906 if (strcasecmp(vmu->exit, "somecontext3")) {
10907 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10908 res = 1;
10909 }
10910 if (vmu->minsecs != 10) {
10911 ast_test_status_update(test, "Parse failure for minsecs option\n");
10912 res = 1;
10913 }
10914 if (vmu->maxsecs != 100) {
10915 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10916 res = 1;
10917 }
10918 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10919 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10920 res = 1;
10921 }
10922 if (vmu->maxdeletedmsg != 50) {
10923 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10924 res = 1;
10925 }
10926 if (vmu->volgain != 1.3) {
10927 ast_test_status_update(test, "Parse failure for volgain option\n");
10928 res = 1;
10929 }
10930 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10931 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10932 res = 1;
10933 }
10934 #ifdef IMAP_STORAGE
10935 apply_options(vmu, option_string2);
10936
10937 if (strcasecmp(vmu->imapuser, "imapuser")) {
10938 ast_test_status_update(test, "Parse failure for imapuser option\n");
10939 res = 1;
10940 }
10941 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10942 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10943 res = 1;
10944 }
10945 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10946 ast_test_status_update(test, "Parse failure for imapfolder option\n");
10947 res = 1;
10948 }
10949 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10950 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10951 res = 1;
10952 }
10953 #endif
10954
10955 free_user(vmu);
10956 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10957 }
10958
10959 static int vm_box_exists(struct ast_channel *chan, const char *data)
10960 {
10961 struct ast_vm_user svm;
10962 char *context, *box;
10963 AST_DECLARE_APP_ARGS(args,
10964 AST_APP_ARG(mbox);
10965 AST_APP_ARG(options);
10966 );
10967 static int dep_warning = 0;
10968
10969 if (ast_strlen_zero(data)) {
10970 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10971 return -1;
10972 }
10973
10974 if (!dep_warning) {
10975 dep_warning = 1;
10976 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10977 }
10978
10979 box = ast_strdupa(data);
10980
10981 AST_STANDARD_APP_ARGS(args, box);
10982
10983 if (args.options) {
10984 }
10985
10986 if ((context = strchr(args.mbox, '@'))) {
10987 *context = '\0';
10988 context++;
10989 }
10990
10991 if (find_user(&svm, context, args.mbox)) {
10992 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10993 } else
10994 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10995
10996 return 0;
10997 }
10998
10999 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11000 {
11001 struct ast_vm_user svm;
11002 AST_DECLARE_APP_ARGS(arg,
11003 AST_APP_ARG(mbox);
11004 AST_APP_ARG(context);
11005 );
11006
11007 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11008
11009 if (ast_strlen_zero(arg.mbox)) {
11010 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11011 return -1;
11012 }
11013
11014 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11015 return 0;
11016 }
11017
11018 static struct ast_custom_function mailbox_exists_acf = {
11019 .name = "MAILBOX_EXISTS",
11020 .read = acf_mailbox_exists,
11021 };
11022
11023 static int vmauthenticate(struct ast_channel *chan, const char *data)
11024 {
11025 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11026 struct ast_vm_user vmus;
11027 char *options = NULL;
11028 int silent = 0, skipuser = 0;
11029 int res = -1;
11030
11031 if (data) {
11032 s = ast_strdupa(data);
11033 user = strsep(&s, ",");
11034 options = strsep(&s, ",");
11035 if (user) {
11036 s = user;
11037 user = strsep(&s, "@");
11038 context = strsep(&s, "");
11039 if (!ast_strlen_zero(user))
11040 skipuser++;
11041 ast_copy_string(mailbox, user, sizeof(mailbox));
11042 }
11043 }
11044
11045 if (options) {
11046 silent = (strchr(options, 's')) != NULL;
11047 }
11048
11049 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11050 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11051 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11052 ast_play_and_wait(chan, "auth-thankyou");
11053 res = 0;
11054 } else if (mailbox[0] == '*') {
11055
11056 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11057 res = 0;
11058 }
11059 }
11060
11061 return res;
11062 }
11063
11064 static char *show_users_realtime(int fd, const char *context)
11065 {
11066 struct ast_config *cfg;
11067 const char *cat = NULL;
11068
11069 if (!(cfg = ast_load_realtime_multientry("voicemail",
11070 "context", context, SENTINEL))) {
11071 return CLI_FAILURE;
11072 }
11073
11074 ast_cli(fd,
11075 "\n"
11076 "=============================================================\n"
11077 "=== Configured Voicemail Users ==============================\n"
11078 "=============================================================\n"
11079 "===\n");
11080
11081 while ((cat = ast_category_browse(cfg, cat))) {
11082 struct ast_variable *var = NULL;
11083 ast_cli(fd,
11084 "=== Mailbox ...\n"
11085 "===\n");
11086 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11087 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11088 ast_cli(fd,
11089 "===\n"
11090 "=== ---------------------------------------------------------\n"
11091 "===\n");
11092 }
11093
11094 ast_cli(fd,
11095 "=============================================================\n"
11096 "\n");
11097
11098 ast_config_destroy(cfg);
11099
11100 return CLI_SUCCESS;
11101 }
11102
11103 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11104 {
11105 int which = 0;
11106 int wordlen;
11107 struct ast_vm_user *vmu;
11108 const char *context = "";
11109
11110
11111 if (pos > 4)
11112 return NULL;
11113 if (pos == 3)
11114 return (state == 0) ? ast_strdup("for") : NULL;
11115 wordlen = strlen(word);
11116 AST_LIST_TRAVERSE(&users, vmu, list) {
11117 if (!strncasecmp(word, vmu->context, wordlen)) {
11118 if (context && strcmp(context, vmu->context) && ++which > state)
11119 return ast_strdup(vmu->context);
11120
11121 context = vmu->context;
11122 }
11123 }
11124 return NULL;
11125 }
11126
11127
11128 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11129 {
11130 struct ast_vm_user *vmu;
11131 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11132 const char *context = NULL;
11133 int users_counter = 0;
11134
11135 switch (cmd) {
11136 case CLI_INIT:
11137 e->command = "voicemail show users";
11138 e->usage =
11139 "Usage: voicemail show users [for <context>]\n"
11140 " Lists all mailboxes currently set up\n";
11141 return NULL;
11142 case CLI_GENERATE:
11143 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11144 }
11145
11146 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11147 return CLI_SHOWUSAGE;
11148 if (a->argc == 5) {
11149 if (strcmp(a->argv[3],"for"))
11150 return CLI_SHOWUSAGE;
11151 context = a->argv[4];
11152 }
11153
11154 if (ast_check_realtime("voicemail")) {
11155 if (!context) {
11156 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11157 return CLI_SHOWUSAGE;
11158 }
11159 return show_users_realtime(a->fd, context);
11160 }
11161
11162 AST_LIST_LOCK(&users);
11163 if (AST_LIST_EMPTY(&users)) {
11164 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11165 AST_LIST_UNLOCK(&users);
11166 return CLI_FAILURE;
11167 }
11168 if (!context) {
11169 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11170 } else {
11171 int count = 0;
11172 AST_LIST_TRAVERSE(&users, vmu, list) {
11173 if (!strcmp(context, vmu->context)) {
11174 count++;
11175 break;
11176 }
11177 }
11178 if (count) {
11179 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11180 } else {
11181 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11182 AST_LIST_UNLOCK(&users);
11183 return CLI_FAILURE;
11184 }
11185 }
11186 AST_LIST_TRAVERSE(&users, vmu, list) {
11187 int newmsgs = 0, oldmsgs = 0;
11188 char count[12], tmp[256] = "";
11189
11190 if (!context || !strcmp(context, vmu->context)) {
11191 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11192 inboxcount(tmp, &newmsgs, &oldmsgs);
11193 snprintf(count, sizeof(count), "%d", newmsgs);
11194 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11195 users_counter++;
11196 }
11197 }
11198 AST_LIST_UNLOCK(&users);
11199 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11200 return CLI_SUCCESS;
11201 }
11202
11203
11204 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11205 {
11206 struct vm_zone *zone;
11207 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11208 char *res = CLI_SUCCESS;
11209
11210 switch (cmd) {
11211 case CLI_INIT:
11212 e->command = "voicemail show zones";
11213 e->usage =
11214 "Usage: voicemail show zones\n"
11215 " Lists zone message formats\n";
11216 return NULL;
11217 case CLI_GENERATE:
11218 return NULL;
11219 }
11220
11221 if (a->argc != 3)
11222 return CLI_SHOWUSAGE;
11223
11224 AST_LIST_LOCK(&zones);
11225 if (!AST_LIST_EMPTY(&zones)) {
11226 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11227 AST_LIST_TRAVERSE(&zones, zone, list) {
11228 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11229 }
11230 } else {
11231 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11232 res = CLI_FAILURE;
11233 }
11234 AST_LIST_UNLOCK(&zones);
11235
11236 return res;
11237 }
11238
11239
11240 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11241 {
11242 switch (cmd) {
11243 case CLI_INIT:
11244 e->command = "voicemail reload";
11245 e->usage =
11246 "Usage: voicemail reload\n"
11247 " Reload voicemail configuration\n";
11248 return NULL;
11249 case CLI_GENERATE:
11250 return NULL;
11251 }
11252
11253 if (a->argc != 2)
11254 return CLI_SHOWUSAGE;
11255
11256 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11257 load_config(1);
11258
11259 return CLI_SUCCESS;
11260 }
11261
11262 static struct ast_cli_entry cli_voicemail[] = {
11263 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11264 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11265 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11266 };
11267
11268 #ifdef IMAP_STORAGE
11269 #define DATA_EXPORT_VM_USERS(USER) \
11270 USER(ast_vm_user, context, AST_DATA_STRING) \
11271 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11272 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11273 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11274 USER(ast_vm_user, email, AST_DATA_STRING) \
11275 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11276 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11277 USER(ast_vm_user, pager, AST_DATA_STRING) \
11278 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11279 USER(ast_vm_user, language, AST_DATA_STRING) \
11280 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11281 USER(ast_vm_user, callback, AST_DATA_STRING) \
11282 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11283 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11284 USER(ast_vm_user, exit, AST_DATA_STRING) \
11285 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11286 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11287 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11288 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11289 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11290 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11291 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11292 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11293 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11294 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11295 #else
11296 #define DATA_EXPORT_VM_USERS(USER) \
11297 USER(ast_vm_user, context, AST_DATA_STRING) \
11298 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11299 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11300 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11301 USER(ast_vm_user, email, AST_DATA_STRING) \
11302 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11303 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11304 USER(ast_vm_user, pager, AST_DATA_STRING) \
11305 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11306 USER(ast_vm_user, language, AST_DATA_STRING) \
11307 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11308 USER(ast_vm_user, callback, AST_DATA_STRING) \
11309 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11310 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11311 USER(ast_vm_user, exit, AST_DATA_STRING) \
11312 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11313 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11314 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11315 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11316 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11317 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11318 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11319 #endif
11320
11321 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11322
11323 #define DATA_EXPORT_VM_ZONES(ZONE) \
11324 ZONE(vm_zone, name, AST_DATA_STRING) \
11325 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11326 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11327
11328 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11329
11330
11331
11332
11333
11334
11335
11336
11337 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11338 struct ast_data *data_root, struct ast_vm_user *user)
11339 {
11340 struct ast_data *data_user, *data_zone;
11341 struct ast_data *data_state;
11342 struct vm_zone *zone = NULL;
11343 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11344 char ext_context[256] = "";
11345
11346 data_user = ast_data_add_node(data_root, "user");
11347 if (!data_user) {
11348 return -1;
11349 }
11350
11351 ast_data_add_structure(ast_vm_user, data_user, user);
11352
11353 AST_LIST_LOCK(&zones);
11354 AST_LIST_TRAVERSE(&zones, zone, list) {
11355 if (!strcmp(zone->name, user->zonetag)) {
11356 break;
11357 }
11358 }
11359 AST_LIST_UNLOCK(&zones);
11360
11361
11362 data_state = ast_data_add_node(data_user, "state");
11363 if (!data_state) {
11364 return -1;
11365 }
11366 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11367 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11368 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11369 ast_data_add_int(data_state, "newmsg", newmsg);
11370 ast_data_add_int(data_state, "oldmsg", oldmsg);
11371
11372 if (zone) {
11373 data_zone = ast_data_add_node(data_user, "zone");
11374 ast_data_add_structure(vm_zone, data_zone, zone);
11375 }
11376
11377 if (!ast_data_search_match(search, data_user)) {
11378 ast_data_remove_node(data_root, data_user);
11379 }
11380
11381 return 0;
11382 }
11383
11384 static int vm_users_data_provider_get(const struct ast_data_search *search,
11385 struct ast_data *data_root)
11386 {
11387 struct ast_vm_user *user;
11388
11389 AST_LIST_LOCK(&users);
11390 AST_LIST_TRAVERSE(&users, user, list) {
11391 vm_users_data_provider_get_helper(search, data_root, user);
11392 }
11393 AST_LIST_UNLOCK(&users);
11394
11395 return 0;
11396 }
11397
11398 static const struct ast_data_handler vm_users_data_provider = {
11399 .version = AST_DATA_HANDLER_VERSION,
11400 .get = vm_users_data_provider_get
11401 };
11402
11403 static const struct ast_data_entry vm_data_providers[] = {
11404 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11405 };
11406
11407 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11408 {
11409 int new = 0, old = 0, urgent = 0;
11410
11411 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11412
11413 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11414 mwi_sub->old_urgent = urgent;
11415 mwi_sub->old_new = new;
11416 mwi_sub->old_old = old;
11417 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11418 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11419 }
11420 }
11421
11422 static void poll_subscribed_mailboxes(void)
11423 {
11424 struct mwi_sub *mwi_sub;
11425
11426 AST_RWLIST_RDLOCK(&mwi_subs);
11427 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11428 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11429 poll_subscribed_mailbox(mwi_sub);
11430 }
11431 }
11432 AST_RWLIST_UNLOCK(&mwi_subs);
11433 }
11434
11435 static void *mb_poll_thread(void *data)
11436 {
11437 while (poll_thread_run) {
11438 struct timespec ts = { 0, };
11439 struct timeval wait;
11440
11441 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11442 ts.tv_sec = wait.tv_sec;
11443 ts.tv_nsec = wait.tv_usec * 1000;
11444
11445 ast_mutex_lock(&poll_lock);
11446 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11447 ast_mutex_unlock(&poll_lock);
11448
11449 if (!poll_thread_run)
11450 break;
11451
11452 poll_subscribed_mailboxes();
11453 }
11454
11455 return NULL;
11456 }
11457
11458 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11459 {
11460 ast_free(mwi_sub);
11461 }
11462
11463 static int handle_unsubscribe(void *datap)
11464 {
11465 struct mwi_sub *mwi_sub;
11466 uint32_t *uniqueid = datap;
11467
11468 AST_RWLIST_WRLOCK(&mwi_subs);
11469 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11470 if (mwi_sub->uniqueid == *uniqueid) {
11471 AST_LIST_REMOVE_CURRENT(entry);
11472 break;
11473 }
11474 }
11475 AST_RWLIST_TRAVERSE_SAFE_END
11476 AST_RWLIST_UNLOCK(&mwi_subs);
11477
11478 if (mwi_sub)
11479 mwi_sub_destroy(mwi_sub);
11480
11481 ast_free(uniqueid);
11482 return 0;
11483 }
11484
11485 static int handle_subscribe(void *datap)
11486 {
11487 unsigned int len;
11488 struct mwi_sub *mwi_sub;
11489 struct mwi_sub_task *p = datap;
11490
11491 len = sizeof(*mwi_sub);
11492 if (!ast_strlen_zero(p->mailbox))
11493 len += strlen(p->mailbox);
11494
11495 if (!ast_strlen_zero(p->context))
11496 len += strlen(p->context) + 1;
11497
11498 if (!(mwi_sub = ast_calloc(1, len)))
11499 return -1;
11500
11501 mwi_sub->uniqueid = p->uniqueid;
11502 if (!ast_strlen_zero(p->mailbox))
11503 strcpy(mwi_sub->mailbox, p->mailbox);
11504
11505 if (!ast_strlen_zero(p->context)) {
11506 strcat(mwi_sub->mailbox, "@");
11507 strcat(mwi_sub->mailbox, p->context);
11508 }
11509
11510 AST_RWLIST_WRLOCK(&mwi_subs);
11511 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11512 AST_RWLIST_UNLOCK(&mwi_subs);
11513 ast_free((void *) p->mailbox);
11514 ast_free((void *) p->context);
11515 ast_free(p);
11516 poll_subscribed_mailbox(mwi_sub);
11517 return 0;
11518 }
11519
11520 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11521 {
11522 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11523
11524 if (!uniqueid) {
11525 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11526 return;
11527 }
11528
11529 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11530 ast_free(uniqueid);
11531 return;
11532 }
11533
11534 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11535 ast_free(uniqueid);
11536 return;
11537 }
11538
11539 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11540 *uniqueid = u;
11541 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11542 ast_free(uniqueid);
11543 }
11544 }
11545
11546 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11547 {
11548 struct mwi_sub_task *mwist;
11549
11550 if (ast_event_get_type(event) != AST_EVENT_SUB)
11551 return;
11552
11553 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11554 return;
11555
11556 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11557 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11558 return;
11559 }
11560 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11561 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11562 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11563
11564 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11565 ast_free(mwist);
11566 }
11567 }
11568
11569 static void start_poll_thread(void)
11570 {
11571 int errcode;
11572 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11573 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11574 AST_EVENT_IE_END);
11575
11576 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11577 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11578 AST_EVENT_IE_END);
11579
11580 if (mwi_sub_sub)
11581 ast_event_report_subs(mwi_sub_sub);
11582
11583 poll_thread_run = 1;
11584
11585 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11586 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11587 }
11588 }
11589
11590 static void stop_poll_thread(void)
11591 {
11592 poll_thread_run = 0;
11593
11594 if (mwi_sub_sub) {
11595 ast_event_unsubscribe(mwi_sub_sub);
11596 mwi_sub_sub = NULL;
11597 }
11598
11599 if (mwi_unsub_sub) {
11600 ast_event_unsubscribe(mwi_unsub_sub);
11601 mwi_unsub_sub = NULL;
11602 }
11603
11604 ast_mutex_lock(&poll_lock);
11605 ast_cond_signal(&poll_cond);
11606 ast_mutex_unlock(&poll_lock);
11607
11608 pthread_join(poll_thread, NULL);
11609
11610 poll_thread = AST_PTHREADT_NULL;
11611 }
11612
11613
11614 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11615 {
11616 struct ast_vm_user *vmu = NULL;
11617 const char *id = astman_get_header(m, "ActionID");
11618 char actionid[128] = "";
11619
11620 if (!ast_strlen_zero(id))
11621 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11622
11623 AST_LIST_LOCK(&users);
11624
11625 if (AST_LIST_EMPTY(&users)) {
11626 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11627 AST_LIST_UNLOCK(&users);
11628 return RESULT_SUCCESS;
11629 }
11630
11631 astman_send_ack(s, m, "Voicemail user list will follow");
11632
11633 AST_LIST_TRAVERSE(&users, vmu, list) {
11634 char dirname[256];
11635
11636 #ifdef IMAP_STORAGE
11637 int new, old;
11638 inboxcount(vmu->mailbox, &new, &old);
11639 #endif
11640
11641 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11642 astman_append(s,
11643 "%s"
11644 "Event: VoicemailUserEntry\r\n"
11645 "VMContext: %s\r\n"
11646 "VoiceMailbox: %s\r\n"
11647 "Fullname: %s\r\n"
11648 "Email: %s\r\n"
11649 "Pager: %s\r\n"
11650 "ServerEmail: %s\r\n"
11651 "MailCommand: %s\r\n"
11652 "Language: %s\r\n"
11653 "TimeZone: %s\r\n"
11654 "Callback: %s\r\n"
11655 "Dialout: %s\r\n"
11656 "UniqueID: %s\r\n"
11657 "ExitContext: %s\r\n"
11658 "SayDurationMinimum: %d\r\n"
11659 "SayEnvelope: %s\r\n"
11660 "SayCID: %s\r\n"
11661 "AttachMessage: %s\r\n"
11662 "AttachmentFormat: %s\r\n"
11663 "DeleteMessage: %s\r\n"
11664 "VolumeGain: %.2f\r\n"
11665 "CanReview: %s\r\n"
11666 "CallOperator: %s\r\n"
11667 "MaxMessageCount: %d\r\n"
11668 "MaxMessageLength: %d\r\n"
11669 "NewMessageCount: %d\r\n"
11670 #ifdef IMAP_STORAGE
11671 "OldMessageCount: %d\r\n"
11672 "IMAPUser: %s\r\n"
11673 #endif
11674 "\r\n",
11675 actionid,
11676 vmu->context,
11677 vmu->mailbox,
11678 vmu->fullname,
11679 vmu->email,
11680 vmu->pager,
11681 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11682 mailcmd,
11683 vmu->language,
11684 vmu->zonetag,
11685 vmu->callback,
11686 vmu->dialout,
11687 vmu->uniqueid,
11688 vmu->exit,
11689 vmu->saydurationm,
11690 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11691 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11692 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11693 vmu->attachfmt,
11694 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11695 vmu->volgain,
11696 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11697 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11698 vmu->maxmsg,
11699 vmu->maxsecs,
11700 #ifdef IMAP_STORAGE
11701 new, old, vmu->imapuser
11702 #else
11703 count_messages(vmu, dirname)
11704 #endif
11705 );
11706 }
11707 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11708
11709 AST_LIST_UNLOCK(&users);
11710
11711 return RESULT_SUCCESS;
11712 }
11713
11714
11715 static void free_vm_users(void)
11716 {
11717 struct ast_vm_user *current;
11718 AST_LIST_LOCK(&users);
11719 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11720 ast_set_flag(current, VM_ALLOCED);
11721 free_user(current);
11722 }
11723 AST_LIST_UNLOCK(&users);
11724 }
11725
11726
11727 static void free_vm_zones(void)
11728 {
11729 struct vm_zone *zcur;
11730 AST_LIST_LOCK(&zones);
11731 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11732 free_zone(zcur);
11733 AST_LIST_UNLOCK(&zones);
11734 }
11735
11736 static const char *substitute_escapes(const char *value)
11737 {
11738 char *current;
11739
11740
11741 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11742
11743 ast_str_reset(str);
11744
11745
11746 for (current = (char *) value; *current; current++) {
11747 if (*current == '\\') {
11748 current++;
11749 if (!*current) {
11750 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11751 break;
11752 }
11753 switch (*current) {
11754 case '\\':
11755 ast_str_append(&str, 0, "\\");
11756 break;
11757 case 'r':
11758 ast_str_append(&str, 0, "\r");
11759 break;
11760 case 'n':
11761 #ifdef IMAP_STORAGE
11762 if (!str->used || str->str[str->used - 1] != '\r') {
11763 ast_str_append(&str, 0, "\r");
11764 }
11765 #endif
11766 ast_str_append(&str, 0, "\n");
11767 break;
11768 case 't':
11769 ast_str_append(&str, 0, "\t");
11770 break;
11771 default:
11772 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11773 break;
11774 }
11775 } else {
11776 ast_str_append(&str, 0, "%c", *current);
11777 }
11778 }
11779
11780 return ast_str_buffer(str);
11781 }
11782
11783 static int load_config(int reload)
11784 {
11785 struct ast_config *cfg, *ucfg;
11786 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11787 int res;
11788
11789 ast_unload_realtime("voicemail");
11790 ast_unload_realtime("voicemail_data");
11791
11792 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11793 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11794 return 0;
11795 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11796 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11797 ucfg = NULL;
11798 }
11799 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11800 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11801 ast_config_destroy(ucfg);
11802 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11803 return 0;
11804 }
11805 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11806 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11807 return 0;
11808 } else {
11809 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11810 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11811 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11812 ucfg = NULL;
11813 }
11814 }
11815
11816 res = actual_load_config(reload, cfg, ucfg);
11817
11818 ast_config_destroy(cfg);
11819 ast_config_destroy(ucfg);
11820
11821 return res;
11822 }
11823
11824 #ifdef TEST_FRAMEWORK
11825 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11826 {
11827 ast_unload_realtime("voicemail");
11828 ast_unload_realtime("voicemail_data");
11829 return actual_load_config(reload, cfg, ucfg);
11830 }
11831 #endif
11832
11833 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11834 {
11835 struct ast_vm_user *current;
11836 char *cat;
11837 struct ast_variable *var;
11838 const char *val;
11839 char *q, *stringp, *tmp;
11840 int x;
11841 unsigned int tmpadsi[4];
11842 char secretfn[PATH_MAX] = "";
11843
11844 #ifdef IMAP_STORAGE
11845 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11846 #endif
11847
11848 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11849 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11850 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11851 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11852 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11853
11854
11855 free_vm_users();
11856
11857
11858 free_vm_zones();
11859
11860 AST_LIST_LOCK(&users);
11861
11862 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11863 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11864
11865 if (cfg) {
11866
11867
11868 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11869 val = "default";
11870 ast_copy_string(userscontext, val, sizeof(userscontext));
11871
11872 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11873 val = "yes";
11874 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11875
11876 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11877 val = "no";
11878 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11879
11880 volgain = 0.0;
11881 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11882 sscanf(val, "%30lf", &volgain);
11883
11884 #ifdef ODBC_STORAGE
11885 strcpy(odbc_database, "asterisk");
11886 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11887 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11888 }
11889 strcpy(odbc_table, "voicemessages");
11890 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11891 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11892 }
11893 #endif
11894
11895 strcpy(mailcmd, SENDMAIL);
11896 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11897 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11898
11899 maxsilence = 0;
11900 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11901 maxsilence = atoi(val);
11902 if (maxsilence > 0)
11903 maxsilence *= 1000;
11904 }
11905
11906 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11907 maxmsg = MAXMSG;
11908 } else {
11909 maxmsg = atoi(val);
11910 if (maxmsg < 0) {
11911 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11912 maxmsg = MAXMSG;
11913 } else if (maxmsg > MAXMSGLIMIT) {
11914 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11915 maxmsg = MAXMSGLIMIT;
11916 }
11917 }
11918
11919 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11920 maxdeletedmsg = 0;
11921 } else {
11922 if (sscanf(val, "%30d", &x) == 1)
11923 maxdeletedmsg = x;
11924 else if (ast_true(val))
11925 maxdeletedmsg = MAXMSG;
11926 else
11927 maxdeletedmsg = 0;
11928
11929 if (maxdeletedmsg < 0) {
11930 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11931 maxdeletedmsg = MAXMSG;
11932 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11933 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11934 maxdeletedmsg = MAXMSGLIMIT;
11935 }
11936 }
11937
11938
11939 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11940 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11941 }
11942
11943
11944 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11945 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11946 }
11947
11948
11949 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11950 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11951 pwdchange = PWDCHANGE_EXTERNAL;
11952 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11953 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11954 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11955 }
11956
11957
11958 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11959 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11960 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11961 }
11962
11963 #ifdef IMAP_STORAGE
11964
11965 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11966 ast_copy_string(imapserver, val, sizeof(imapserver));
11967 } else {
11968 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11969 }
11970
11971 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11972 ast_copy_string(imapport, val, sizeof(imapport));
11973 } else {
11974 ast_copy_string(imapport, "143", sizeof(imapport));
11975 }
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11978 ast_copy_string(imapflags, val, sizeof(imapflags));
11979 }
11980
11981 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11982 ast_copy_string(authuser, val, sizeof(authuser));
11983 }
11984
11985 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11986 ast_copy_string(authpassword, val, sizeof(authpassword));
11987 }
11988
11989 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11990 if (ast_false(val))
11991 expungeonhangup = 0;
11992 else
11993 expungeonhangup = 1;
11994 } else {
11995 expungeonhangup = 1;
11996 }
11997
11998 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11999 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12000 } else {
12001 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12002 }
12003 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12004 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12005 }
12006 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12007 imapgreetings = ast_true(val);
12008 } else {
12009 imapgreetings = 0;
12010 }
12011 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12012 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12013 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12014
12015 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12016 } else {
12017 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12018 }
12019
12020
12021
12022
12023
12024 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12025 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12026 } else {
12027 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12028 }
12029
12030 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12031 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12032 } else {
12033 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12034 }
12035
12036 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12037 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12038 } else {
12039 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12040 }
12041
12042 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12043 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12044 } else {
12045 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12046 }
12047
12048
12049 imapversion++;
12050 #endif
12051
12052 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12053 ast_copy_string(externnotify, val, sizeof(externnotify));
12054 ast_debug(1, "found externnotify: %s\n", externnotify);
12055 } else {
12056 externnotify[0] = '\0';
12057 }
12058
12059
12060 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12061 ast_debug(1, "Enabled SMDI voicemail notification\n");
12062 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12063 smdi_iface = ast_smdi_interface_find(val);
12064 } else {
12065 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12066 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12067 }
12068 if (!smdi_iface) {
12069 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12070 }
12071 }
12072
12073
12074 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12075 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12076 silencethreshold = atoi(val);
12077
12078 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12079 val = ASTERISK_USERNAME;
12080 ast_copy_string(serveremail, val, sizeof(serveremail));
12081
12082 vmmaxsecs = 0;
12083 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12084 if (sscanf(val, "%30d", &x) == 1) {
12085 vmmaxsecs = x;
12086 } else {
12087 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12088 }
12089 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12090 static int maxmessage_deprecate = 0;
12091 if (maxmessage_deprecate == 0) {
12092 maxmessage_deprecate = 1;
12093 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12094 }
12095 if (sscanf(val, "%30d", &x) == 1) {
12096 vmmaxsecs = x;
12097 } else {
12098 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12099 }
12100 }
12101
12102 vmminsecs = 0;
12103 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12104 if (sscanf(val, "%30d", &x) == 1) {
12105 vmminsecs = x;
12106 if (maxsilence / 1000 >= vmminsecs) {
12107 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12108 }
12109 } else {
12110 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12111 }
12112 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12113 static int maxmessage_deprecate = 0;
12114 if (maxmessage_deprecate == 0) {
12115 maxmessage_deprecate = 1;
12116 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12117 }
12118 if (sscanf(val, "%30d", &x) == 1) {
12119 vmminsecs = x;
12120 if (maxsilence / 1000 >= vmminsecs) {
12121 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12122 }
12123 } else {
12124 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12125 }
12126 }
12127
12128 val = ast_variable_retrieve(cfg, "general", "format");
12129 if (!val) {
12130 val = "wav";
12131 } else {
12132 tmp = ast_strdupa(val);
12133 val = ast_format_str_reduce(tmp);
12134 if (!val) {
12135 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12136 val = "wav";
12137 }
12138 }
12139 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12140
12141 skipms = 3000;
12142 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12143 if (sscanf(val, "%30d", &x) == 1) {
12144 maxgreet = x;
12145 } else {
12146 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12147 }
12148 }
12149
12150 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12151 if (sscanf(val, "%30d", &x) == 1) {
12152 skipms = x;
12153 } else {
12154 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12155 }
12156 }
12157
12158 maxlogins = 3;
12159 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12160 if (sscanf(val, "%30d", &x) == 1) {
12161 maxlogins = x;
12162 } else {
12163 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12164 }
12165 }
12166
12167 minpassword = MINPASSWORD;
12168 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12169 if (sscanf(val, "%30d", &x) == 1) {
12170 minpassword = x;
12171 } else {
12172 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12173 }
12174 }
12175
12176
12177 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12178 val = "no";
12179 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12180
12181
12182 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12183 val = "no";
12184 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12185
12186 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12187 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12188 stringp = ast_strdupa(val);
12189 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12190 if (!ast_strlen_zero(stringp)) {
12191 q = strsep(&stringp, ",");
12192 while ((*q == ' ')||(*q == '\t'))
12193 q++;
12194 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12195 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12196 } else {
12197 cidinternalcontexts[x][0] = '\0';
12198 }
12199 }
12200 }
12201 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12202 ast_debug(1, "VM Review Option disabled globally\n");
12203 val = "no";
12204 }
12205 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12206
12207
12208 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12209 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12210 val = "no";
12211 } else {
12212 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12213 }
12214 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12215 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12216 ast_debug(1, "VM next message wrap disabled globally\n");
12217 val = "no";
12218 }
12219 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12220
12221 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12222 ast_debug(1, "VM Operator break disabled globally\n");
12223 val = "no";
12224 }
12225 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12226
12227 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12228 ast_debug(1, "VM CID Info before msg disabled globally\n");
12229 val = "no";
12230 }
12231 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12232
12233 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12234 ast_debug(1, "Send Voicemail msg disabled globally\n");
12235 val = "no";
12236 }
12237 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12238
12239 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12240 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12241 val = "yes";
12242 }
12243 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12244
12245 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12246 ast_debug(1, "Move Heard enabled globally\n");
12247 val = "yes";
12248 }
12249 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12250
12251 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12252 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12253 val = "no";
12254 }
12255 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12256
12257 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12258 ast_debug(1, "Duration info before msg enabled globally\n");
12259 val = "yes";
12260 }
12261 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12262
12263 saydurationminfo = 2;
12264 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12265 if (sscanf(val, "%30d", &x) == 1) {
12266 saydurationminfo = x;
12267 } else {
12268 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12269 }
12270 }
12271
12272 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12273 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12274 val = "no";
12275 }
12276 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12277
12278 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12279 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12280 ast_debug(1, "found dialout context: %s\n", dialcontext);
12281 } else {
12282 dialcontext[0] = '\0';
12283 }
12284
12285 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12286 ast_copy_string(callcontext, val, sizeof(callcontext));
12287 ast_debug(1, "found callback context: %s\n", callcontext);
12288 } else {
12289 callcontext[0] = '\0';
12290 }
12291
12292 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12293 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12294 ast_debug(1, "found operator context: %s\n", exitcontext);
12295 } else {
12296 exitcontext[0] = '\0';
12297 }
12298
12299
12300 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12301 ast_copy_string(vm_password, val, sizeof(vm_password));
12302 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12303 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12304 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12305 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12306 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12307 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12308 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12309 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12310 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12311 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12312 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12313 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12314 }
12315 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12316 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12317 }
12318
12319 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12320 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12321 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12322 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12323 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12324 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12325 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12326 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12327 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12328 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12329
12330 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12331 val = "no";
12332 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12333
12334 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12335 val = "voicemail.conf";
12336 }
12337 if (!(strcmp(val, "spooldir"))) {
12338 passwordlocation = OPT_PWLOC_SPOOLDIR;
12339 } else {
12340 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12341 }
12342
12343 poll_freq = DEFAULT_POLL_FREQ;
12344 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12345 if (sscanf(val, "%30u", &poll_freq) != 1) {
12346 poll_freq = DEFAULT_POLL_FREQ;
12347 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12348 }
12349 }
12350
12351 poll_mailboxes = 0;
12352 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12353 poll_mailboxes = ast_true(val);
12354
12355 memset(fromstring, 0, sizeof(fromstring));
12356 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12357 strcpy(charset, "ISO-8859-1");
12358 if (emailbody) {
12359 ast_free(emailbody);
12360 emailbody = NULL;
12361 }
12362 if (emailsubject) {
12363 ast_free(emailsubject);
12364 emailsubject = NULL;
12365 }
12366 if (pagerbody) {
12367 ast_free(pagerbody);
12368 pagerbody = NULL;
12369 }
12370 if (pagersubject) {
12371 ast_free(pagersubject);
12372 pagersubject = NULL;
12373 }
12374 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12375 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12376 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12377 ast_copy_string(fromstring, val, sizeof(fromstring));
12378 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12379 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12380 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12381 ast_copy_string(charset, val, sizeof(charset));
12382 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12383 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12384 for (x = 0; x < 4; x++) {
12385 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12386 }
12387 }
12388 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12389 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12390 for (x = 0; x < 4; x++) {
12391 memcpy(&adsisec[x], &tmpadsi[x], 1);
12392 }
12393 }
12394 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12395 if (atoi(val)) {
12396 adsiver = atoi(val);
12397 }
12398 }
12399 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12400 ast_copy_string(zonetag, val, sizeof(zonetag));
12401 }
12402 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12403 ast_copy_string(locale, val, sizeof(locale));
12404 }
12405 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12406 emailsubject = ast_strdup(substitute_escapes(val));
12407 }
12408 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12409 emailbody = ast_strdup(substitute_escapes(val));
12410 }
12411 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12412 pagersubject = ast_strdup(substitute_escapes(val));
12413 }
12414 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12415 pagerbody = ast_strdup(substitute_escapes(val));
12416 }
12417
12418
12419 if (ucfg) {
12420 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12421 if (!strcasecmp(cat, "general")) {
12422 continue;
12423 }
12424 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12425 continue;
12426 if ((current = find_or_create(userscontext, cat))) {
12427 populate_defaults(current);
12428 apply_options_full(current, ast_variable_browse(ucfg, cat));
12429 ast_copy_string(current->context, userscontext, sizeof(current->context));
12430 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12431 current->passwordlocation = OPT_PWLOC_USERSCONF;
12432 }
12433
12434 switch (current->passwordlocation) {
12435 case OPT_PWLOC_SPOOLDIR:
12436 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12437 read_password_from_file(secretfn, current->password, sizeof(current->password));
12438 }
12439 }
12440 }
12441 }
12442
12443
12444 cat = ast_category_browse(cfg, NULL);
12445 while (cat) {
12446 if (strcasecmp(cat, "general")) {
12447 var = ast_variable_browse(cfg, cat);
12448 if (strcasecmp(cat, "zonemessages")) {
12449
12450 while (var) {
12451 append_mailbox(cat, var->name, var->value);
12452 var = var->next;
12453 }
12454 } else {
12455
12456 while (var) {
12457 struct vm_zone *z;
12458 if ((z = ast_malloc(sizeof(*z)))) {
12459 char *msg_format, *tzone;
12460 msg_format = ast_strdupa(var->value);
12461 tzone = strsep(&msg_format, "|,");
12462 if (msg_format) {
12463 ast_copy_string(z->name, var->name, sizeof(z->name));
12464 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12465 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12466 AST_LIST_LOCK(&zones);
12467 AST_LIST_INSERT_HEAD(&zones, z, list);
12468 AST_LIST_UNLOCK(&zones);
12469 } else {
12470 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12471 ast_free(z);
12472 }
12473 } else {
12474 AST_LIST_UNLOCK(&users);
12475 return -1;
12476 }
12477 var = var->next;
12478 }
12479 }
12480 }
12481 cat = ast_category_browse(cfg, cat);
12482 }
12483
12484 AST_LIST_UNLOCK(&users);
12485
12486 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12487 start_poll_thread();
12488 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12489 stop_poll_thread();;
12490
12491 return 0;
12492 } else {
12493 AST_LIST_UNLOCK(&users);
12494 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12495 return 0;
12496 }
12497 }
12498
12499 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12500 {
12501 int res = -1;
12502 char dir[PATH_MAX];
12503 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12504 ast_debug(2, "About to try retrieving name file %s\n", dir);
12505 RETRIEVE(dir, -1, mailbox, context);
12506 if (ast_fileexists(dir, NULL, NULL)) {
12507 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12508 }
12509 DISPOSE(dir, -1);
12510 return res;
12511 }
12512
12513 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12514 struct ast_config *pwconf;
12515 struct ast_flags config_flags = { 0 };
12516
12517 pwconf = ast_config_load(secretfn, config_flags);
12518 if (valid_config(pwconf)) {
12519 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12520 if (val) {
12521 ast_copy_string(password, val, passwordlen);
12522 ast_config_destroy(pwconf);
12523 return;
12524 }
12525 ast_config_destroy(pwconf);
12526 }
12527 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12528 }
12529
12530 static int write_password_to_file(const char *secretfn, const char *password) {
12531 struct ast_config *conf;
12532 struct ast_category *cat;
12533 struct ast_variable *var;
12534 int res = -1;
12535
12536 if (!(conf = ast_config_new())) {
12537 ast_log(LOG_ERROR, "Error creating new config structure\n");
12538 return res;
12539 }
12540 if (!(cat = ast_category_new("general", "", 1))) {
12541 ast_log(LOG_ERROR, "Error creating new category structure\n");
12542 ast_config_destroy(conf);
12543 return res;
12544 }
12545 if (!(var = ast_variable_new("password", password, ""))) {
12546 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12547 ast_config_destroy(conf);
12548 ast_category_destroy(cat);
12549 return res;
12550 }
12551 ast_category_append(conf, cat);
12552 ast_variable_append(cat, var);
12553 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12554 res = 0;
12555 } else {
12556 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12557 }
12558
12559 ast_config_destroy(conf);
12560 return res;
12561 }
12562
12563 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12564 {
12565 char *context;
12566 char *args_copy;
12567 int res;
12568
12569 if (ast_strlen_zero(data)) {
12570 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12571 return -1;
12572 }
12573
12574 args_copy = ast_strdupa(data);
12575 if ((context = strchr(args_copy, '@'))) {
12576 *context++ = '\0';
12577 } else {
12578 context = "default";
12579 }
12580
12581 if ((res = sayname(chan, args_copy, context) < 0)) {
12582 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12583 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12584 if (!res) {
12585 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12586 }
12587 }
12588
12589 return res;
12590 }
12591
12592 #ifdef TEST_FRAMEWORK
12593 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12594 {
12595 return 0;
12596 }
12597
12598 static struct ast_frame *fake_read(struct ast_channel *ast)
12599 {
12600 return &ast_null_frame;
12601 }
12602
12603 AST_TEST_DEFINE(test_voicemail_vmsayname)
12604 {
12605 char dir[PATH_MAX];
12606 char dir2[PATH_MAX];
12607 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12608 static const char TEST_EXTENSION[] = "1234";
12609
12610 struct ast_channel *test_channel1 = NULL;
12611 int res = -1;
12612
12613 static const struct ast_channel_tech fake_tech = {
12614 .write = fake_write,
12615 .read = fake_read,
12616 };
12617
12618 switch (cmd) {
12619 case TEST_INIT:
12620 info->name = "vmsayname_exec";
12621 info->category = "/apps/app_voicemail/";
12622 info->summary = "Vmsayname unit test";
12623 info->description =
12624 "This tests passing various parameters to vmsayname";
12625 return AST_TEST_NOT_RUN;
12626 case TEST_EXECUTE:
12627 break;
12628 }
12629
12630 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12631 NULL, NULL, 0, 0, "TestChannel1"))) {
12632 goto exit_vmsayname_test;
12633 }
12634
12635
12636 test_channel1->nativeformats = AST_FORMAT_GSM;
12637 test_channel1->writeformat = AST_FORMAT_GSM;
12638 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12639 test_channel1->readformat = AST_FORMAT_GSM;
12640 test_channel1->rawreadformat = AST_FORMAT_GSM;
12641 test_channel1->tech = &fake_tech;
12642
12643 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12644 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12645 if (!(res = vmsayname_exec(test_channel1, dir))) {
12646 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12647 if (ast_fileexists(dir, NULL, NULL)) {
12648 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12649 res = -1;
12650 goto exit_vmsayname_test;
12651 } else {
12652
12653 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12654 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12655 goto exit_vmsayname_test;
12656 }
12657 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12658 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12659
12660 if ((res = symlink(dir, dir2))) {
12661 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12662 goto exit_vmsayname_test;
12663 }
12664 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12665 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12666 res = vmsayname_exec(test_channel1, dir);
12667
12668
12669 unlink(dir2);
12670 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12671 rmdir(dir2);
12672 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12673 rmdir(dir2);
12674 }
12675 }
12676
12677 exit_vmsayname_test:
12678
12679 if (test_channel1) {
12680 ast_hangup(test_channel1);
12681 }
12682
12683 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12684 }
12685
12686 AST_TEST_DEFINE(test_voicemail_msgcount)
12687 {
12688 int i, j, res = AST_TEST_PASS, syserr;
12689 struct ast_vm_user *vmu;
12690 struct ast_vm_user svm;
12691 struct vm_state vms;
12692 #ifdef IMAP_STORAGE
12693 struct ast_channel *chan = NULL;
12694 #endif
12695 struct {
12696 char dir[256];
12697 char file[256];
12698 char txtfile[256];
12699 } tmp[3];
12700 char syscmd[256];
12701 const char origweasels[] = "tt-weasels";
12702 const char testcontext[] = "test";
12703 const char testmailbox[] = "00000000";
12704 const char testspec[] = "00000000@test";
12705 FILE *txt;
12706 int new, old, urgent;
12707 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12708 const int folder2mbox[3] = { 1, 11, 0 };
12709 const int expected_results[3][12] = {
12710
12711 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12712 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12713 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12714 };
12715
12716 switch (cmd) {
12717 case TEST_INIT:
12718 info->name = "test_voicemail_msgcount";
12719 info->category = "/apps/app_voicemail/";
12720 info->summary = "Test Voicemail status checks";
12721 info->description =
12722 "Verify that message counts are correct when retrieved through the public API";
12723 return AST_TEST_NOT_RUN;
12724 case TEST_EXECUTE:
12725 break;
12726 }
12727
12728
12729 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12730 if ((syserr = ast_safe_system(syscmd))) {
12731 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12732 syserr > 0 ? strerror(syserr) : "unable to fork()");
12733 return AST_TEST_FAIL;
12734 }
12735
12736 #ifdef IMAP_STORAGE
12737 if (!(chan = ast_dummy_channel_alloc())) {
12738 ast_test_status_update(test, "Unable to create dummy channel\n");
12739 return AST_TEST_FAIL;
12740 }
12741 #endif
12742
12743 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12744 !(vmu = find_or_create(testcontext, testmailbox))) {
12745 ast_test_status_update(test, "Cannot create vmu structure\n");
12746 ast_unreplace_sigchld();
12747 #ifdef IMAP_STORAGE
12748 chan = ast_channel_unref(chan);
12749 #endif
12750 return AST_TEST_FAIL;
12751 }
12752
12753 populate_defaults(vmu);
12754 memset(&vms, 0, sizeof(vms));
12755
12756
12757 for (i = 0; i < 3; i++) {
12758 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12759 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12760 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12761
12762 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12763 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12764 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12765 if ((syserr = ast_safe_system(syscmd))) {
12766 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12767 syserr > 0 ? strerror(syserr) : "unable to fork()");
12768 ast_unreplace_sigchld();
12769 #ifdef IMAP_STORAGE
12770 chan = ast_channel_unref(chan);
12771 #endif
12772 return AST_TEST_FAIL;
12773 }
12774 }
12775
12776 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12777 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12778 fclose(txt);
12779 } else {
12780 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12781 res = AST_TEST_FAIL;
12782 break;
12783 }
12784 open_mailbox(&vms, vmu, folder2mbox[i]);
12785 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12786
12787
12788 for (j = 0; j < 3; j++) {
12789
12790 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12791 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12792 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12793 res = AST_TEST_FAIL;
12794 }
12795 }
12796
12797 new = old = urgent = 0;
12798 if (ast_app_inboxcount(testspec, &new, &old)) {
12799 ast_test_status_update(test, "inboxcount returned failure\n");
12800 res = AST_TEST_FAIL;
12801 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12802 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12803 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12804 res = AST_TEST_FAIL;
12805 }
12806
12807 new = old = urgent = 0;
12808 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12809 ast_test_status_update(test, "inboxcount2 returned failure\n");
12810 res = AST_TEST_FAIL;
12811 } else if (old != expected_results[i][6 + 0] ||
12812 urgent != expected_results[i][6 + 1] ||
12813 new != expected_results[i][6 + 2] ) {
12814 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12815 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12816 res = AST_TEST_FAIL;
12817 }
12818
12819 new = old = urgent = 0;
12820 for (j = 0; j < 3; j++) {
12821 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12822 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12823 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12824 res = AST_TEST_FAIL;
12825 }
12826 }
12827 }
12828
12829 for (i = 0; i < 3; i++) {
12830
12831
12832
12833 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12834 DISPOSE(tmp[i].dir, 0);
12835 }
12836
12837 if (vms.deleted) {
12838 ast_free(vms.deleted);
12839 }
12840 if (vms.heard) {
12841 ast_free(vms.heard);
12842 }
12843
12844 #ifdef IMAP_STORAGE
12845 chan = ast_channel_unref(chan);
12846 #endif
12847
12848
12849 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12850 if ((syserr = ast_safe_system(syscmd))) {
12851 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12852 syserr > 0 ? strerror(syserr) : "unable to fork()");
12853 }
12854
12855 return res;
12856 }
12857
12858 AST_TEST_DEFINE(test_voicemail_notify_endl)
12859 {
12860 int res = AST_TEST_PASS;
12861 char testcontext[] = "test";
12862 char testmailbox[] = "00000000";
12863 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12864 char attach[256], attach2[256];
12865 char buf[256] = "";
12866 struct ast_channel *chan = NULL;
12867 struct ast_vm_user *vmu, vmus = {
12868 .flags = 0,
12869 };
12870 FILE *file;
12871 struct {
12872 char *name;
12873 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12874 void *location;
12875 union {
12876 int intval;
12877 char *strval;
12878 } u;
12879 } test_items[] = {
12880 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12881 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12882 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12883 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12884 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12885 { "attach2", STRPTR, attach2, .u.strval = "" },
12886 { "attach", STRPTR, attach, .u.strval = "" },
12887 };
12888 int which;
12889
12890 switch (cmd) {
12891 case TEST_INIT:
12892 info->name = "test_voicemail_notify_endl";
12893 info->category = "/apps/app_voicemail/";
12894 info->summary = "Test Voicemail notification end-of-line";
12895 info->description =
12896 "Verify that notification emails use a consistent end-of-line character";
12897 return AST_TEST_NOT_RUN;
12898 case TEST_EXECUTE:
12899 break;
12900 }
12901
12902 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12903 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12904
12905 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12906 !(vmu = find_or_create(testcontext, testmailbox))) {
12907 ast_test_status_update(test, "Cannot create vmu structure\n");
12908 return AST_TEST_NOT_RUN;
12909 }
12910
12911 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12912 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12913 return AST_TEST_NOT_RUN;
12914 }
12915
12916 populate_defaults(vmu);
12917 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12918 #ifdef IMAP_STORAGE
12919
12920 #endif
12921
12922 file = tmpfile();
12923 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12924
12925 rewind(file);
12926 if (ftruncate(fileno(file), 0)) {
12927 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12928 res = AST_TEST_FAIL;
12929 break;
12930 }
12931
12932
12933 if (test_items[which].type == INT) {
12934 *((int *) test_items[which].location) = test_items[which].u.intval;
12935 } else if (test_items[which].type == FLAGVAL) {
12936 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12937 ast_clear_flag(vmu, test_items[which].u.intval);
12938 } else {
12939 ast_set_flag(vmu, test_items[which].u.intval);
12940 }
12941 } else if (test_items[which].type == STATIC) {
12942 strcpy(test_items[which].location, test_items[which].u.strval);
12943 } else if (test_items[which].type == STRPTR) {
12944 test_items[which].location = test_items[which].u.strval;
12945 }
12946
12947 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12948 rewind(file);
12949 while (fgets(buf, sizeof(buf), file)) {
12950 if (
12951 #ifdef IMAP_STORAGE
12952 buf[strlen(buf) - 2] != '\r'
12953 #else
12954 buf[strlen(buf) - 2] == '\r'
12955 #endif
12956 || buf[strlen(buf) - 1] != '\n') {
12957 res = AST_TEST_FAIL;
12958 }
12959 }
12960 }
12961 fclose(file);
12962 return res;
12963 }
12964
12965 AST_TEST_DEFINE(test_voicemail_load_config)
12966 {
12967 int res = AST_TEST_PASS;
12968 struct ast_vm_user *vmu;
12969 struct ast_config *cfg;
12970 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12971 int fd;
12972 FILE *file;
12973 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12974
12975 switch (cmd) {
12976 case TEST_INIT:
12977 info->name = "test_voicemail_load_config";
12978 info->category = "/apps/app_voicemail/";
12979 info->summary = "Test loading Voicemail config";
12980 info->description =
12981 "Verify that configuration is loaded consistently. "
12982 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12983 "some options were loaded after the mailboxes were instantiated, causing "
12984 "those options not to be set correctly.";
12985 return AST_TEST_NOT_RUN;
12986 case TEST_EXECUTE:
12987 break;
12988 }
12989
12990
12991 if ((fd = mkstemp(config_filename)) < 0) {
12992 return AST_TEST_FAIL;
12993 }
12994 if (!(file = fdopen(fd, "w"))) {
12995 close(fd);
12996 unlink(config_filename);
12997 return AST_TEST_FAIL;
12998 }
12999 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13000 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13001 fputs("00000002 => 9999,Mrs. Test\n", file);
13002 fclose(file);
13003
13004 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
13005 res = AST_TEST_FAIL;
13006 goto cleanup;
13007 }
13008
13009 load_config_from_memory(1, cfg, NULL);
13010 ast_config_destroy(cfg);
13011
13012 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13013 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13014 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13015
13016 AST_LIST_LOCK(&users);
13017 AST_LIST_TRAVERSE(&users, vmu, list) {
13018 if (!strcmp(vmu->mailbox, "00000001")) {
13019 if (0);
13020 CHECK(vmu, callback, "othercontext")
13021 CHECK(vmu, locale, "nl_NL.UTF-8")
13022 CHECK(vmu, zonetag, "central")
13023 } else if (!strcmp(vmu->mailbox, "00000002")) {
13024 if (0);
13025 CHECK(vmu, callback, "somecontext")
13026 CHECK(vmu, locale, "de_DE.UTF-8")
13027 CHECK(vmu, zonetag, "european")
13028 }
13029 }
13030 AST_LIST_UNLOCK(&users);
13031
13032 #undef CHECK
13033
13034
13035 load_config(1);
13036
13037 cleanup:
13038 unlink(config_filename);
13039 return res;
13040 }
13041
13042 #endif
13043
13044 static int reload(void)
13045 {
13046 return load_config(1);
13047 }
13048
13049 static int unload_module(void)
13050 {
13051 int res;
13052
13053 res = ast_unregister_application(app);
13054 res |= ast_unregister_application(app2);
13055 res |= ast_unregister_application(app3);
13056 res |= ast_unregister_application(app4);
13057 res |= ast_unregister_application(sayname_app);
13058 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13059 res |= ast_manager_unregister("VoicemailUsersList");
13060 res |= ast_data_unregister(NULL);
13061 #ifdef TEST_FRAMEWORK
13062 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13063 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13064 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13065 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13066 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13067 #endif
13068 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13069 ast_uninstall_vm_functions();
13070 ao2_ref(inprocess_container, -1);
13071
13072 if (poll_thread != AST_PTHREADT_NULL)
13073 stop_poll_thread();
13074
13075 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13076 ast_unload_realtime("voicemail");
13077 ast_unload_realtime("voicemail_data");
13078
13079 free_vm_users();
13080 free_vm_zones();
13081 return res;
13082 }
13083
13084 static int load_module(void)
13085 {
13086 int res;
13087 my_umask = umask(0);
13088 umask(my_umask);
13089
13090 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13091 return AST_MODULE_LOAD_DECLINE;
13092 }
13093
13094
13095 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13096
13097 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13098 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13099 }
13100
13101 if ((res = load_config(0)))
13102 return res;
13103
13104 res = ast_register_application_xml(app, vm_exec);
13105 res |= ast_register_application_xml(app2, vm_execmain);
13106 res |= ast_register_application_xml(app3, vm_box_exists);
13107 res |= ast_register_application_xml(app4, vmauthenticate);
13108 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13109 res |= ast_custom_function_register(&mailbox_exists_acf);
13110 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13111 #ifdef TEST_FRAMEWORK
13112 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13113 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13114 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13115 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13116 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13117 #endif
13118
13119 if (res)
13120 return res;
13121
13122 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13123 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13124
13125 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13126 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13127 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13128
13129 return res;
13130 }
13131
13132 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13133 {
13134 int cmd = 0;
13135 char destination[80] = "";
13136 int retries = 0;
13137
13138 if (!num) {
13139 ast_verb(3, "Destination number will be entered manually\n");
13140 while (retries < 3 && cmd != 't') {
13141 destination[1] = '\0';
13142 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13143 if (!cmd)
13144 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13145 if (!cmd)
13146 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13147 if (!cmd) {
13148 cmd = ast_waitfordigit(chan, 6000);
13149 if (cmd)
13150 destination[0] = cmd;
13151 }
13152 if (!cmd) {
13153 retries++;
13154 } else {
13155
13156 if (cmd < 0)
13157 return 0;
13158 if (cmd == '*') {
13159 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13160 return 0;
13161 }
13162 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13163 retries++;
13164 else
13165 cmd = 't';
13166 }
13167 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13168 }
13169 if (retries >= 3) {
13170 return 0;
13171 }
13172
13173 } else {
13174 if (option_verbose > 2)
13175 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13176 ast_copy_string(destination, num, sizeof(destination));
13177 }
13178
13179 if (!ast_strlen_zero(destination)) {
13180 if (destination[strlen(destination) -1 ] == '*')
13181 return 0;
13182 if (option_verbose > 2)
13183 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13184 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13185 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13186 chan->priority = 0;
13187 return 9;
13188 }
13189 return 0;
13190 }
13191
13192
13193
13194
13195
13196
13197
13198
13199
13200
13201
13202
13203
13204
13205 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)
13206 {
13207 int res = 0;
13208 char filename[PATH_MAX];
13209 struct ast_config *msg_cfg = NULL;
13210 const char *origtime, *context;
13211 char *name, *num;
13212 int retries = 0;
13213 char *cid;
13214 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13215
13216 vms->starting = 0;
13217
13218 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13219
13220
13221 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13222 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13223 msg_cfg = ast_config_load(filename, config_flags);
13224 DISPOSE(vms->curdir, vms->curmsg);
13225 if (!valid_config(msg_cfg)) {
13226 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13227 return 0;
13228 }
13229
13230 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13231 ast_config_destroy(msg_cfg);
13232 return 0;
13233 }
13234
13235 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13236
13237 context = ast_variable_retrieve(msg_cfg, "message", "context");
13238 if (!strncasecmp("macro", context, 5))
13239 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13240 switch (option) {
13241 case 3:
13242 if (!res)
13243 res = play_message_datetime(chan, vmu, origtime, filename);
13244 if (!res)
13245 res = play_message_callerid(chan, vms, cid, context, 0);
13246
13247 res = 't';
13248 break;
13249
13250 case 2:
13251
13252 if (ast_strlen_zero(cid))
13253 break;
13254
13255 ast_callerid_parse(cid, &name, &num);
13256 while ((res > -1) && (res != 't')) {
13257 switch (res) {
13258 case '1':
13259 if (num) {
13260
13261 res = dialout(chan, vmu, num, vmu->callback);
13262 if (res) {
13263 ast_config_destroy(msg_cfg);
13264 return 9;
13265 }
13266 } else {
13267 res = '2';
13268 }
13269 break;
13270
13271 case '2':
13272
13273 if (!ast_strlen_zero(vmu->dialout)) {
13274 res = dialout(chan, vmu, NULL, vmu->dialout);
13275 if (res) {
13276 ast_config_destroy(msg_cfg);
13277 return 9;
13278 }
13279 } else {
13280 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13281 res = ast_play_and_wait(chan, "vm-sorry");
13282 }
13283 ast_config_destroy(msg_cfg);
13284 return res;
13285 case '*':
13286 res = 't';
13287 break;
13288 case '3':
13289 case '4':
13290 case '5':
13291 case '6':
13292 case '7':
13293 case '8':
13294 case '9':
13295 case '0':
13296
13297 res = ast_play_and_wait(chan, "vm-sorry");
13298 retries++;
13299 break;
13300 default:
13301 if (num) {
13302 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13303 res = ast_play_and_wait(chan, "vm-num-i-have");
13304 if (!res)
13305 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13306 if (!res)
13307 res = ast_play_and_wait(chan, "vm-tocallnum");
13308
13309 if (!ast_strlen_zero(vmu->dialout)) {
13310 if (!res)
13311 res = ast_play_and_wait(chan, "vm-calldiffnum");
13312 }
13313 } else {
13314 res = ast_play_and_wait(chan, "vm-nonumber");
13315 if (!ast_strlen_zero(vmu->dialout)) {
13316 if (!res)
13317 res = ast_play_and_wait(chan, "vm-toenternumber");
13318 }
13319 }
13320 if (!res) {
13321 res = ast_play_and_wait(chan, "vm-star-cancel");
13322 }
13323 if (!res) {
13324 res = ast_waitfordigit(chan, 6000);
13325 }
13326 if (!res) {
13327 retries++;
13328 if (retries > 3) {
13329 res = 't';
13330 }
13331 }
13332 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13333 break;
13334
13335 }
13336 if (res == 't')
13337 res = 0;
13338 else if (res == '*')
13339 res = -1;
13340 }
13341 break;
13342
13343 case 1:
13344
13345 if (ast_strlen_zero(cid))
13346 break;
13347
13348 ast_callerid_parse(cid, &name, &num);
13349 if (!num) {
13350 ast_verb(3, "No CID number available, no reply sent\n");
13351 if (!res)
13352 res = ast_play_and_wait(chan, "vm-nonumber");
13353 ast_config_destroy(msg_cfg);
13354 return res;
13355 } else {
13356 struct ast_vm_user vmu2;
13357 if (find_user(&vmu2, vmu->context, num)) {
13358 struct leave_vm_options leave_options;
13359 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13360 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13361
13362 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13363
13364 memset(&leave_options, 0, sizeof(leave_options));
13365 leave_options.record_gain = record_gain;
13366 res = leave_voicemail(chan, mailbox, &leave_options);
13367 if (!res)
13368 res = 't';
13369 ast_config_destroy(msg_cfg);
13370 return res;
13371 } else {
13372
13373 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13374 ast_play_and_wait(chan, "vm-nobox");
13375 res = 't';
13376 ast_config_destroy(msg_cfg);
13377 return res;
13378 }
13379 }
13380 res = 0;
13381
13382 break;
13383 }
13384
13385 ast_config_destroy(msg_cfg);
13386
13387 #ifndef IMAP_STORAGE
13388 if (!res) {
13389 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13390 vms->heard[msg] = 1;
13391 res = wait_file(chan, vms, vms->fn);
13392 }
13393 #endif
13394 return res;
13395 }
13396
13397 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13398 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13399 signed char record_gain, struct vm_state *vms, char *flag)
13400 {
13401
13402 int res = 0;
13403 int cmd = 0;
13404 int max_attempts = 3;
13405 int attempts = 0;
13406 int recorded = 0;
13407 int msg_exists = 0;
13408 signed char zero_gain = 0;
13409 char tempfile[PATH_MAX];
13410 char *acceptdtmf = "#";
13411 char *canceldtmf = "";
13412 int canceleddtmf = 0;
13413
13414
13415
13416
13417 if (duration == NULL) {
13418 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13419 return -1;
13420 }
13421
13422 if (!outsidecaller)
13423 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13424 else
13425 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13426
13427 cmd = '3';
13428
13429 while ((cmd >= 0) && (cmd != 't')) {
13430 switch (cmd) {
13431 case '1':
13432 if (!msg_exists) {
13433
13434 cmd = '3';
13435 break;
13436 } else {
13437
13438 ast_verb(3, "Saving message as is\n");
13439 if (!outsidecaller)
13440 ast_filerename(tempfile, recordfile, NULL);
13441 ast_stream_and_wait(chan, "vm-msgsaved", "");
13442 if (!outsidecaller) {
13443
13444 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13445 DISPOSE(recordfile, -1);
13446 }
13447 cmd = 't';
13448 return res;
13449 }
13450 case '2':
13451
13452 ast_verb(3, "Reviewing the message\n");
13453 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13454 break;
13455 case '3':
13456 msg_exists = 0;
13457
13458 if (recorded == 1)
13459 ast_verb(3, "Re-recording the message\n");
13460 else
13461 ast_verb(3, "Recording the message\n");
13462
13463 if (recorded && outsidecaller) {
13464 cmd = ast_play_and_wait(chan, INTRO);
13465 cmd = ast_play_and_wait(chan, "beep");
13466 }
13467 recorded = 1;
13468
13469 if (record_gain)
13470 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13471 if (ast_test_flag(vmu, VM_OPERATOR))
13472 canceldtmf = "0";
13473 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13474 if (strchr(canceldtmf, cmd)) {
13475
13476 canceleddtmf = 1;
13477 }
13478 if (record_gain)
13479 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13480 if (cmd == -1) {
13481
13482 if (!outsidecaller) {
13483
13484 ast_filedelete(tempfile, NULL);
13485 }
13486 return cmd;
13487 }
13488 if (cmd == '0') {
13489 break;
13490 } else if (cmd == '*') {
13491 break;
13492 #if 0
13493 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13494
13495 ast_verb(3, "Message too short\n");
13496 cmd = ast_play_and_wait(chan, "vm-tooshort");
13497 cmd = ast_filedelete(tempfile, NULL);
13498 break;
13499 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13500
13501 ast_verb(3, "Nothing recorded\n");
13502 cmd = ast_filedelete(tempfile, NULL);
13503 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13504 if (!cmd)
13505 cmd = ast_play_and_wait(chan, "vm-speakup");
13506 break;
13507 #endif
13508 } else {
13509
13510 msg_exists = 1;
13511 cmd = 0;
13512 }
13513 break;
13514 case '4':
13515 if (outsidecaller) {
13516
13517 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13518 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13519 res = ast_play_and_wait(chan, "vm-marked-urgent");
13520 strcpy(flag, "Urgent");
13521 } else if (flag) {
13522 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13523 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13524 strcpy(flag, "");
13525 } else {
13526 ast_play_and_wait(chan, "vm-sorry");
13527 }
13528 cmd = 0;
13529 } else {
13530 cmd = ast_play_and_wait(chan, "vm-sorry");
13531 }
13532 break;
13533 case '5':
13534 case '6':
13535 case '7':
13536 case '8':
13537 case '9':
13538 case '*':
13539 case '#':
13540 cmd = ast_play_and_wait(chan, "vm-sorry");
13541 break;
13542 #if 0
13543
13544
13545 case '*':
13546
13547 cmd = ast_play_and_wait(chan, "vm-deleted");
13548 cmd = ast_filedelete(tempfile, NULL);
13549 if (outsidecaller) {
13550 res = vm_exec(chan, NULL);
13551 return res;
13552 }
13553 else
13554 return 1;
13555 #endif
13556 case '0':
13557 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13558 cmd = ast_play_and_wait(chan, "vm-sorry");
13559 break;
13560 }
13561 if (msg_exists || recorded) {
13562 cmd = ast_play_and_wait(chan, "vm-saveoper");
13563 if (!cmd)
13564 cmd = ast_waitfordigit(chan, 3000);
13565 if (cmd == '1') {
13566 ast_filerename(tempfile, recordfile, NULL);
13567 ast_play_and_wait(chan, "vm-msgsaved");
13568 cmd = '0';
13569 } else if (cmd == '4') {
13570 if (flag) {
13571 ast_play_and_wait(chan, "vm-marked-urgent");
13572 strcpy(flag, "Urgent");
13573 }
13574 ast_play_and_wait(chan, "vm-msgsaved");
13575 cmd = '0';
13576 } else {
13577 ast_play_and_wait(chan, "vm-deleted");
13578 DELETE(tempfile, -1, tempfile, vmu);
13579 cmd = '0';
13580 }
13581 }
13582 return cmd;
13583 default:
13584
13585
13586
13587 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13588 return cmd;
13589 if (msg_exists) {
13590 cmd = ast_play_and_wait(chan, "vm-review");
13591 if (!cmd && outsidecaller) {
13592 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13593 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13594 } else if (flag) {
13595 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13596 }
13597 }
13598 } else {
13599 cmd = ast_play_and_wait(chan, "vm-torerecord");
13600 if (!cmd)
13601 cmd = ast_waitfordigit(chan, 600);
13602 }
13603
13604 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13605 cmd = ast_play_and_wait(chan, "vm-reachoper");
13606 if (!cmd)
13607 cmd = ast_waitfordigit(chan, 600);
13608 }
13609 #if 0
13610 if (!cmd)
13611 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13612 #endif
13613 if (!cmd)
13614 cmd = ast_waitfordigit(chan, 6000);
13615 if (!cmd) {
13616 attempts++;
13617 }
13618 if (attempts > max_attempts) {
13619 cmd = 't';
13620 }
13621 }
13622 }
13623 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13624
13625 ast_filedelete(tempfile, NULL);
13626 }
13627
13628 if (cmd != 't' && outsidecaller)
13629 ast_play_and_wait(chan, "vm-goodbye");
13630
13631 return cmd;
13632 }
13633
13634
13635
13636
13637
13638 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13639 .load = load_module,
13640 .unload = unload_module,
13641 .reload = reload,
13642 .nonoptreq = "res_adsi,res_smdi",
13643 );