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: 352643 $")
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 mailcmd[160];
00644 char language[MAX_LANGUAGE];
00645 char zonetag[80];
00646 char locale[20];
00647 char callback[80];
00648 char dialout[80];
00649 char uniqueid[80];
00650 char exit[80];
00651 char attachfmt[20];
00652 unsigned int flags;
00653 int saydurationm;
00654 int minsecs;
00655 int maxmsg;
00656 int maxdeletedmsg;
00657 int maxsecs;
00658 int passwordlocation;
00659 #ifdef IMAP_STORAGE
00660 char imapuser[80];
00661 char imappassword[80];
00662 char imapfolder[64];
00663 char imapvmshareid[80];
00664 int imapversion;
00665 #endif
00666 double volgain;
00667 AST_LIST_ENTRY(ast_vm_user) list;
00668 };
00669
00670
00671 struct vm_zone {
00672 AST_LIST_ENTRY(vm_zone) list;
00673 char name[80];
00674 char timezone[80];
00675 char msg_format[512];
00676 };
00677
00678 #define VMSTATE_MAX_MSG_ARRAY 256
00679
00680
00681 struct vm_state {
00682 char curbox[80];
00683 char username[80];
00684 char context[80];
00685 char curdir[PATH_MAX];
00686 char vmbox[PATH_MAX];
00687 char fn[PATH_MAX];
00688 char intro[PATH_MAX];
00689 int *deleted;
00690 int *heard;
00691 int dh_arraysize;
00692 int curmsg;
00693 int lastmsg;
00694 int newmessages;
00695 int oldmessages;
00696 int urgentmessages;
00697 int starting;
00698 int repeats;
00699 #ifdef IMAP_STORAGE
00700 ast_mutex_t lock;
00701 int updated;
00702 long msgArray[VMSTATE_MAX_MSG_ARRAY];
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 = 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 ast_set_flag(retval, VM_ALLOCED);
01404 else
01405 memset(retval, 0, sizeof(*retval));
01406 if (mailbox)
01407 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01408 populate_defaults(retval);
01409 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01410 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01411 else
01412 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01413 if (var) {
01414 apply_options_full(retval, var);
01415 ast_variables_destroy(var);
01416 } else {
01417 if (!ivm)
01418 free_user(retval);
01419 retval = NULL;
01420 }
01421 }
01422 return retval;
01423 }
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01434 {
01435
01436 struct ast_vm_user *vmu = NULL, *cur;
01437 AST_LIST_LOCK(&users);
01438
01439 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01440 context = "default";
01441
01442 AST_LIST_TRAVERSE(&users, cur, list) {
01443 #ifdef IMAP_STORAGE
01444 if (cur->imapversion != imapversion) {
01445 continue;
01446 }
01447 #endif
01448 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01449 break;
01450 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01451 break;
01452 }
01453 if (cur) {
01454
01455 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01456 *vmu = *cur;
01457 if (!ivm) {
01458 vmu->emailbody = ast_strdup(cur->emailbody);
01459 vmu->emailsubject = ast_strdup(cur->emailsubject);
01460 }
01461 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01462 AST_LIST_NEXT(vmu, list) = NULL;
01463 }
01464 } else
01465 vmu = find_user_realtime(ivm, context, mailbox);
01466 AST_LIST_UNLOCK(&users);
01467 return vmu;
01468 }
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01481 {
01482
01483 struct ast_vm_user *cur;
01484 int res = -1;
01485 AST_LIST_LOCK(&users);
01486 AST_LIST_TRAVERSE(&users, cur, list) {
01487 if ((!context || !strcasecmp(context, cur->context)) &&
01488 (!strcasecmp(mailbox, cur->mailbox)))
01489 break;
01490 }
01491 if (cur) {
01492 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01493 res = 0;
01494 }
01495 AST_LIST_UNLOCK(&users);
01496 return res;
01497 }
01498
01499
01500
01501
01502
01503
01504
01505
01506 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01507 {
01508 struct ast_config *cfg = NULL;
01509 struct ast_variable *var = NULL;
01510 struct ast_category *cat = NULL;
01511 char *category = NULL, *value = NULL, *new = NULL;
01512 const char *tmp = NULL;
01513 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01514 char secretfn[PATH_MAX] = "";
01515 int found = 0;
01516
01517 if (!change_password_realtime(vmu, newpassword))
01518 return;
01519
01520
01521 switch (vmu->passwordlocation) {
01522 case OPT_PWLOC_SPOOLDIR:
01523 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01524 if (write_password_to_file(secretfn, newpassword) == 0) {
01525 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01526 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01527 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01528 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01529 break;
01530 } else {
01531 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01532 }
01533
01534 case OPT_PWLOC_VOICEMAILCONF:
01535 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01536 while ((category = ast_category_browse(cfg, category))) {
01537 if (!strcasecmp(category, vmu->context)) {
01538 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01539 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01540 break;
01541 }
01542 value = strstr(tmp, ",");
01543 if (!value) {
01544 new = alloca(strlen(newpassword)+1);
01545 sprintf(new, "%s", newpassword);
01546 } else {
01547 new = alloca((strlen(value) + strlen(newpassword) + 1));
01548 sprintf(new, "%s%s", newpassword, value);
01549 }
01550 if (!(cat = ast_category_get(cfg, category))) {
01551 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01552 break;
01553 }
01554 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01555 found = 1;
01556 }
01557 }
01558
01559 if (found) {
01560 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01561 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01562 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01563 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01564 break;
01565 }
01566 }
01567
01568 case OPT_PWLOC_USERSCONF:
01569
01570
01571 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01572 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01573 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01574 ast_debug(4, "users.conf: %s\n", category);
01575 if (!strcasecmp(category, vmu->mailbox)) {
01576 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01577 ast_debug(3, "looks like we need to make vmsecret!\n");
01578 var = ast_variable_new("vmsecret", newpassword, "");
01579 } else {
01580 var = NULL;
01581 }
01582 new = alloca(strlen(newpassword) + 1);
01583 sprintf(new, "%s", newpassword);
01584 if (!(cat = ast_category_get(cfg, category))) {
01585 ast_debug(4, "failed to get category!\n");
01586 ast_free(var);
01587 break;
01588 }
01589 if (!var) {
01590 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01591 } else {
01592 ast_variable_append(cat, var);
01593 }
01594 found = 1;
01595 break;
01596 }
01597 }
01598
01599 if (found) {
01600 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01601 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01602 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01603 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01604 }
01605 }
01606 }
01607 }
01608
01609 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01610 {
01611 char buf[255];
01612 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01613 ast_debug(1, "External password: %s\n",buf);
01614 if (!ast_safe_system(buf)) {
01615 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01616 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01617
01618 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01619 }
01620 }
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01636 {
01637 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01638 }
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652 static int make_file(char *dest, const int len, const char *dir, const int num)
01653 {
01654 return snprintf(dest, len, "%s/msg%04d", dir, num);
01655 }
01656
01657
01658 static FILE *vm_mkftemp(char *template)
01659 {
01660 FILE *p = NULL;
01661 int pfd = mkstemp(template);
01662 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01663 if (pfd > -1) {
01664 p = fdopen(pfd, "w+");
01665 if (!p) {
01666 close(pfd);
01667 pfd = -1;
01668 }
01669 }
01670 return p;
01671 }
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01682 {
01683 mode_t mode = VOICEMAIL_DIR_MODE;
01684 int res;
01685
01686 make_dir(dest, len, context, ext, folder);
01687 if ((res = ast_mkdir(dest, mode))) {
01688 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01689 return -1;
01690 }
01691 return 0;
01692 }
01693
01694 static const char * const mailbox_folders[] = {
01695 #ifdef IMAP_STORAGE
01696 imapfolder,
01697 #else
01698 "INBOX",
01699 #endif
01700 "Old",
01701 "Work",
01702 "Family",
01703 "Friends",
01704 "Cust1",
01705 "Cust2",
01706 "Cust3",
01707 "Cust4",
01708 "Cust5",
01709 "Deleted",
01710 "Urgent",
01711 };
01712
01713 static const char *mbox(struct ast_vm_user *vmu, int id)
01714 {
01715 #ifdef IMAP_STORAGE
01716 if (vmu && id == 0) {
01717 return vmu->imapfolder;
01718 }
01719 #endif
01720 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01721 }
01722
01723 static int get_folder_by_name(const char *name)
01724 {
01725 size_t i;
01726
01727 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01728 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01729 return i;
01730 }
01731 }
01732
01733 return -1;
01734 }
01735
01736 static void free_user(struct ast_vm_user *vmu)
01737 {
01738 if (ast_test_flag(vmu, VM_ALLOCED)) {
01739
01740 ast_free(vmu->emailbody);
01741 vmu->emailbody = NULL;
01742
01743 ast_free(vmu->emailsubject);
01744 vmu->emailsubject = NULL;
01745
01746 ast_free(vmu);
01747 }
01748 }
01749
01750 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01751
01752 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01753 if (!vms->dh_arraysize) {
01754
01755 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01756 return -1;
01757 }
01758 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01759 return -1;
01760 }
01761 vms->dh_arraysize = arraysize;
01762 } else if (vms->dh_arraysize < arraysize) {
01763 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01764 return -1;
01765 }
01766 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01767 return -1;
01768 }
01769 memset(vms->deleted, 0, arraysize * sizeof(int));
01770 memset(vms->heard, 0, arraysize * sizeof(int));
01771 vms->dh_arraysize = arraysize;
01772 }
01773
01774 return 0;
01775 }
01776
01777
01778
01779 #ifdef IMAP_STORAGE
01780 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01781 {
01782 char arg[10];
01783 struct vm_state *vms;
01784 unsigned long messageNum;
01785
01786
01787 if (msgnum < 0 && !imapgreetings) {
01788 ast_filedelete(file, NULL);
01789 return;
01790 }
01791
01792 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01793 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);
01794 return;
01795 }
01796
01797
01798
01799 messageNum = vms->msgArray[msgnum];
01800 if (messageNum == 0) {
01801 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01802 return;
01803 }
01804 if (option_debug > 2)
01805 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01806
01807 snprintf (arg, sizeof(arg), "%lu", messageNum);
01808 ast_mutex_lock(&vms->lock);
01809 mail_setflag (vms->mailstream, arg, "\\DELETED");
01810 mail_expunge(vms->mailstream);
01811 ast_mutex_unlock(&vms->lock);
01812 }
01813
01814 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01815 {
01816 struct vm_state *vms_p;
01817 char *file, *filename;
01818 char *attachment;
01819 int i;
01820 BODY *body;
01821
01822
01823
01824
01825 if (msgnum > -1 || !imapgreetings) {
01826 return 0;
01827 } else {
01828 file = strrchr(ast_strdupa(dir), '/');
01829 if (file)
01830 *file++ = '\0';
01831 else {
01832 ast_debug (1, "Failed to procure file name from directory passed.\n");
01833 return -1;
01834 }
01835 }
01836
01837
01838 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01839 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01840
01841
01842
01843
01844 if (!(vms_p = create_vm_state_from_user(vmu))) {
01845 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01846 return -1;
01847 }
01848 }
01849
01850
01851 *vms_p->introfn = '\0';
01852
01853 ast_mutex_lock(&vms_p->lock);
01854 init_mailstream(vms_p, GREETINGS_FOLDER);
01855 if (!vms_p->mailstream) {
01856 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01857 ast_mutex_unlock(&vms_p->lock);
01858 return -1;
01859 }
01860
01861
01862 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01863 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01864
01865 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01866 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01867 } else {
01868 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01869 ast_mutex_unlock(&vms_p->lock);
01870 return -1;
01871 }
01872 filename = strsep(&attachment, ".");
01873 if (!strcmp(filename, file)) {
01874 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01875 vms_p->msgArray[vms_p->curmsg] = i + 1;
01876 save_body(body, vms_p, "2", attachment, 0);
01877 ast_mutex_unlock(&vms_p->lock);
01878 return 0;
01879 }
01880 }
01881 ast_mutex_unlock(&vms_p->lock);
01882
01883 return -1;
01884 }
01885
01886 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01887 {
01888 BODY *body;
01889 char *header_content;
01890 char *attachedfilefmt;
01891 char buf[80];
01892 struct vm_state *vms;
01893 char text_file[PATH_MAX];
01894 FILE *text_file_ptr;
01895 int res = 0;
01896 struct ast_vm_user *vmu;
01897
01898 if (!(vmu = find_user(NULL, context, mailbox))) {
01899 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01900 return -1;
01901 }
01902
01903 if (msgnum < 0) {
01904 if (imapgreetings) {
01905 res = imap_retrieve_greeting(dir, msgnum, vmu);
01906 goto exit;
01907 } else {
01908 res = 0;
01909 goto exit;
01910 }
01911 }
01912
01913
01914
01915
01916 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01917
01918
01919
01920
01921
01922
01923
01924 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01925 res = -1;
01926 goto exit;
01927 }
01928
01929 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01930 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01931
01932
01933 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01934 res = 0;
01935 goto exit;
01936 }
01937
01938 if (option_debug > 2)
01939 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01940 if (vms->msgArray[msgnum] == 0) {
01941 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01942 res = -1;
01943 goto exit;
01944 }
01945
01946
01947 ast_mutex_lock(&vms->lock);
01948 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01949 ast_mutex_unlock(&vms->lock);
01950
01951 if (ast_strlen_zero(header_content)) {
01952 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01953 res = -1;
01954 goto exit;
01955 }
01956
01957 ast_mutex_lock(&vms->lock);
01958 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01959 ast_mutex_unlock(&vms->lock);
01960
01961
01962 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01963 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01964 } else {
01965 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01966 res = -1;
01967 goto exit;
01968 }
01969
01970
01971
01972 strsep(&attachedfilefmt, ".");
01973 if (!attachedfilefmt) {
01974 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01975 res = -1;
01976 goto exit;
01977 }
01978
01979 save_body(body, vms, "2", attachedfilefmt, 0);
01980 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01981 *vms->introfn = '\0';
01982 }
01983
01984
01985 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01986
01987 if (!(text_file_ptr = fopen(text_file, "w"))) {
01988 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01989 }
01990
01991 fprintf(text_file_ptr, "%s\n", "[message]");
01992
01993 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01994 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01995 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01996 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01997 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01998 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01999 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02000 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02001 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02002 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02003 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02004 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02005 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02006 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02007 fclose(text_file_ptr);
02008
02009 exit:
02010 free_user(vmu);
02011 return res;
02012 }
02013
02014 static int folder_int(const char *folder)
02015 {
02016
02017 if (!folder) {
02018 return 0;
02019 }
02020 if (!strcasecmp(folder, imapfolder)) {
02021 return 0;
02022 } else if (!strcasecmp(folder, "Old")) {
02023 return 1;
02024 } else if (!strcasecmp(folder, "Work")) {
02025 return 2;
02026 } else if (!strcasecmp(folder, "Family")) {
02027 return 3;
02028 } else if (!strcasecmp(folder, "Friends")) {
02029 return 4;
02030 } else if (!strcasecmp(folder, "Cust1")) {
02031 return 5;
02032 } else if (!strcasecmp(folder, "Cust2")) {
02033 return 6;
02034 } else if (!strcasecmp(folder, "Cust3")) {
02035 return 7;
02036 } else if (!strcasecmp(folder, "Cust4")) {
02037 return 8;
02038 } else if (!strcasecmp(folder, "Cust5")) {
02039 return 9;
02040 } else if (!strcasecmp(folder, "Urgent")) {
02041 return 11;
02042 } else {
02043 return 0;
02044 }
02045 }
02046
02047 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02048 {
02049 SEARCHPGM *pgm;
02050 SEARCHHEADER *hdr;
02051
02052 struct ast_vm_user *vmu, vmus;
02053 struct vm_state *vms_p;
02054 int ret = 0;
02055 int fold = folder_int(folder);
02056 int urgent = 0;
02057
02058
02059 if (fold == 11) {
02060 fold = NEW_FOLDER;
02061 urgent = 1;
02062 }
02063
02064 if (ast_strlen_zero(mailbox))
02065 return 0;
02066
02067
02068 vmu = find_user(&vmus, context, mailbox);
02069 if (!vmu) {
02070 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02071 return -1;
02072 } else {
02073
02074 if (vmu->imapuser[0] == '\0') {
02075 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02076 return -1;
02077 }
02078 }
02079
02080
02081 if (vmu->imapuser[0] == '\0') {
02082 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02083 free_user(vmu);
02084 return -1;
02085 }
02086
02087
02088 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02089 if (!vms_p) {
02090 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02091 }
02092 if (vms_p) {
02093 ast_debug(3, "Returning before search - user is logged in\n");
02094 if (fold == 0) {
02095 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02096 }
02097 if (fold == 1) {
02098 return vms_p->oldmessages;
02099 }
02100 }
02101
02102
02103 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02104 if (!vms_p) {
02105 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02106 }
02107
02108 if (!vms_p) {
02109 vms_p = create_vm_state_from_user(vmu);
02110 }
02111 ret = init_mailstream(vms_p, fold);
02112 if (!vms_p->mailstream) {
02113 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02114 return -1;
02115 }
02116 if (ret == 0) {
02117 ast_mutex_lock(&vms_p->lock);
02118 pgm = mail_newsearchpgm ();
02119 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02120 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02121 pgm->header = hdr;
02122 if (fold != OLD_FOLDER) {
02123 pgm->unseen = 1;
02124 pgm->seen = 0;
02125 }
02126
02127
02128
02129 else {
02130 pgm->unseen = 0;
02131 pgm->seen = 1;
02132 }
02133
02134 if (fold == NEW_FOLDER) {
02135 if (urgent) {
02136 pgm->flagged = 1;
02137 pgm->unflagged = 0;
02138 } else {
02139 pgm->flagged = 0;
02140 pgm->unflagged = 1;
02141 }
02142 }
02143 pgm->undeleted = 1;
02144 pgm->deleted = 0;
02145
02146 vms_p->vmArrayIndex = 0;
02147 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02148 if (fold == 0 && urgent == 0)
02149 vms_p->newmessages = vms_p->vmArrayIndex;
02150 if (fold == 1)
02151 vms_p->oldmessages = vms_p->vmArrayIndex;
02152 if (fold == 0 && urgent == 1)
02153 vms_p->urgentmessages = vms_p->vmArrayIndex;
02154
02155 mail_free_searchpgm(&pgm);
02156 ast_mutex_unlock(&vms_p->lock);
02157 vms_p->updated = 0;
02158 return vms_p->vmArrayIndex;
02159 } else {
02160 ast_mutex_lock(&vms_p->lock);
02161 mail_ping(vms_p->mailstream);
02162 ast_mutex_unlock(&vms_p->lock);
02163 }
02164 return 0;
02165 }
02166
02167 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02168 {
02169
02170 check_quota(vms, vmu->imapfolder);
02171 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02172 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02173 ast_play_and_wait(chan, "vm-mailboxfull");
02174 return -1;
02175 }
02176
02177
02178 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));
02179 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02180 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02181 ast_play_and_wait(chan, "vm-mailboxfull");
02182 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02183 return -1;
02184 }
02185
02186 return 0;
02187 }
02188
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198 static int messagecount(const char *context, const char *mailbox, const char *folder)
02199 {
02200 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02201 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02202 } else {
02203 return __messagecount(context, mailbox, folder);
02204 }
02205 }
02206
02207 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)
02208 {
02209 char *myserveremail = serveremail;
02210 char fn[PATH_MAX];
02211 char introfn[PATH_MAX];
02212 char mailbox[256];
02213 char *stringp;
02214 FILE *p = NULL;
02215 char tmp[80] = "/tmp/astmail-XXXXXX";
02216 long len;
02217 void *buf;
02218 int tempcopy = 0;
02219 STRING str;
02220 int ret;
02221 char *imap_flags = NIL;
02222 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02223 int box = NEW_FOLDER;
02224
02225
02226 if (msgnum < 0) {
02227 if(!imapgreetings) {
02228 return 0;
02229 } else {
02230 box = GREETINGS_FOLDER;
02231 }
02232 }
02233
02234 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02235 return -1;
02236 }
02237
02238
02239 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02240 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02241 imap_flags = "\\FLAGGED";
02242 }
02243
02244
02245 fmt = ast_strdupa(fmt);
02246 stringp = fmt;
02247 strsep(&stringp, "|");
02248
02249 if (!ast_strlen_zero(vmu->serveremail))
02250 myserveremail = vmu->serveremail;
02251
02252 if (msgnum > -1)
02253 make_file(fn, sizeof(fn), dir, msgnum);
02254 else
02255 ast_copy_string (fn, dir, sizeof(fn));
02256
02257 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02258 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02259 *introfn = '\0';
02260 }
02261
02262 if (ast_strlen_zero(vmu->email)) {
02263
02264
02265
02266
02267
02268 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02269 tempcopy = 1;
02270 }
02271
02272 if (!strcmp(fmt, "wav49"))
02273 fmt = "WAV";
02274 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02275
02276
02277
02278 if (!(p = vm_mkftemp(tmp))) {
02279 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02280 if (tempcopy)
02281 *(vmu->email) = '\0';
02282 return -1;
02283 }
02284
02285 if (msgnum < 0 && imapgreetings) {
02286 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02287 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02288 return -1;
02289 }
02290 imap_delete_old_greeting(fn, vms);
02291 }
02292
02293 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02294 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02295 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02296 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02297
02298 len = ftell(p);
02299 rewind(p);
02300 if (!(buf = ast_malloc(len + 1))) {
02301 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02302 fclose(p);
02303 if (tempcopy)
02304 *(vmu->email) = '\0';
02305 return -1;
02306 }
02307 if (fread(buf, len, 1, p) < len) {
02308 if (ferror(p)) {
02309 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02310 return -1;
02311 }
02312 }
02313 ((char *) buf)[len] = '\0';
02314 INIT(&str, mail_string, buf, len);
02315 ret = init_mailstream(vms, box);
02316 if (ret == 0) {
02317 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02318 ast_mutex_lock(&vms->lock);
02319 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02320 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02321 ast_mutex_unlock(&vms->lock);
02322 fclose(p);
02323 unlink(tmp);
02324 ast_free(buf);
02325 } else {
02326 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02327 fclose(p);
02328 unlink(tmp);
02329 ast_free(buf);
02330 return -1;
02331 }
02332 ast_debug(3, "%s stored\n", fn);
02333
02334 if (tempcopy)
02335 *(vmu->email) = '\0';
02336 inprocess_count(vmu->mailbox, vmu->context, -1);
02337 return 0;
02338
02339 }
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352
02353
02354 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02355 {
02356 char tmp[PATH_MAX] = "";
02357 char *mailboxnc;
02358 char *context;
02359 char *mb;
02360 char *cur;
02361 if (newmsgs)
02362 *newmsgs = 0;
02363 if (oldmsgs)
02364 *oldmsgs = 0;
02365 if (urgentmsgs)
02366 *urgentmsgs = 0;
02367
02368 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02369
02370 if (ast_strlen_zero(mailbox_context))
02371 return 0;
02372
02373 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02374 context = strchr(tmp, '@');
02375 if (strchr(mailbox_context, ',')) {
02376 int tmpnew, tmpold, tmpurgent;
02377 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02378 mb = tmp;
02379 while ((cur = strsep(&mb, ", "))) {
02380 if (!ast_strlen_zero(cur)) {
02381 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02382 return -1;
02383 else {
02384 if (newmsgs)
02385 *newmsgs += tmpnew;
02386 if (oldmsgs)
02387 *oldmsgs += tmpold;
02388 if (urgentmsgs)
02389 *urgentmsgs += tmpurgent;
02390 }
02391 }
02392 }
02393 return 0;
02394 }
02395 if (context) {
02396 *context = '\0';
02397 mailboxnc = tmp;
02398 context++;
02399 } else {
02400 context = "default";
02401 mailboxnc = (char *) mailbox_context;
02402 }
02403
02404 if (newmsgs) {
02405 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02406 if (!vmu) {
02407 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02408 return -1;
02409 }
02410 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02411 return -1;
02412 }
02413 }
02414 if (oldmsgs) {
02415 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02416 return -1;
02417 }
02418 }
02419 if (urgentmsgs) {
02420 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02421 return -1;
02422 }
02423 }
02424 return 0;
02425 }
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437 static int has_voicemail(const char *mailbox, const char *folder)
02438 {
02439 char tmp[256], *tmp2, *box, *context;
02440 ast_copy_string(tmp, mailbox, sizeof(tmp));
02441 tmp2 = tmp;
02442 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02443 while ((box = strsep(&tmp2, ",&"))) {
02444 if (!ast_strlen_zero(box)) {
02445 if (has_voicemail(box, folder)) {
02446 return 1;
02447 }
02448 }
02449 }
02450 }
02451 if ((context = strchr(tmp, '@'))) {
02452 *context++ = '\0';
02453 } else {
02454 context = "default";
02455 }
02456 return __messagecount(context, tmp, folder) ? 1 : 0;
02457 }
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474 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)
02475 {
02476 struct vm_state *sendvms = NULL, *destvms = NULL;
02477 char messagestring[10];
02478 if (msgnum >= recip->maxmsg) {
02479 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02480 return -1;
02481 }
02482 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02483 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02484 return -1;
02485 }
02486 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02487 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02488 return -1;
02489 }
02490 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02491 ast_mutex_lock(&sendvms->lock);
02492 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02493 ast_mutex_unlock(&sendvms->lock);
02494 return 0;
02495 }
02496 ast_mutex_unlock(&sendvms->lock);
02497 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02498 return -1;
02499 }
02500
02501 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02502 {
02503 char tmp[256], *t = tmp;
02504 size_t left = sizeof(tmp);
02505
02506 if (box == OLD_FOLDER) {
02507 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02508 } else {
02509 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02510 }
02511
02512 if (box == NEW_FOLDER) {
02513 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02514 } else {
02515 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02516 }
02517
02518
02519 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02520
02521
02522 if (!ast_strlen_zero(authuser))
02523 ast_build_string(&t, &left, "/authuser=%s", authuser);
02524
02525
02526 if (!ast_strlen_zero(imapflags))
02527 ast_build_string(&t, &left, "/%s", imapflags);
02528
02529
02530 #if 1
02531 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02532 #else
02533 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02534 #endif
02535 if (box == NEW_FOLDER || box == OLD_FOLDER)
02536 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02537 else if (box == GREETINGS_FOLDER)
02538 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02539 else {
02540 if (!ast_strlen_zero(imapparentfolder)) {
02541
02542 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02543 } else {
02544 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02545 }
02546 }
02547 }
02548
02549 static int init_mailstream(struct vm_state *vms, int box)
02550 {
02551 MAILSTREAM *stream = NIL;
02552 long debug;
02553 char tmp[256];
02554
02555 if (!vms) {
02556 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02557 return -1;
02558 }
02559 if (option_debug > 2)
02560 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02561 if (vms->mailstream == NIL || !vms->mailstream) {
02562 if (option_debug)
02563 ast_log(LOG_DEBUG, "mailstream not set.\n");
02564 } else {
02565 stream = vms->mailstream;
02566 }
02567
02568 debug = NIL;
02569
02570 if (delimiter == '\0') {
02571 char *cp;
02572 #ifdef USE_SYSTEM_IMAP
02573 #include <imap/linkage.c>
02574 #elif defined(USE_SYSTEM_CCLIENT)
02575 #include <c-client/linkage.c>
02576 #else
02577 #include "linkage.c"
02578 #endif
02579
02580 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02581 ast_mutex_lock(&vms->lock);
02582 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02583 ast_mutex_unlock(&vms->lock);
02584 if (stream == NIL) {
02585 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02586 return -1;
02587 }
02588 get_mailbox_delimiter(stream);
02589
02590 for (cp = vms->imapfolder; *cp; cp++)
02591 if (*cp == '/')
02592 *cp = delimiter;
02593 }
02594
02595 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02596 if (option_debug > 2)
02597 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02598 ast_mutex_lock(&vms->lock);
02599 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02600 ast_mutex_unlock(&vms->lock);
02601 if (vms->mailstream == NIL) {
02602 return -1;
02603 } else {
02604 return 0;
02605 }
02606 }
02607
02608 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02609 {
02610 SEARCHPGM *pgm;
02611 SEARCHHEADER *hdr;
02612 int ret, urgent = 0;
02613
02614
02615 if (box == 11) {
02616 box = NEW_FOLDER;
02617 urgent = 1;
02618 }
02619
02620 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02621 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02622 vms->imapversion = vmu->imapversion;
02623 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02624
02625 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02626 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02627 return -1;
02628 }
02629
02630 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02631
02632
02633 if (box == 0) {
02634 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02635 check_quota(vms, (char *) mbox(vmu, box));
02636 }
02637
02638 ast_mutex_lock(&vms->lock);
02639 pgm = mail_newsearchpgm();
02640
02641
02642 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02643 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02644 pgm->header = hdr;
02645 pgm->deleted = 0;
02646 pgm->undeleted = 1;
02647
02648
02649 if (box == NEW_FOLDER && urgent == 1) {
02650 pgm->unseen = 1;
02651 pgm->seen = 0;
02652 pgm->flagged = 1;
02653 pgm->unflagged = 0;
02654 } else if (box == NEW_FOLDER && urgent == 0) {
02655 pgm->unseen = 1;
02656 pgm->seen = 0;
02657 pgm->flagged = 0;
02658 pgm->unflagged = 1;
02659 } else if (box == OLD_FOLDER) {
02660 pgm->seen = 1;
02661 pgm->unseen = 0;
02662 }
02663
02664 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02665
02666 vms->vmArrayIndex = 0;
02667 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02668 vms->lastmsg = vms->vmArrayIndex - 1;
02669 mail_free_searchpgm(&pgm);
02670
02671
02672
02673
02674 if (box == 0 && !vms->dh_arraysize) {
02675 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02676 }
02677 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02678 ast_mutex_unlock(&vms->lock);
02679 return -1;
02680 }
02681
02682 ast_mutex_unlock(&vms->lock);
02683 return 0;
02684 }
02685
02686 static void write_file(char *filename, char *buffer, unsigned long len)
02687 {
02688 FILE *output;
02689
02690 output = fopen (filename, "w");
02691 if (fwrite(buffer, len, 1, output) != 1) {
02692 if (ferror(output)) {
02693 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02694 }
02695 }
02696 fclose (output);
02697 }
02698
02699 static void update_messages_by_imapuser(const char *user, unsigned long number)
02700 {
02701 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02702
02703 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02704 return;
02705 }
02706
02707 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02708 vms->msgArray[vms->vmArrayIndex++] = number;
02709 }
02710
02711 void mm_searched(MAILSTREAM *stream, unsigned long number)
02712 {
02713 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02714
02715 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02716 return;
02717
02718 update_messages_by_imapuser(user, number);
02719 }
02720
02721 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02722 {
02723 struct ast_variable *var;
02724 struct ast_vm_user *vmu;
02725
02726 vmu = ast_calloc(1, sizeof *vmu);
02727 if (!vmu)
02728 return NULL;
02729 ast_set_flag(vmu, VM_ALLOCED);
02730 populate_defaults(vmu);
02731
02732 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02733 if (var) {
02734 apply_options_full(vmu, var);
02735 ast_variables_destroy(var);
02736 return vmu;
02737 } else {
02738 ast_free(vmu);
02739 return NULL;
02740 }
02741 }
02742
02743
02744
02745 void mm_exists(MAILSTREAM * stream, unsigned long number)
02746 {
02747
02748 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02749 if (number == 0) return;
02750 set_update(stream);
02751 }
02752
02753
02754 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02755 {
02756
02757 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02758 if (number == 0) return;
02759 set_update(stream);
02760 }
02761
02762
02763 void mm_flags(MAILSTREAM * stream, unsigned long number)
02764 {
02765
02766 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02767 if (number == 0) return;
02768 set_update(stream);
02769 }
02770
02771
02772 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02773 {
02774 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02775 mm_log (string, errflg);
02776 }
02777
02778
02779 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02780 {
02781 if (delimiter == '\0') {
02782 delimiter = delim;
02783 }
02784
02785 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02786 if (attributes & LATT_NOINFERIORS)
02787 ast_debug(5, "no inferiors\n");
02788 if (attributes & LATT_NOSELECT)
02789 ast_debug(5, "no select\n");
02790 if (attributes & LATT_MARKED)
02791 ast_debug(5, "marked\n");
02792 if (attributes & LATT_UNMARKED)
02793 ast_debug(5, "unmarked\n");
02794 }
02795
02796
02797 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02798 {
02799 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02800 if (attributes & LATT_NOINFERIORS)
02801 ast_debug(5, "no inferiors\n");
02802 if (attributes & LATT_NOSELECT)
02803 ast_debug(5, "no select\n");
02804 if (attributes & LATT_MARKED)
02805 ast_debug(5, "marked\n");
02806 if (attributes & LATT_UNMARKED)
02807 ast_debug(5, "unmarked\n");
02808 }
02809
02810
02811 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02812 {
02813 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02814 if (status->flags & SA_MESSAGES)
02815 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02816 if (status->flags & SA_RECENT)
02817 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02818 if (status->flags & SA_UNSEEN)
02819 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02820 if (status->flags & SA_UIDVALIDITY)
02821 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02822 if (status->flags & SA_UIDNEXT)
02823 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02824 ast_log(AST_LOG_NOTICE, "\n");
02825 }
02826
02827
02828 void mm_log(char *string, long errflg)
02829 {
02830 switch ((short) errflg) {
02831 case NIL:
02832 ast_debug(1, "IMAP Info: %s\n", string);
02833 break;
02834 case PARSE:
02835 case WARN:
02836 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02837 break;
02838 case ERROR:
02839 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02840 break;
02841 }
02842 }
02843
02844
02845 void mm_dlog(char *string)
02846 {
02847 ast_log(AST_LOG_NOTICE, "%s\n", string);
02848 }
02849
02850
02851 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02852 {
02853 struct ast_vm_user *vmu;
02854
02855 ast_debug(4, "Entering callback mm_login\n");
02856
02857 ast_copy_string(user, mb->user, MAILTMPLEN);
02858
02859
02860 if (!ast_strlen_zero(authpassword)) {
02861 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02862 } else {
02863 AST_LIST_TRAVERSE(&users, vmu, list) {
02864 if (!strcasecmp(mb->user, vmu->imapuser)) {
02865 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02866 break;
02867 }
02868 }
02869 if (!vmu) {
02870 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02871 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02872 free_user(vmu);
02873 }
02874 }
02875 }
02876 }
02877
02878
02879 void mm_critical(MAILSTREAM * stream)
02880 {
02881 }
02882
02883
02884 void mm_nocritical(MAILSTREAM * stream)
02885 {
02886 }
02887
02888
02889 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02890 {
02891 kill (getpid (), SIGSTOP);
02892 return NIL;
02893 }
02894
02895
02896 void mm_fatal(char *string)
02897 {
02898 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02899 }
02900
02901
02902 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02903 {
02904 struct vm_state *vms;
02905 char *mailbox = stream->mailbox, *user;
02906 char buf[1024] = "";
02907 unsigned long usage = 0, limit = 0;
02908
02909 while (pquota) {
02910 usage = pquota->usage;
02911 limit = pquota->limit;
02912 pquota = pquota->next;
02913 }
02914
02915 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)))) {
02916 ast_log(AST_LOG_ERROR, "No state found.\n");
02917 return;
02918 }
02919
02920 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02921
02922 vms->quota_usage = usage;
02923 vms->quota_limit = limit;
02924 }
02925
02926 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02927 {
02928 char *start, *eol_pnt;
02929 int taglen;
02930
02931 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02932 return NULL;
02933
02934 taglen = strlen(tag) + 1;
02935 if (taglen < 1)
02936 return NULL;
02937
02938 if (!(start = strstr(header, tag)))
02939 return NULL;
02940
02941
02942 memset(buf, 0, len);
02943
02944 ast_copy_string(buf, start+taglen, len);
02945 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02946 *eol_pnt = '\0';
02947 return buf;
02948 }
02949
02950 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02951 {
02952 char *start, *quote, *eol_pnt;
02953
02954 if (ast_strlen_zero(mailbox))
02955 return NULL;
02956
02957 if (!(start = strstr(mailbox, "/user=")))
02958 return NULL;
02959
02960 ast_copy_string(buf, start+6, len);
02961
02962 if (!(quote = strchr(buf, '\"'))) {
02963 if (!(eol_pnt = strchr(buf, '/')))
02964 eol_pnt = strchr(buf,'}');
02965 *eol_pnt = '\0';
02966 return buf;
02967 } else {
02968 eol_pnt = strchr(buf+1,'\"');
02969 *eol_pnt = '\0';
02970 return buf+1;
02971 }
02972 }
02973
02974 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02975 {
02976 struct vm_state *vms_p;
02977
02978 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02979 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02980 return vms_p;
02981 }
02982 if (option_debug > 4)
02983 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02984 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02985 return NULL;
02986 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02987 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02988 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02989 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02990 vms_p->mailstream = NIL;
02991 vms_p->imapversion = vmu->imapversion;
02992 if (option_debug > 4)
02993 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02994 vms_p->updated = 1;
02995
02996 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02997 init_vm_state(vms_p);
02998 vmstate_insert(vms_p);
02999 return vms_p;
03000 }
03001
03002 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03003 {
03004 struct vmstate *vlist = NULL;
03005
03006 if (interactive) {
03007 struct vm_state *vms;
03008 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03009 vms = pthread_getspecific(ts_vmstate.key);
03010 return vms;
03011 }
03012
03013 AST_LIST_LOCK(&vmstates);
03014 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03015 if (!vlist->vms) {
03016 ast_debug(3, "error: vms is NULL for %s\n", user);
03017 continue;
03018 }
03019 if (vlist->vms->imapversion != imapversion) {
03020 continue;
03021 }
03022 if (!vlist->vms->imapuser) {
03023 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03024 continue;
03025 }
03026
03027 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03028 AST_LIST_UNLOCK(&vmstates);
03029 return vlist->vms;
03030 }
03031 }
03032 AST_LIST_UNLOCK(&vmstates);
03033
03034 ast_debug(3, "%s not found in vmstates\n", user);
03035
03036 return NULL;
03037 }
03038
03039 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03040 {
03041
03042 struct vmstate *vlist = NULL;
03043 const char *local_context = S_OR(context, "default");
03044
03045 if (interactive) {
03046 struct vm_state *vms;
03047 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03048 vms = pthread_getspecific(ts_vmstate.key);
03049 return vms;
03050 }
03051
03052 AST_LIST_LOCK(&vmstates);
03053 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03054 if (!vlist->vms) {
03055 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03056 continue;
03057 }
03058 if (vlist->vms->imapversion != imapversion) {
03059 continue;
03060 }
03061 if (!vlist->vms->username || !vlist->vms->context) {
03062 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03063 continue;
03064 }
03065
03066 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);
03067
03068 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03069 ast_debug(3, "Found it!\n");
03070 AST_LIST_UNLOCK(&vmstates);
03071 return vlist->vms;
03072 }
03073 }
03074 AST_LIST_UNLOCK(&vmstates);
03075
03076 ast_debug(3, "%s not found in vmstates\n", mailbox);
03077
03078 return NULL;
03079 }
03080
03081 static void vmstate_insert(struct vm_state *vms)
03082 {
03083 struct vmstate *v;
03084 struct vm_state *altvms;
03085
03086
03087
03088
03089 if (vms->interactive == 1) {
03090 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03091 if (altvms) {
03092 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03093 vms->newmessages = altvms->newmessages;
03094 vms->oldmessages = altvms->oldmessages;
03095 vms->vmArrayIndex = altvms->vmArrayIndex;
03096 vms->lastmsg = altvms->lastmsg;
03097 vms->curmsg = altvms->curmsg;
03098
03099 vms->persist_vms = altvms;
03100
03101 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03102 vms->mailstream = altvms->mailstream;
03103 #else
03104 vms->mailstream = NIL;
03105 #endif
03106 }
03107 return;
03108 }
03109
03110 if (!(v = ast_calloc(1, sizeof(*v))))
03111 return;
03112
03113 v->vms = vms;
03114
03115 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03116
03117 AST_LIST_LOCK(&vmstates);
03118 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03119 AST_LIST_UNLOCK(&vmstates);
03120 }
03121
03122 static void vmstate_delete(struct vm_state *vms)
03123 {
03124 struct vmstate *vc = NULL;
03125 struct vm_state *altvms = NULL;
03126
03127
03128
03129 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03130 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03131 altvms->newmessages = vms->newmessages;
03132 altvms->oldmessages = vms->oldmessages;
03133 altvms->updated = 1;
03134 vms->mailstream = mail_close(vms->mailstream);
03135
03136
03137 return;
03138 }
03139
03140 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03141
03142 AST_LIST_LOCK(&vmstates);
03143 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03144 if (vc->vms == vms) {
03145 AST_LIST_REMOVE_CURRENT(list);
03146 break;
03147 }
03148 }
03149 AST_LIST_TRAVERSE_SAFE_END
03150 AST_LIST_UNLOCK(&vmstates);
03151
03152 if (vc) {
03153 ast_mutex_destroy(&vc->vms->lock);
03154 ast_free(vc);
03155 }
03156 else
03157 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03158 }
03159
03160 static void set_update(MAILSTREAM * stream)
03161 {
03162 struct vm_state *vms;
03163 char *mailbox = stream->mailbox, *user;
03164 char buf[1024] = "";
03165
03166 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03167 if (user && option_debug > 2)
03168 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03169 return;
03170 }
03171
03172 ast_debug(3, "User %s mailbox set for update.\n", user);
03173
03174 vms->updated = 1;
03175 }
03176
03177 static void init_vm_state(struct vm_state *vms)
03178 {
03179 int x;
03180 vms->vmArrayIndex = 0;
03181 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03182 vms->msgArray[x] = 0;
03183 }
03184 ast_mutex_init(&vms->lock);
03185 }
03186
03187 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03188 {
03189 char *body_content;
03190 char *body_decoded;
03191 char *fn = is_intro ? vms->introfn : vms->fn;
03192 unsigned long len;
03193 unsigned long newlen;
03194 char filename[256];
03195
03196 if (!body || body == NIL)
03197 return -1;
03198
03199 ast_mutex_lock(&vms->lock);
03200 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03201 ast_mutex_unlock(&vms->lock);
03202 if (body_content != NIL) {
03203 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03204
03205 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03206
03207 if (!newlen) {
03208 return -1;
03209 }
03210 write_file(filename, (char *) body_decoded, newlen);
03211 } else {
03212 ast_debug(5, "Body of message is NULL.\n");
03213 return -1;
03214 }
03215 return 0;
03216 }
03217
03218
03219
03220
03221
03222
03223
03224
03225 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03226 char tmp[50];
03227 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03228 mail_list(stream, tmp, "*");
03229 }
03230
03231
03232
03233
03234
03235
03236
03237
03238 static void check_quota(struct vm_state *vms, char *mailbox) {
03239 ast_mutex_lock(&vms->lock);
03240 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03241 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03242 if (vms && vms->mailstream != NULL) {
03243 imap_getquotaroot(vms->mailstream, mailbox);
03244 } else {
03245 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03246 }
03247 ast_mutex_unlock(&vms->lock);
03248 }
03249
03250 #endif
03251
03252
03253
03254
03255
03256 static int vm_lock_path(const char *path)
03257 {
03258 switch (ast_lock_path(path)) {
03259 case AST_LOCK_TIMEOUT:
03260 return -1;
03261 default:
03262 return 0;
03263 }
03264 }
03265
03266
03267 #ifdef ODBC_STORAGE
03268 struct generic_prepare_struct {
03269 char *sql;
03270 int argc;
03271 char **argv;
03272 };
03273
03274 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03275 {
03276 struct generic_prepare_struct *gps = data;
03277 int res, i;
03278 SQLHSTMT stmt;
03279
03280 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03281 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03282 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03283 return NULL;
03284 }
03285 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03286 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03287 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03288 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03289 return NULL;
03290 }
03291 for (i = 0; i < gps->argc; i++)
03292 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03293
03294 return stmt;
03295 }
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311 static int retrieve_file(char *dir, int msgnum)
03312 {
03313 int x = 0;
03314 int res;
03315 int fd = -1;
03316 size_t fdlen = 0;
03317 void *fdm = MAP_FAILED;
03318 SQLSMALLINT colcount = 0;
03319 SQLHSTMT stmt;
03320 char sql[PATH_MAX];
03321 char fmt[80]="";
03322 char *c;
03323 char coltitle[256];
03324 SQLSMALLINT collen;
03325 SQLSMALLINT datatype;
03326 SQLSMALLINT decimaldigits;
03327 SQLSMALLINT nullable;
03328 SQLULEN colsize;
03329 SQLLEN colsize2;
03330 FILE *f = NULL;
03331 char rowdata[80];
03332 char fn[PATH_MAX];
03333 char full_fn[PATH_MAX];
03334 char msgnums[80];
03335 char *argv[] = { dir, msgnums };
03336 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03337
03338 struct odbc_obj *obj;
03339 obj = ast_odbc_request_obj(odbc_database, 0);
03340 if (obj) {
03341 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03342 c = strchr(fmt, '|');
03343 if (c)
03344 *c = '\0';
03345 if (!strcasecmp(fmt, "wav49"))
03346 strcpy(fmt, "WAV");
03347 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03348 if (msgnum > -1)
03349 make_file(fn, sizeof(fn), dir, msgnum);
03350 else
03351 ast_copy_string(fn, dir, sizeof(fn));
03352
03353
03354 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03355
03356 if (!(f = fopen(full_fn, "w+"))) {
03357 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03358 goto yuck;
03359 }
03360
03361 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03362 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03363 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03364 if (!stmt) {
03365 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03366 ast_odbc_release_obj(obj);
03367 goto yuck;
03368 }
03369 res = SQLFetch(stmt);
03370 if (res == SQL_NO_DATA) {
03371 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03372 ast_odbc_release_obj(obj);
03373 goto yuck;
03374 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03375 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03376 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03377 ast_odbc_release_obj(obj);
03378 goto yuck;
03379 }
03380 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03381 if (fd < 0) {
03382 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03383 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03384 ast_odbc_release_obj(obj);
03385 goto yuck;
03386 }
03387 res = SQLNumResultCols(stmt, &colcount);
03388 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03389 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03390 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03391 ast_odbc_release_obj(obj);
03392 goto yuck;
03393 }
03394 if (f)
03395 fprintf(f, "[message]\n");
03396 for (x = 0; x < colcount; x++) {
03397 rowdata[0] = '\0';
03398 colsize = 0;
03399 collen = sizeof(coltitle);
03400 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03401 &datatype, &colsize, &decimaldigits, &nullable);
03402 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03403 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03404 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03405 ast_odbc_release_obj(obj);
03406 goto yuck;
03407 }
03408 if (!strcasecmp(coltitle, "recording")) {
03409 off_t offset;
03410 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03411 fdlen = colsize2;
03412 if (fd > -1) {
03413 char tmp[1]="";
03414 lseek(fd, fdlen - 1, SEEK_SET);
03415 if (write(fd, tmp, 1) != 1) {
03416 close(fd);
03417 fd = -1;
03418 continue;
03419 }
03420
03421 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03422 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03423 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03424 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03425 ast_odbc_release_obj(obj);
03426 goto yuck;
03427 } else {
03428 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03429 munmap(fdm, CHUNKSIZE);
03430 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03431 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03432 unlink(full_fn);
03433 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03434 ast_odbc_release_obj(obj);
03435 goto yuck;
03436 }
03437 }
03438 }
03439 if (truncate(full_fn, fdlen) < 0) {
03440 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03441 }
03442 }
03443 } else {
03444 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03445 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03446 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03447 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03448 ast_odbc_release_obj(obj);
03449 goto yuck;
03450 }
03451 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03452 fprintf(f, "%s=%s\n", coltitle, rowdata);
03453 }
03454 }
03455 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03456 ast_odbc_release_obj(obj);
03457 } else
03458 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03459 yuck:
03460 if (f)
03461 fclose(f);
03462 if (fd > -1)
03463 close(fd);
03464 return x - 1;
03465 }
03466
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03479 {
03480 int x = 0;
03481 int res;
03482 SQLHSTMT stmt;
03483 char sql[PATH_MAX];
03484 char rowdata[20];
03485 char *argv[] = { dir };
03486 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03487
03488 struct odbc_obj *obj;
03489 obj = ast_odbc_request_obj(odbc_database, 0);
03490 if (obj) {
03491 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03492
03493 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03494 if (!stmt) {
03495 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03496 ast_odbc_release_obj(obj);
03497 goto yuck;
03498 }
03499 res = SQLFetch(stmt);
03500 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03501 if (res == SQL_NO_DATA) {
03502 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03503 } else {
03504 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03505 }
03506
03507 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03508 ast_odbc_release_obj(obj);
03509 goto yuck;
03510 }
03511 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03512 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03513 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03514 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03515 ast_odbc_release_obj(obj);
03516 goto yuck;
03517 }
03518 if (sscanf(rowdata, "%30d", &x) != 1)
03519 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03520 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03521 ast_odbc_release_obj(obj);
03522 return x;
03523 } else
03524 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03525 yuck:
03526 return x - 1;
03527 }
03528
03529
03530
03531
03532
03533
03534
03535
03536
03537
03538 static int message_exists(char *dir, int msgnum)
03539 {
03540 int x = 0;
03541 int res;
03542 SQLHSTMT stmt;
03543 char sql[PATH_MAX];
03544 char rowdata[20];
03545 char msgnums[20];
03546 char *argv[] = { dir, msgnums };
03547 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03548
03549 struct odbc_obj *obj;
03550 obj = ast_odbc_request_obj(odbc_database, 0);
03551 if (obj) {
03552 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03553 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03554 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03555 if (!stmt) {
03556 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03557 ast_odbc_release_obj(obj);
03558 goto yuck;
03559 }
03560 res = SQLFetch(stmt);
03561 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03562 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03563 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03564 ast_odbc_release_obj(obj);
03565 goto yuck;
03566 }
03567 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03568 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03569 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03570 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03571 ast_odbc_release_obj(obj);
03572 goto yuck;
03573 }
03574 if (sscanf(rowdata, "%30d", &x) != 1)
03575 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03576 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03577 ast_odbc_release_obj(obj);
03578 } else
03579 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03580 yuck:
03581 return x;
03582 }
03583
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593 static int count_messages(struct ast_vm_user *vmu, char *dir)
03594 {
03595 int x = 0;
03596 int res;
03597 SQLHSTMT stmt;
03598 char sql[PATH_MAX];
03599 char rowdata[20];
03600 char *argv[] = { dir };
03601 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03602
03603 struct odbc_obj *obj;
03604 obj = ast_odbc_request_obj(odbc_database, 0);
03605 if (obj) {
03606 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03607 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03608 if (!stmt) {
03609 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03610 ast_odbc_release_obj(obj);
03611 goto yuck;
03612 }
03613 res = SQLFetch(stmt);
03614 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03615 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03616 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03617 ast_odbc_release_obj(obj);
03618 goto yuck;
03619 }
03620 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03621 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03622 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03623 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03624 ast_odbc_release_obj(obj);
03625 goto yuck;
03626 }
03627 if (sscanf(rowdata, "%30d", &x) != 1)
03628 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03629 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03630 ast_odbc_release_obj(obj);
03631 return x;
03632 } else
03633 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03634 yuck:
03635 return x - 1;
03636
03637 }
03638
03639
03640
03641
03642
03643
03644
03645
03646
03647
03648
03649 static void delete_file(const char *sdir, int smsg)
03650 {
03651 SQLHSTMT stmt;
03652 char sql[PATH_MAX];
03653 char msgnums[20];
03654 char *argv[] = { NULL, msgnums };
03655 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03656 struct odbc_obj *obj;
03657
03658 argv[0] = ast_strdupa(sdir);
03659
03660 obj = ast_odbc_request_obj(odbc_database, 0);
03661 if (obj) {
03662 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03663 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03664 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03665 if (!stmt)
03666 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03667 else
03668 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03669 ast_odbc_release_obj(obj);
03670 } else
03671 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03672 return;
03673 }
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03687 {
03688 SQLHSTMT stmt;
03689 char sql[512];
03690 char msgnums[20];
03691 char msgnumd[20];
03692 struct odbc_obj *obj;
03693 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03694 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03695
03696 delete_file(ddir, dmsg);
03697 obj = ast_odbc_request_obj(odbc_database, 0);
03698 if (obj) {
03699 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03700 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03701 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);
03702 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03703 if (!stmt)
03704 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03705 else
03706 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03707 ast_odbc_release_obj(obj);
03708 } else
03709 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03710 return;
03711 }
03712
03713 struct insert_data {
03714 char *sql;
03715 const char *dir;
03716 const char *msgnums;
03717 void *data;
03718 SQLLEN datalen;
03719 SQLLEN indlen;
03720 const char *context;
03721 const char *macrocontext;
03722 const char *callerid;
03723 const char *origtime;
03724 const char *duration;
03725 const char *mailboxuser;
03726 const char *mailboxcontext;
03727 const char *category;
03728 const char *flag;
03729 };
03730
03731 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03732 {
03733 struct insert_data *data = vdata;
03734 int res;
03735 SQLHSTMT stmt;
03736
03737 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03738 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03739 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03740 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03741 return NULL;
03742 }
03743
03744 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03745 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03746 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03747 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03748 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03749 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03750 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03751 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03752 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03753 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03754 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03755 if (!ast_strlen_zero(data->category)) {
03756 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03757 }
03758 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03759 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03760 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03761 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03762 return NULL;
03763 }
03764
03765 return stmt;
03766 }
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776
03777
03778
03779
03780
03781 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03782 {
03783 int res = 0;
03784 int fd = -1;
03785 void *fdm = MAP_FAILED;
03786 size_t fdlen = -1;
03787 SQLHSTMT stmt;
03788 char sql[PATH_MAX];
03789 char msgnums[20];
03790 char fn[PATH_MAX];
03791 char full_fn[PATH_MAX];
03792 char fmt[80]="";
03793 char *c;
03794 struct ast_config *cfg = NULL;
03795 struct odbc_obj *obj;
03796 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03797 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03798 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03799
03800 delete_file(dir, msgnum);
03801 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03802 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03803 return -1;
03804 }
03805
03806 do {
03807 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03808 c = strchr(fmt, '|');
03809 if (c)
03810 *c = '\0';
03811 if (!strcasecmp(fmt, "wav49"))
03812 strcpy(fmt, "WAV");
03813 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03814 if (msgnum > -1)
03815 make_file(fn, sizeof(fn), dir, msgnum);
03816 else
03817 ast_copy_string(fn, dir, sizeof(fn));
03818 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03819 cfg = ast_config_load(full_fn, config_flags);
03820 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03821 fd = open(full_fn, O_RDWR);
03822 if (fd < 0) {
03823 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03824 res = -1;
03825 break;
03826 }
03827 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03828 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03829 idata.context = "";
03830 }
03831 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03832 idata.macrocontext = "";
03833 }
03834 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03835 idata.callerid = "";
03836 }
03837 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03838 idata.origtime = "";
03839 }
03840 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03841 idata.duration = "";
03842 }
03843 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03844 idata.category = "";
03845 }
03846 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03847 idata.flag = "";
03848 }
03849 }
03850 fdlen = lseek(fd, 0, SEEK_END);
03851 lseek(fd, 0, SEEK_SET);
03852 printf("Length is %zd\n", fdlen);
03853 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03854 if (fdm == MAP_FAILED) {
03855 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03856 res = -1;
03857 break;
03858 }
03859 idata.data = fdm;
03860 idata.datalen = idata.indlen = fdlen;
03861
03862 if (!ast_strlen_zero(idata.category))
03863 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03864 else
03865 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03866
03867 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03868 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03869 } else {
03870 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03871 res = -1;
03872 }
03873 } while (0);
03874 if (obj) {
03875 ast_odbc_release_obj(obj);
03876 }
03877 if (cfg)
03878 ast_config_destroy(cfg);
03879 if (fdm != MAP_FAILED)
03880 munmap(fdm, fdlen);
03881 if (fd > -1)
03882 close(fd);
03883 return res;
03884 }
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897
03898
03899 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03900 {
03901 SQLHSTMT stmt;
03902 char sql[PATH_MAX];
03903 char msgnums[20];
03904 char msgnumd[20];
03905 struct odbc_obj *obj;
03906 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03907 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03908
03909 delete_file(ddir, dmsg);
03910 obj = ast_odbc_request_obj(odbc_database, 0);
03911 if (obj) {
03912 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03913 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03914 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03915 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03916 if (!stmt)
03917 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03918 else
03919 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03920 ast_odbc_release_obj(obj);
03921 } else
03922 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03923 return;
03924 }
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937 static int remove_file(char *dir, int msgnum)
03938 {
03939 char fn[PATH_MAX];
03940 char full_fn[PATH_MAX];
03941 char msgnums[80];
03942
03943 if (msgnum > -1) {
03944 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03945 make_file(fn, sizeof(fn), dir, msgnum);
03946 } else
03947 ast_copy_string(fn, dir, sizeof(fn));
03948 ast_filedelete(fn, NULL);
03949 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03950 unlink(full_fn);
03951 return 0;
03952 }
03953 #else
03954 #ifndef IMAP_STORAGE
03955
03956
03957
03958
03959
03960
03961
03962
03963
03964 static int count_messages(struct ast_vm_user *vmu, char *dir)
03965 {
03966
03967 int vmcount = 0;
03968 DIR *vmdir = NULL;
03969 struct dirent *vment = NULL;
03970
03971 if (vm_lock_path(dir))
03972 return ERROR_LOCK_PATH;
03973
03974 if ((vmdir = opendir(dir))) {
03975 while ((vment = readdir(vmdir))) {
03976 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03977 vmcount++;
03978 }
03979 }
03980 closedir(vmdir);
03981 }
03982 ast_unlock_path(dir);
03983
03984 return vmcount;
03985 }
03986
03987
03988
03989
03990
03991
03992
03993
03994 static void rename_file(char *sfn, char *dfn)
03995 {
03996 char stxt[PATH_MAX];
03997 char dtxt[PATH_MAX];
03998 ast_filerename(sfn, dfn, NULL);
03999 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04000 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04001 if (ast_check_realtime("voicemail_data")) {
04002 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04003 }
04004 rename(stxt, dtxt);
04005 }
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04019 {
04020 int x;
04021 unsigned char map[MAXMSGLIMIT] = "";
04022 DIR *msgdir;
04023 struct dirent *msgdirent;
04024 int msgdirint;
04025 char extension[4];
04026 int stopcount = 0;
04027
04028
04029
04030
04031
04032 if (!(msgdir = opendir(dir))) {
04033 return -1;
04034 }
04035
04036 while ((msgdirent = readdir(msgdir))) {
04037 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04038 map[msgdirint] = 1;
04039 stopcount++;
04040 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04041 }
04042 }
04043 closedir(msgdir);
04044
04045 for (x = 0; x < vmu->maxmsg; x++) {
04046 if (map[x] == 1) {
04047 stopcount--;
04048 } else if (map[x] == 0 && !stopcount) {
04049 break;
04050 }
04051 }
04052
04053 return x - 1;
04054 }
04055
04056 #endif
04057 #endif
04058 #ifndef IMAP_STORAGE
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069 static int copy(char *infile, char *outfile)
04070 {
04071 int ifd;
04072 int ofd;
04073 int res;
04074 int len;
04075 char buf[4096];
04076
04077 #ifdef HARDLINK_WHEN_POSSIBLE
04078
04079 if (link(infile, outfile)) {
04080 #endif
04081 if ((ifd = open(infile, O_RDONLY)) < 0) {
04082 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04083 return -1;
04084 }
04085 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04086 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04087 close(ifd);
04088 return -1;
04089 }
04090 do {
04091 len = read(ifd, buf, sizeof(buf));
04092 if (len < 0) {
04093 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04094 close(ifd);
04095 close(ofd);
04096 unlink(outfile);
04097 }
04098 if (len) {
04099 res = write(ofd, buf, len);
04100 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04101 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04102 close(ifd);
04103 close(ofd);
04104 unlink(outfile);
04105 }
04106 }
04107 } while (len);
04108 close(ifd);
04109 close(ofd);
04110 return 0;
04111 #ifdef HARDLINK_WHEN_POSSIBLE
04112 } else {
04113
04114 return 0;
04115 }
04116 #endif
04117 }
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128 static void copy_plain_file(char *frompath, char *topath)
04129 {
04130 char frompath2[PATH_MAX], topath2[PATH_MAX];
04131 struct ast_variable *tmp,*var = NULL;
04132 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04133 ast_filecopy(frompath, topath, NULL);
04134 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04135 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04136 if (ast_check_realtime("voicemail_data")) {
04137 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04138
04139 for (tmp = var; tmp; tmp = tmp->next) {
04140 if (!strcasecmp(tmp->name, "origmailbox")) {
04141 origmailbox = tmp->value;
04142 } else if (!strcasecmp(tmp->name, "context")) {
04143 context = tmp->value;
04144 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04145 macrocontext = tmp->value;
04146 } else if (!strcasecmp(tmp->name, "exten")) {
04147 exten = tmp->value;
04148 } else if (!strcasecmp(tmp->name, "priority")) {
04149 priority = tmp->value;
04150 } else if (!strcasecmp(tmp->name, "callerchan")) {
04151 callerchan = tmp->value;
04152 } else if (!strcasecmp(tmp->name, "callerid")) {
04153 callerid = tmp->value;
04154 } else if (!strcasecmp(tmp->name, "origdate")) {
04155 origdate = tmp->value;
04156 } else if (!strcasecmp(tmp->name, "origtime")) {
04157 origtime = tmp->value;
04158 } else if (!strcasecmp(tmp->name, "category")) {
04159 category = tmp->value;
04160 } else if (!strcasecmp(tmp->name, "duration")) {
04161 duration = tmp->value;
04162 }
04163 }
04164 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);
04165 }
04166 copy(frompath2, topath2);
04167 ast_variables_destroy(var);
04168 }
04169 #endif
04170
04171
04172
04173
04174
04175
04176
04177
04178
04179 static int vm_delete(char *file)
04180 {
04181 char *txt;
04182 int txtsize = 0;
04183
04184 txtsize = (strlen(file) + 5)*sizeof(char);
04185 txt = alloca(txtsize);
04186
04187
04188
04189 if (ast_check_realtime("voicemail_data")) {
04190 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04191 }
04192 snprintf(txt, txtsize, "%s.txt", file);
04193 unlink(txt);
04194 return ast_filedelete(file, NULL);
04195 }
04196
04197
04198
04199
04200 static int inbuf(struct baseio *bio, FILE *fi)
04201 {
04202 int l;
04203
04204 if (bio->ateof)
04205 return 0;
04206
04207 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04208 if (ferror(fi))
04209 return -1;
04210
04211 bio->ateof = 1;
04212 return 0;
04213 }
04214
04215 bio->iolen = l;
04216 bio->iocp = 0;
04217
04218 return 1;
04219 }
04220
04221
04222
04223
04224 static int inchar(struct baseio *bio, FILE *fi)
04225 {
04226 if (bio->iocp>=bio->iolen) {
04227 if (!inbuf(bio, fi))
04228 return EOF;
04229 }
04230
04231 return bio->iobuf[bio->iocp++];
04232 }
04233
04234
04235
04236
04237 static int ochar(struct baseio *bio, int c, FILE *so)
04238 {
04239 if (bio->linelength >= BASELINELEN) {
04240 if (fputs(ENDL, so) == EOF) {
04241 return -1;
04242 }
04243
04244 bio->linelength = 0;
04245 }
04246
04247 if (putc(((unsigned char) c), so) == EOF) {
04248 return -1;
04249 }
04250
04251 bio->linelength++;
04252
04253 return 1;
04254 }
04255
04256
04257
04258
04259
04260
04261
04262
04263
04264
04265 static int base_encode(char *filename, FILE *so)
04266 {
04267 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04268 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04269 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04270 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04271 int i, hiteof = 0;
04272 FILE *fi;
04273 struct baseio bio;
04274
04275 memset(&bio, 0, sizeof(bio));
04276 bio.iocp = BASEMAXINLINE;
04277
04278 if (!(fi = fopen(filename, "rb"))) {
04279 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04280 return -1;
04281 }
04282
04283 while (!hiteof){
04284 unsigned char igroup[3], ogroup[4];
04285 int c, n;
04286
04287 memset(igroup, 0, sizeof(igroup));
04288
04289 for (n = 0; n < 3; n++) {
04290 if ((c = inchar(&bio, fi)) == EOF) {
04291 hiteof = 1;
04292 break;
04293 }
04294
04295 igroup[n] = (unsigned char) c;
04296 }
04297
04298 if (n > 0) {
04299 ogroup[0]= dtable[igroup[0] >> 2];
04300 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04301 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04302 ogroup[3]= dtable[igroup[2] & 0x3F];
04303
04304 if (n < 3) {
04305 ogroup[3] = '=';
04306
04307 if (n < 2)
04308 ogroup[2] = '=';
04309 }
04310
04311 for (i = 0; i < 4; i++)
04312 ochar(&bio, ogroup[i], so);
04313 }
04314 }
04315
04316 fclose(fi);
04317
04318 if (fputs(ENDL, so) == EOF) {
04319 return 0;
04320 }
04321
04322 return 1;
04323 }
04324
04325 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)
04326 {
04327 char callerid[256];
04328 char num[12];
04329 char fromdir[256], fromfile[256];
04330 struct ast_config *msg_cfg;
04331 const char *origcallerid, *origtime;
04332 char origcidname[80], origcidnum[80], origdate[80];
04333 int inttime;
04334 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04335
04336
04337 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04338 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04339 snprintf(num, sizeof(num), "%d", msgnum);
04340 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04341 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04342 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04343 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04344 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04345 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04346 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04347 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04348 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04349 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04350
04351
04352 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04353 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04354 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04355 strcat(fromfile, ".txt");
04356 }
04357 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04358 if (option_debug > 0) {
04359 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04360 }
04361 return;
04362 }
04363
04364 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04365 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04366 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04367 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04368 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04369 }
04370
04371 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04372 struct timeval tv = { inttime, };
04373 struct ast_tm tm;
04374 ast_localtime(&tv, &tm, NULL);
04375 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04376 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04377 }
04378 ast_config_destroy(msg_cfg);
04379 }
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04390 {
04391 const char *ptr;
04392
04393
04394 ast_str_set(buf, maxlen, "\"");
04395 for (ptr = from; *ptr; ptr++) {
04396 if (*ptr == '"' || *ptr == '\\') {
04397 ast_str_append(buf, maxlen, "\\%c", *ptr);
04398 } else {
04399 ast_str_append(buf, maxlen, "%c", *ptr);
04400 }
04401 }
04402 ast_str_append(buf, maxlen, "\"");
04403
04404 return ast_str_buffer(*buf);
04405 }
04406
04407
04408
04409
04410
04411 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04412 {
04413 const struct vm_zone *z = NULL;
04414 struct timeval t = ast_tvnow();
04415
04416
04417 if (!ast_strlen_zero(vmu->zonetag)) {
04418
04419 AST_LIST_LOCK(&zones);
04420 AST_LIST_TRAVERSE(&zones, z, list) {
04421 if (!strcmp(z->name, vmu->zonetag))
04422 break;
04423 }
04424 AST_LIST_UNLOCK(&zones);
04425 }
04426 ast_localtime(&t, tm, z ? z->timezone : NULL);
04427 return tm;
04428 }
04429
04430
04431
04432
04433
04434 static int check_mime(const char *str)
04435 {
04436 for (; *str; str++) {
04437 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04438 return 1;
04439 }
04440 }
04441 return 0;
04442 }
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04462 {
04463 struct ast_str *tmp = ast_str_alloca(80);
04464 int first_section = 1;
04465
04466 ast_str_reset(*end);
04467 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04468 for (; *start; start++) {
04469 int need_encoding = 0;
04470 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04471 need_encoding = 1;
04472 }
04473 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04474 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04475 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04476 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04477
04478 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04479 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04480 first_section = 0;
04481 }
04482 if (need_encoding && *start == ' ') {
04483 ast_str_append(&tmp, -1, "_");
04484 } else if (need_encoding) {
04485 ast_str_append(&tmp, -1, "=%hhX", *start);
04486 } else {
04487 ast_str_append(&tmp, -1, "%c", *start);
04488 }
04489 }
04490 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04491 return ast_str_buffer(*end);
04492 }
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517 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)
04518 {
04519 char date[256];
04520 char host[MAXHOSTNAMELEN] = "";
04521 char who[256];
04522 char bound[256];
04523 char dur[256];
04524 struct ast_tm tm;
04525 char enc_cidnum[256] = "", enc_cidname[256] = "";
04526 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04527 char *greeting_attachment;
04528 char filename[256];
04529
04530 if (!str1 || !str2) {
04531 ast_free(str1);
04532 ast_free(str2);
04533 return;
04534 }
04535
04536 if (cidnum) {
04537 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04538 }
04539 if (cidname) {
04540 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04541 }
04542 gethostname(host, sizeof(host) - 1);
04543
04544 if (strchr(srcemail, '@')) {
04545 ast_copy_string(who, srcemail, sizeof(who));
04546 } else {
04547 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04548 }
04549
04550 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04551 if (greeting_attachment) {
04552 *greeting_attachment++ = '\0';
04553 }
04554
04555 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04556 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04557 fprintf(p, "Date: %s" ENDL, date);
04558
04559
04560 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04561
04562 if (!ast_strlen_zero(fromstring)) {
04563 struct ast_channel *ast;
04564 if ((ast = ast_dummy_channel_alloc())) {
04565 char *ptr;
04566 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04567 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04568
04569 if (check_mime(ast_str_buffer(str1))) {
04570 int first_line = 1;
04571 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04572 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04573 *ptr = '\0';
04574 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04575 first_line = 0;
04576
04577 ast_str_set(&str2, 0, "%s", ptr + 1);
04578 }
04579 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04580 } else {
04581 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04582 }
04583 ast = ast_channel_unref(ast);
04584 } else {
04585 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04586 }
04587 } else {
04588 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04589 }
04590
04591 if (check_mime(vmu->fullname)) {
04592 int first_line = 1;
04593 char *ptr;
04594 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04595 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04596 *ptr = '\0';
04597 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04598 first_line = 0;
04599
04600 ast_str_set(&str2, 0, "%s", ptr + 1);
04601 }
04602 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04603 } else {
04604 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04605 }
04606
04607 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04608 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04609 struct ast_channel *ast;
04610 if ((ast = ast_dummy_channel_alloc())) {
04611 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04612 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04613 if (check_mime(ast_str_buffer(str1))) {
04614 int first_line = 1;
04615 char *ptr;
04616 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04617 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04618 *ptr = '\0';
04619 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04620 first_line = 0;
04621
04622 ast_str_set(&str2, 0, "%s", ptr + 1);
04623 }
04624 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04625 } else {
04626 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04627 }
04628 ast = ast_channel_unref(ast);
04629 } else {
04630 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04631 }
04632 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04633 if (ast_strlen_zero(flag)) {
04634 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04635 } else {
04636 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04637 }
04638 } else {
04639 if (ast_strlen_zero(flag)) {
04640 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04641 } else {
04642 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04643 }
04644 }
04645
04646 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04647 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04648 if (imap) {
04649
04650 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04651
04652 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04653 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04654 #ifdef IMAP_STORAGE
04655 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04656 #else
04657 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04658 #endif
04659
04660 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04661 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04662 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04663 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04664 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04665 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04666 if (!ast_strlen_zero(category)) {
04667 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04668 } else {
04669 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04670 }
04671 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04672 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04673 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04674 }
04675 if (!ast_strlen_zero(cidnum)) {
04676 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04677 }
04678 if (!ast_strlen_zero(cidname)) {
04679 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04680 }
04681 fprintf(p, "MIME-Version: 1.0" ENDL);
04682 if (attach_user_voicemail) {
04683
04684 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04685 (int) getpid(), (unsigned int) ast_random());
04686
04687 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04688 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04689 fprintf(p, "--%s" ENDL, bound);
04690 }
04691 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04692 if (emailbody || vmu->emailbody) {
04693 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04694 struct ast_channel *ast;
04695 if ((ast = ast_dummy_channel_alloc())) {
04696 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04697 ast_str_substitute_variables(&str1, 0, ast, e_body);
04698 #ifdef IMAP_STORAGE
04699 {
04700
04701 char *line = ast_str_buffer(str1), *next;
04702 do {
04703
04704 if ((next = strchr(line, '\n'))) {
04705 *next++ = '\0';
04706 }
04707 fprintf(p, "%s" ENDL, line);
04708 line = next;
04709 } while (!ast_strlen_zero(line));
04710 }
04711 #else
04712 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04713 #endif
04714 ast = ast_channel_unref(ast);
04715 } else {
04716 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04717 }
04718 } else if (msgnum > -1) {
04719 if (strcmp(vmu->mailbox, mailbox)) {
04720
04721 struct ast_config *msg_cfg;
04722 const char *v;
04723 int inttime;
04724 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04725 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04726
04727 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04728 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04729 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04730 strcat(fromfile, ".txt");
04731 }
04732 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04733 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04734 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04735 }
04736
04737
04738
04739 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04740 struct timeval tv = { inttime, };
04741 struct ast_tm tm;
04742 ast_localtime(&tv, &tm, NULL);
04743 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04744 }
04745 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04746 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04747 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04748 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04749 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04750 date, origcallerid, origdate);
04751 ast_config_destroy(msg_cfg);
04752 } else {
04753 goto plain_message;
04754 }
04755 } else {
04756 plain_message:
04757 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04758 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04759 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04760 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04761 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04762 }
04763 } else {
04764 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04765 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04766 }
04767
04768 if (imap || attach_user_voicemail) {
04769 if (!ast_strlen_zero(attach2)) {
04770 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04771 ast_debug(5, "creating second attachment filename %s\n", filename);
04772 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04773 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04774 ast_debug(5, "creating attachment filename %s\n", filename);
04775 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04776 } else {
04777 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04778 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04779 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04780 }
04781 }
04782 ast_free(str1);
04783 ast_free(str2);
04784 }
04785
04786 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)
04787 {
04788 char tmpdir[256], newtmp[256];
04789 char fname[256];
04790 char tmpcmd[256];
04791 int tmpfd = -1;
04792 int soxstatus = 0;
04793
04794
04795 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04796
04797 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04798 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04799 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04800 tmpfd = mkstemp(newtmp);
04801 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04802 ast_debug(3, "newtmp: %s\n", newtmp);
04803 if (tmpfd > -1) {
04804 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04805 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04806 attach = newtmp;
04807 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04808 } else {
04809 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04810 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04811 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04812 }
04813 }
04814 }
04815 fprintf(p, "--%s" ENDL, bound);
04816 if (msgnum > -1)
04817 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04818 else
04819 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04820 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04821 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04822 if (msgnum > -1)
04823 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04824 else
04825 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04826 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04827 base_encode(fname, p);
04828 if (last)
04829 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04830 if (tmpfd > -1) {
04831 if (soxstatus == 0) {
04832 unlink(fname);
04833 }
04834 close(tmpfd);
04835 unlink(newtmp);
04836 }
04837 return 0;
04838 }
04839
04840 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)
04841 {
04842 FILE *p = NULL;
04843 char tmp[80] = "/tmp/astmail-XXXXXX";
04844 char tmp2[256];
04845 char *stringp;
04846
04847 if (vmu && ast_strlen_zero(vmu->email)) {
04848 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04849 return(0);
04850 }
04851
04852
04853 format = ast_strdupa(format);
04854 stringp = format;
04855 strsep(&stringp, "|");
04856
04857 if (!strcmp(format, "wav49"))
04858 format = "WAV";
04859 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04860
04861
04862 if ((p = vm_mkftemp(tmp)) == NULL) {
04863 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04864 return -1;
04865 } else {
04866 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04867 fclose(p);
04868 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04869 ast_safe_system(tmp2);
04870 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04871 }
04872 return 0;
04873 }
04874
04875 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)
04876 {
04877 char enc_cidnum[256], enc_cidname[256];
04878 char date[256];
04879 char host[MAXHOSTNAMELEN] = "";
04880 char who[256];
04881 char dur[PATH_MAX];
04882 char tmp[80] = "/tmp/astmail-XXXXXX";
04883 char tmp2[PATH_MAX];
04884 struct ast_tm tm;
04885 FILE *p;
04886 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04887
04888 if (!str1 || !str2) {
04889 ast_free(str1);
04890 ast_free(str2);
04891 return -1;
04892 }
04893
04894 if (cidnum) {
04895 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04896 }
04897 if (cidname) {
04898 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04899 }
04900
04901 if ((p = vm_mkftemp(tmp)) == NULL) {
04902 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04903 ast_free(str1);
04904 ast_free(str2);
04905 return -1;
04906 }
04907 gethostname(host, sizeof(host)-1);
04908 if (strchr(srcemail, '@')) {
04909 ast_copy_string(who, srcemail, sizeof(who));
04910 } else {
04911 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04912 }
04913 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04914 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04915 fprintf(p, "Date: %s\n", date);
04916
04917
04918 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04919
04920 if (!ast_strlen_zero(pagerfromstring)) {
04921 struct ast_channel *ast;
04922 if ((ast = ast_dummy_channel_alloc())) {
04923 char *ptr;
04924 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04925 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04926
04927 if (check_mime(ast_str_buffer(str1))) {
04928 int first_line = 1;
04929 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04930 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04931 *ptr = '\0';
04932 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04933 first_line = 0;
04934
04935 ast_str_set(&str2, 0, "%s", ptr + 1);
04936 }
04937 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04938 } else {
04939 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04940 }
04941 ast = ast_channel_unref(ast);
04942 } else {
04943 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04944 }
04945 } else {
04946 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04947 }
04948
04949 if (check_mime(vmu->fullname)) {
04950 int first_line = 1;
04951 char *ptr;
04952 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04953 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04954 *ptr = '\0';
04955 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04956 first_line = 0;
04957
04958 ast_str_set(&str2, 0, "%s", ptr + 1);
04959 }
04960 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04961 } else {
04962 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04963 }
04964
04965 if (!ast_strlen_zero(pagersubject)) {
04966 struct ast_channel *ast;
04967 if ((ast = ast_dummy_channel_alloc())) {
04968 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04969 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04970 if (check_mime(ast_str_buffer(str1))) {
04971 int first_line = 1;
04972 char *ptr;
04973 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04974 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04975 *ptr = '\0';
04976 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04977 first_line = 0;
04978
04979 ast_str_set(&str2, 0, "%s", ptr + 1);
04980 }
04981 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04982 } else {
04983 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04984 }
04985 ast = ast_channel_unref(ast);
04986 } else {
04987 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04988 }
04989 } else {
04990 if (ast_strlen_zero(flag)) {
04991 fprintf(p, "Subject: New VM\n\n");
04992 } else {
04993 fprintf(p, "Subject: New %s VM\n\n", flag);
04994 }
04995 }
04996
04997 if (pagerbody) {
04998 struct ast_channel *ast;
04999 if ((ast = ast_dummy_channel_alloc())) {
05000 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05001 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05002 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05003 ast = ast_channel_unref(ast);
05004 } else {
05005 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05006 }
05007 } else {
05008 fprintf(p, "New %s long %s msg in box %s\n"
05009 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05010 }
05011
05012 fclose(p);
05013 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05014 ast_safe_system(tmp2);
05015 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05016 ast_free(str1);
05017 ast_free(str2);
05018 return 0;
05019 }
05020
05021
05022
05023
05024
05025
05026
05027
05028
05029
05030 static int get_date(char *s, int len)
05031 {
05032 struct ast_tm tm;
05033 struct timeval t = ast_tvnow();
05034
05035 ast_localtime(&t, &tm, "UTC");
05036
05037 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05038 }
05039
05040 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05041 {
05042 int res;
05043 char fn[PATH_MAX];
05044 char dest[PATH_MAX];
05045
05046 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05047
05048 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05049 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05050 return -1;
05051 }
05052
05053 RETRIEVE(fn, -1, ext, context);
05054 if (ast_fileexists(fn, NULL, NULL) > 0) {
05055 res = ast_stream_and_wait(chan, fn, ecodes);
05056 if (res) {
05057 DISPOSE(fn, -1);
05058 return res;
05059 }
05060 } else {
05061
05062 DISPOSE(fn, -1);
05063 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05064 if (res)
05065 return res;
05066 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05067 if (res)
05068 return res;
05069 }
05070 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05071 return res;
05072 }
05073
05074 static void free_zone(struct vm_zone *z)
05075 {
05076 ast_free(z);
05077 }
05078
05079 #ifdef ODBC_STORAGE
05080 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05081 {
05082 int x = -1;
05083 int res;
05084 SQLHSTMT stmt = NULL;
05085 char sql[PATH_MAX];
05086 char rowdata[20];
05087 char tmp[PATH_MAX] = "";
05088 struct odbc_obj *obj = NULL;
05089 char *context;
05090 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05091
05092 if (newmsgs)
05093 *newmsgs = 0;
05094 if (oldmsgs)
05095 *oldmsgs = 0;
05096 if (urgentmsgs)
05097 *urgentmsgs = 0;
05098
05099
05100 if (ast_strlen_zero(mailbox))
05101 return 0;
05102
05103 ast_copy_string(tmp, mailbox, sizeof(tmp));
05104
05105 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05106 int u, n, o;
05107 char *next, *remaining = tmp;
05108 while ((next = strsep(&remaining, " ,"))) {
05109 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05110 return -1;
05111 }
05112 if (urgentmsgs) {
05113 *urgentmsgs += u;
05114 }
05115 if (newmsgs) {
05116 *newmsgs += n;
05117 }
05118 if (oldmsgs) {
05119 *oldmsgs += o;
05120 }
05121 }
05122 return 0;
05123 }
05124
05125 context = strchr(tmp, '@');
05126 if (context) {
05127 *context = '\0';
05128 context++;
05129 } else
05130 context = "default";
05131
05132 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05133 do {
05134 if (newmsgs) {
05135 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05136 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05137 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05138 break;
05139 }
05140 res = SQLFetch(stmt);
05141 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05142 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05143 break;
05144 }
05145 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05146 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05147 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05148 break;
05149 }
05150 *newmsgs = atoi(rowdata);
05151 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05152 }
05153
05154 if (oldmsgs) {
05155 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05156 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05157 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05158 break;
05159 }
05160 res = SQLFetch(stmt);
05161 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05162 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05163 break;
05164 }
05165 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05166 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05167 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05168 break;
05169 }
05170 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05171 *oldmsgs = atoi(rowdata);
05172 }
05173
05174 if (urgentmsgs) {
05175 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05176 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05177 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05178 break;
05179 }
05180 res = SQLFetch(stmt);
05181 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05182 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05183 break;
05184 }
05185 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05186 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05187 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05188 break;
05189 }
05190 *urgentmsgs = atoi(rowdata);
05191 }
05192
05193 x = 0;
05194 } while (0);
05195 } else {
05196 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05197 }
05198
05199 if (stmt) {
05200 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05201 }
05202 if (obj) {
05203 ast_odbc_release_obj(obj);
05204 }
05205 return x;
05206 }
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217 static int messagecount(const char *context, const char *mailbox, const char *folder)
05218 {
05219 struct odbc_obj *obj = NULL;
05220 int nummsgs = 0;
05221 int res;
05222 SQLHSTMT stmt = NULL;
05223 char sql[PATH_MAX];
05224 char rowdata[20];
05225 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05226 if (!folder)
05227 folder = "INBOX";
05228
05229 if (ast_strlen_zero(mailbox))
05230 return 0;
05231
05232 obj = ast_odbc_request_obj(odbc_database, 0);
05233 if (obj) {
05234 if (!strcmp(folder, "INBOX")) {
05235 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);
05236 } else {
05237 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05238 }
05239 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05240 if (!stmt) {
05241 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05242 goto yuck;
05243 }
05244 res = SQLFetch(stmt);
05245 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05246 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05247 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05248 goto yuck;
05249 }
05250 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05251 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05252 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05253 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05254 goto yuck;
05255 }
05256 nummsgs = atoi(rowdata);
05257 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05258 } else
05259 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05260
05261 yuck:
05262 if (obj)
05263 ast_odbc_release_obj(obj);
05264 return nummsgs;
05265 }
05266
05267
05268
05269
05270
05271
05272
05273
05274
05275 static int has_voicemail(const char *mailbox, const char *folder)
05276 {
05277 char tmp[256], *tmp2 = tmp, *box, *context;
05278 ast_copy_string(tmp, mailbox, sizeof(tmp));
05279 while ((context = box = strsep(&tmp2, ",&"))) {
05280 strsep(&context, "@");
05281 if (ast_strlen_zero(context))
05282 context = "default";
05283 if (messagecount(context, box, folder))
05284 return 1;
05285 }
05286 return 0;
05287 }
05288 #endif
05289 #ifndef IMAP_STORAGE
05290
05291
05292
05293
05294
05295
05296
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306 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)
05307 {
05308 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05309 const char *frombox = mbox(vmu, imbox);
05310 const char *userfolder;
05311 int recipmsgnum;
05312 int res = 0;
05313
05314 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05315
05316 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05317 userfolder = "Urgent";
05318 } else {
05319 userfolder = "INBOX";
05320 }
05321
05322 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05323
05324 if (!dir)
05325 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05326 else
05327 ast_copy_string(fromdir, dir, sizeof(fromdir));
05328
05329 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05330 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05331
05332 if (vm_lock_path(todir))
05333 return ERROR_LOCK_PATH;
05334
05335 recipmsgnum = last_message_index(recip, todir) + 1;
05336 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05337 make_file(topath, sizeof(topath), todir, recipmsgnum);
05338 #ifndef ODBC_STORAGE
05339 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05340 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05341 } else {
05342 #endif
05343
05344
05345
05346 copy_plain_file(frompath, topath);
05347 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05348 vm_delete(topath);
05349 #ifndef ODBC_STORAGE
05350 }
05351 #endif
05352 } else {
05353 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05354 res = -1;
05355 }
05356 ast_unlock_path(todir);
05357 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05358 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05359 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05360 flag);
05361
05362 return res;
05363 }
05364 #endif
05365 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05366
05367 static int messagecount(const char *context, const char *mailbox, const char *folder)
05368 {
05369 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05370 }
05371
05372 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05373 {
05374 DIR *dir;
05375 struct dirent *de;
05376 char fn[256];
05377 int ret = 0;
05378
05379
05380 if (ast_strlen_zero(mailbox))
05381 return 0;
05382
05383 if (ast_strlen_zero(folder))
05384 folder = "INBOX";
05385 if (ast_strlen_zero(context))
05386 context = "default";
05387
05388 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05389
05390 if (!(dir = opendir(fn)))
05391 return 0;
05392
05393 while ((de = readdir(dir))) {
05394 if (!strncasecmp(de->d_name, "msg", 3)) {
05395 if (shortcircuit) {
05396 ret = 1;
05397 break;
05398 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05399 ret++;
05400 }
05401 }
05402 }
05403
05404 closedir(dir);
05405
05406 return ret;
05407 }
05408
05409
05410
05411
05412
05413
05414
05415
05416
05417
05418 static int has_voicemail(const char *mailbox, const char *folder)
05419 {
05420 char tmp[256], *tmp2 = tmp, *box, *context;
05421 ast_copy_string(tmp, mailbox, sizeof(tmp));
05422 if (ast_strlen_zero(folder)) {
05423 folder = "INBOX";
05424 }
05425 while ((box = strsep(&tmp2, ",&"))) {
05426 if ((context = strchr(box, '@')))
05427 *context++ = '\0';
05428 else
05429 context = "default";
05430 if (__has_voicemail(context, box, folder, 1))
05431 return 1;
05432
05433 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05434 return 1;
05435 }
05436 }
05437 return 0;
05438 }
05439
05440
05441 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05442 {
05443 char tmp[256];
05444 char *context;
05445
05446
05447 if (ast_strlen_zero(mailbox))
05448 return 0;
05449
05450 if (newmsgs)
05451 *newmsgs = 0;
05452 if (oldmsgs)
05453 *oldmsgs = 0;
05454 if (urgentmsgs)
05455 *urgentmsgs = 0;
05456
05457 if (strchr(mailbox, ',')) {
05458 int tmpnew, tmpold, tmpurgent;
05459 char *mb, *cur;
05460
05461 ast_copy_string(tmp, mailbox, sizeof(tmp));
05462 mb = tmp;
05463 while ((cur = strsep(&mb, ", "))) {
05464 if (!ast_strlen_zero(cur)) {
05465 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05466 return -1;
05467 else {
05468 if (newmsgs)
05469 *newmsgs += tmpnew;
05470 if (oldmsgs)
05471 *oldmsgs += tmpold;
05472 if (urgentmsgs)
05473 *urgentmsgs += tmpurgent;
05474 }
05475 }
05476 }
05477 return 0;
05478 }
05479
05480 ast_copy_string(tmp, mailbox, sizeof(tmp));
05481
05482 if ((context = strchr(tmp, '@')))
05483 *context++ = '\0';
05484 else
05485 context = "default";
05486
05487 if (newmsgs)
05488 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05489 if (oldmsgs)
05490 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05491 if (urgentmsgs)
05492 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05493
05494 return 0;
05495 }
05496
05497 #endif
05498
05499
05500 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05501 {
05502 int urgentmsgs = 0;
05503 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05504 if (newmsgs) {
05505 *newmsgs += urgentmsgs;
05506 }
05507 return res;
05508 }
05509
05510 static void run_externnotify(char *context, char *extension, const char *flag)
05511 {
05512 char arguments[255];
05513 char ext_context[256] = "";
05514 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05515 struct ast_smdi_mwi_message *mwi_msg;
05516
05517 if (!ast_strlen_zero(context))
05518 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05519 else
05520 ast_copy_string(ext_context, extension, sizeof(ext_context));
05521
05522 if (smdi_iface) {
05523 if (ast_app_has_voicemail(ext_context, NULL))
05524 ast_smdi_mwi_set(smdi_iface, extension);
05525 else
05526 ast_smdi_mwi_unset(smdi_iface, extension);
05527
05528 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05529 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05530 if (!strncmp(mwi_msg->cause, "INV", 3))
05531 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05532 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05533 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05534 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05535 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05536 } else {
05537 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05538 }
05539 }
05540
05541 if (!ast_strlen_zero(externnotify)) {
05542 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05543 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05544 } else {
05545 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05546 ast_debug(1, "Executing %s\n", arguments);
05547 ast_safe_system(arguments);
05548 }
05549 }
05550 }
05551
05552
05553
05554
05555
05556
05557 struct leave_vm_options {
05558 unsigned int flags;
05559 signed char record_gain;
05560 char *exitcontext;
05561 };
05562
05563
05564
05565
05566
05567
05568
05569
05570
05571
05572
05573 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05574 {
05575 #ifdef IMAP_STORAGE
05576 int newmsgs, oldmsgs;
05577 #else
05578 char urgdir[PATH_MAX];
05579 #endif
05580 char txtfile[PATH_MAX];
05581 char tmptxtfile[PATH_MAX];
05582 struct vm_state *vms = NULL;
05583 char callerid[256];
05584 FILE *txt;
05585 char date[256];
05586 int txtdes;
05587 int res = 0;
05588 int msgnum;
05589 int duration = 0;
05590 int sound_duration = 0;
05591 int ausemacro = 0;
05592 int ousemacro = 0;
05593 int ouseexten = 0;
05594 char tmpdur[16];
05595 char priority[16];
05596 char origtime[16];
05597 char dir[PATH_MAX];
05598 char tmpdir[PATH_MAX];
05599 char fn[PATH_MAX];
05600 char prefile[PATH_MAX] = "";
05601 char tempfile[PATH_MAX] = "";
05602 char ext_context[256] = "";
05603 char fmt[80];
05604 char *context;
05605 char ecodes[17] = "#";
05606 struct ast_str *tmp = ast_str_create(16);
05607 char *tmpptr;
05608 struct ast_vm_user *vmu;
05609 struct ast_vm_user svm;
05610 const char *category = NULL;
05611 const char *code;
05612 const char *alldtmf = "0123456789ABCD*#";
05613 char flag[80];
05614
05615 if (!tmp) {
05616 return -1;
05617 }
05618
05619 ast_str_set(&tmp, 0, "%s", ext);
05620 ext = ast_str_buffer(tmp);
05621 if ((context = strchr(ext, '@'))) {
05622 *context++ = '\0';
05623 tmpptr = strchr(context, '&');
05624 } else {
05625 tmpptr = strchr(ext, '&');
05626 }
05627
05628 if (tmpptr)
05629 *tmpptr++ = '\0';
05630
05631 ast_channel_lock(chan);
05632 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05633 category = ast_strdupa(category);
05634 }
05635 ast_channel_unlock(chan);
05636
05637 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05638 ast_copy_string(flag, "Urgent", sizeof(flag));
05639 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05640 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05641 } else {
05642 flag[0] = '\0';
05643 }
05644
05645 ast_debug(3, "Before find_user\n");
05646 if (!(vmu = find_user(&svm, context, ext))) {
05647 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05648 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05649 ast_free(tmp);
05650 return res;
05651 }
05652
05653 if (strcmp(vmu->context, "default"))
05654 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05655 else
05656 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05657
05658
05659
05660
05661
05662
05663 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05664 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05665 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05666 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05667 }
05668
05669
05670
05671
05672 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05673 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05674 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05675 ast_free(tmp);
05676 return -1;
05677 }
05678 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05679 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05680 ast_copy_string(prefile, tempfile, sizeof(prefile));
05681
05682 DISPOSE(tempfile, -1);
05683
05684 #ifndef IMAP_STORAGE
05685 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05686 #else
05687 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05688 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05689 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05690 }
05691 #endif
05692
05693
05694 if (ast_test_flag(vmu, VM_OPERATOR)) {
05695 if (!ast_strlen_zero(vmu->exit)) {
05696 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05697 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05698 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05699 ouseexten = 1;
05700 }
05701 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05702 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05703 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05704 ouseexten = 1;
05705 } else if (!ast_strlen_zero(chan->macrocontext)
05706 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05707 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05708 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05709 ousemacro = 1;
05710 }
05711 }
05712
05713 if (!ast_strlen_zero(vmu->exit)) {
05714 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05715 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05716 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05717 }
05718 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05719 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05720 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05721 } else if (!ast_strlen_zero(chan->macrocontext)
05722 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05723 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05724 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05725 ausemacro = 1;
05726 }
05727
05728 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05729 for (code = alldtmf; *code; code++) {
05730 char e[2] = "";
05731 e[0] = *code;
05732 if (strchr(ecodes, e[0]) == NULL
05733 && ast_canmatch_extension(chan, chan->context, e, 1,
05734 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05735 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05736 }
05737 }
05738 }
05739
05740
05741 if (!ast_strlen_zero(prefile)) {
05742 #ifdef ODBC_STORAGE
05743 int success =
05744 #endif
05745 RETRIEVE(prefile, -1, ext, context);
05746 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05747 if (ast_streamfile(chan, prefile, chan->language) > -1)
05748 res = ast_waitstream(chan, ecodes);
05749 #ifdef ODBC_STORAGE
05750 if (success == -1) {
05751
05752 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05753 store_file(prefile, vmu->mailbox, vmu->context, -1);
05754 }
05755 #endif
05756 } else {
05757 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05758 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05759 }
05760 DISPOSE(prefile, -1);
05761 if (res < 0) {
05762 ast_debug(1, "Hang up during prefile playback\n");
05763 free_user(vmu);
05764 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05765 ast_free(tmp);
05766 return -1;
05767 }
05768 }
05769 if (res == '#') {
05770
05771 ast_set_flag(options, OPT_SILENT);
05772 res = 0;
05773 }
05774
05775 if (vmu->maxmsg == 0) {
05776 if (option_debug > 2)
05777 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05778 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05779 goto leave_vm_out;
05780 }
05781 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05782 res = ast_stream_and_wait(chan, INTRO, ecodes);
05783 if (res == '#') {
05784 ast_set_flag(options, OPT_SILENT);
05785 res = 0;
05786 }
05787 }
05788 if (res > 0)
05789 ast_stopstream(chan);
05790
05791
05792 if (res == '*') {
05793 chan->exten[0] = 'a';
05794 chan->exten[1] = '\0';
05795 if (!ast_strlen_zero(vmu->exit)) {
05796 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05797 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05798 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05799 }
05800 chan->priority = 0;
05801 free_user(vmu);
05802 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05803 ast_free(tmp);
05804 return 0;
05805 }
05806
05807
05808 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05809 transfer:
05810 if (ouseexten || ousemacro) {
05811 chan->exten[0] = 'o';
05812 chan->exten[1] = '\0';
05813 if (!ast_strlen_zero(vmu->exit)) {
05814 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05815 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05816 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05817 }
05818 ast_play_and_wait(chan, "transfer");
05819 chan->priority = 0;
05820 free_user(vmu);
05821 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05822 }
05823 ast_free(tmp);
05824 return OPERATOR_EXIT;
05825 }
05826
05827
05828 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05829 if (!ast_strlen_zero(options->exitcontext))
05830 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05831 free_user(vmu);
05832 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05833 ast_free(tmp);
05834 return res;
05835 }
05836
05837 if (res < 0) {
05838 free_user(vmu);
05839 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05840 ast_free(tmp);
05841 return -1;
05842 }
05843
05844 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05845 if (!ast_strlen_zero(fmt)) {
05846 msgnum = 0;
05847
05848 #ifdef IMAP_STORAGE
05849
05850
05851 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05852 if (res < 0) {
05853 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05854 ast_free(tmp);
05855 return -1;
05856 }
05857 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05858
05859
05860
05861
05862 if (!(vms = create_vm_state_from_user(vmu))) {
05863 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05864 ast_free(tmp);
05865 return -1;
05866 }
05867 }
05868 vms->newmessages++;
05869
05870
05871 msgnum = newmsgs + oldmsgs;
05872 ast_debug(3, "Messagecount set to %d\n", msgnum);
05873 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05874
05875 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05876
05877 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05878 goto leave_vm_out;
05879 }
05880 #else
05881 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05882 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05883 if (!res)
05884 res = ast_waitstream(chan, "");
05885 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05886 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05887 inprocess_count(vmu->mailbox, vmu->context, -1);
05888 goto leave_vm_out;
05889 }
05890
05891 #endif
05892 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05893 txtdes = mkstemp(tmptxtfile);
05894 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05895 if (txtdes < 0) {
05896 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05897 if (!res)
05898 res = ast_waitstream(chan, "");
05899 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05900 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05901 inprocess_count(vmu->mailbox, vmu->context, -1);
05902 goto leave_vm_out;
05903 }
05904
05905
05906 if (res >= 0) {
05907
05908 res = ast_stream_and_wait(chan, "beep", "");
05909 }
05910
05911
05912 if (ast_check_realtime("voicemail_data")) {
05913 snprintf(priority, sizeof(priority), "%d", chan->priority);
05914 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05915 get_date(date, sizeof(date));
05916 ast_callerid_merge(callerid, sizeof(callerid),
05917 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05918 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05919 "Unknown");
05920 ast_store_realtime("voicemail_data",
05921 "origmailbox", ext,
05922 "context", chan->context,
05923 "macrocontext", chan->macrocontext,
05924 "exten", chan->exten,
05925 "priority", priority,
05926 "callerchan", chan->name,
05927 "callerid", callerid,
05928 "origdate", date,
05929 "origtime", origtime,
05930 "category", S_OR(category, ""),
05931 "filename", tmptxtfile,
05932 SENTINEL);
05933 }
05934
05935
05936 txt = fdopen(txtdes, "w+");
05937 if (txt) {
05938 get_date(date, sizeof(date));
05939 ast_callerid_merge(callerid, sizeof(callerid),
05940 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05941 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05942 "Unknown");
05943 fprintf(txt,
05944 ";\n"
05945 "; Message Information file\n"
05946 ";\n"
05947 "[message]\n"
05948 "origmailbox=%s\n"
05949 "context=%s\n"
05950 "macrocontext=%s\n"
05951 "exten=%s\n"
05952 "rdnis=%s\n"
05953 "priority=%d\n"
05954 "callerchan=%s\n"
05955 "callerid=%s\n"
05956 "origdate=%s\n"
05957 "origtime=%ld\n"
05958 "category=%s\n",
05959 ext,
05960 chan->context,
05961 chan->macrocontext,
05962 chan->exten,
05963 S_COR(chan->redirecting.from.number.valid,
05964 chan->redirecting.from.number.str, "unknown"),
05965 chan->priority,
05966 chan->name,
05967 callerid,
05968 date, (long) time(NULL),
05969 category ? category : "");
05970 } else {
05971 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05972 inprocess_count(vmu->mailbox, vmu->context, -1);
05973 if (ast_check_realtime("voicemail_data")) {
05974 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05975 }
05976 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05977 goto leave_vm_out;
05978 }
05979 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05980
05981 if (txt) {
05982 fprintf(txt, "flag=%s\n", flag);
05983 if (sound_duration < vmu->minsecs) {
05984 fclose(txt);
05985 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
05986 ast_filedelete(tmptxtfile, NULL);
05987 unlink(tmptxtfile);
05988 if (ast_check_realtime("voicemail_data")) {
05989 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05990 }
05991 inprocess_count(vmu->mailbox, vmu->context, -1);
05992 } else {
05993 fprintf(txt, "duration=%d\n", duration);
05994 fclose(txt);
05995 if (vm_lock_path(dir)) {
05996 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05997
05998 ast_filedelete(tmptxtfile, NULL);
05999 unlink(tmptxtfile);
06000 inprocess_count(vmu->mailbox, vmu->context, -1);
06001 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06002 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06003 unlink(tmptxtfile);
06004 ast_unlock_path(dir);
06005 inprocess_count(vmu->mailbox, vmu->context, -1);
06006 if (ast_check_realtime("voicemail_data")) {
06007 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06008 }
06009 } else {
06010 #ifndef IMAP_STORAGE
06011 msgnum = last_message_index(vmu, dir) + 1;
06012 #endif
06013 make_file(fn, sizeof(fn), dir, msgnum);
06014
06015
06016 #ifndef IMAP_STORAGE
06017 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06018 #else
06019 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06020 #endif
06021
06022 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06023 ast_filerename(tmptxtfile, fn, NULL);
06024 rename(tmptxtfile, txtfile);
06025 inprocess_count(vmu->mailbox, vmu->context, -1);
06026
06027
06028
06029 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06030 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06031
06032 ast_unlock_path(dir);
06033 if (ast_check_realtime("voicemail_data")) {
06034 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06035 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06036 }
06037
06038
06039
06040 if (ast_fileexists(fn, NULL, NULL) > 0) {
06041 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06042 }
06043
06044
06045 while (tmpptr) {
06046 struct ast_vm_user recipu, *recip;
06047 char *exten, *cntx;
06048
06049 exten = strsep(&tmpptr, "&");
06050 cntx = strchr(exten, '@');
06051 if (cntx) {
06052 *cntx = '\0';
06053 cntx++;
06054 }
06055 if ((recip = find_user(&recipu, cntx, exten))) {
06056 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06057 free_user(recip);
06058 }
06059 }
06060 #ifndef IMAP_STORAGE
06061 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06062
06063 char sfn[PATH_MAX];
06064 char dfn[PATH_MAX];
06065 int x;
06066
06067 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06068 x = last_message_index(vmu, urgdir) + 1;
06069 make_file(sfn, sizeof(sfn), dir, msgnum);
06070 make_file(dfn, sizeof(dfn), urgdir, x);
06071 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06072 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06073
06074 ast_copy_string(fn, dfn, sizeof(fn));
06075 msgnum = x;
06076 }
06077 #endif
06078
06079 if (ast_fileexists(fn, NULL, NULL)) {
06080 #ifdef IMAP_STORAGE
06081 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06082 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06083 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06084 flag);
06085 #else
06086 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06087 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06088 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06089 flag);
06090 #endif
06091 }
06092
06093
06094 if (ast_fileexists(fn, NULL, NULL)) {
06095 DISPOSE(dir, msgnum);
06096 }
06097 }
06098 }
06099 } else {
06100 inprocess_count(vmu->mailbox, vmu->context, -1);
06101 }
06102 if (res == '0') {
06103 goto transfer;
06104 } else if (res > 0 && res != 't')
06105 res = 0;
06106
06107 if (sound_duration < vmu->minsecs)
06108
06109 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06110 else
06111 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06112 } else
06113 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06114 leave_vm_out:
06115 free_user(vmu);
06116
06117 #ifdef IMAP_STORAGE
06118
06119 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06120 if (expungeonhangup == 1) {
06121 ast_mutex_lock(&vms->lock);
06122 #ifdef HAVE_IMAP_TK2006
06123 if (LEVELUIDPLUS (vms->mailstream)) {
06124 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06125 } else
06126 #endif
06127 mail_expunge(vms->mailstream);
06128 ast_mutex_unlock(&vms->lock);
06129 }
06130 #endif
06131
06132 ast_free(tmp);
06133 return res;
06134 }
06135
06136 #if !defined(IMAP_STORAGE)
06137 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06138 {
06139
06140
06141 int x, dest;
06142 char sfn[PATH_MAX];
06143 char dfn[PATH_MAX];
06144
06145 if (vm_lock_path(dir)) {
06146 return ERROR_LOCK_PATH;
06147 }
06148
06149 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06150 make_file(sfn, sizeof(sfn), dir, x);
06151 if (EXISTS(dir, x, sfn, NULL)) {
06152
06153 if (x != dest) {
06154 make_file(dfn, sizeof(dfn), dir, dest);
06155 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06156 }
06157
06158 dest++;
06159 }
06160 }
06161 ast_unlock_path(dir);
06162
06163 return dest;
06164 }
06165 #endif
06166
06167 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06168 {
06169 int d;
06170 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06171 return d;
06172 }
06173
06174 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06175 {
06176 #ifdef IMAP_STORAGE
06177
06178
06179 char sequence[10];
06180 char mailbox[256];
06181 int res;
06182
06183
06184 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06185
06186 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06187 ast_mutex_lock(&vms->lock);
06188
06189 if (box == OLD_FOLDER) {
06190 mail_setflag(vms->mailstream, sequence, "\\Seen");
06191 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06192 } else if (box == NEW_FOLDER) {
06193 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06194 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06195 }
06196 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06197 ast_mutex_unlock(&vms->lock);
06198 return 0;
06199 }
06200
06201 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06202 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06203 if (mail_create(vms->mailstream, mailbox) == NIL)
06204 ast_debug(5, "Folder exists.\n");
06205 else
06206 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06207 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06208 ast_mutex_unlock(&vms->lock);
06209 return res;
06210 #else
06211 char *dir = vms->curdir;
06212 char *username = vms->username;
06213 char *context = vmu->context;
06214 char sfn[PATH_MAX];
06215 char dfn[PATH_MAX];
06216 char ddir[PATH_MAX];
06217 const char *dbox = mbox(vmu, box);
06218 int x, i;
06219 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06220
06221 if (vm_lock_path(ddir))
06222 return ERROR_LOCK_PATH;
06223
06224 x = last_message_index(vmu, ddir) + 1;
06225
06226 if (box == 10 && x >= vmu->maxdeletedmsg) {
06227 x--;
06228 for (i = 1; i <= x; i++) {
06229
06230 make_file(sfn, sizeof(sfn), ddir, i);
06231 make_file(dfn, sizeof(dfn), ddir, i - 1);
06232 if (EXISTS(ddir, i, sfn, NULL)) {
06233 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06234 } else
06235 break;
06236 }
06237 } else {
06238 if (x >= vmu->maxmsg) {
06239 ast_unlock_path(ddir);
06240 return -1;
06241 }
06242 }
06243 make_file(sfn, sizeof(sfn), dir, msg);
06244 make_file(dfn, sizeof(dfn), ddir, x);
06245 if (strcmp(sfn, dfn)) {
06246 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06247 }
06248 ast_unlock_path(ddir);
06249 #endif
06250 return 0;
06251 }
06252
06253 static int adsi_logo(unsigned char *buf)
06254 {
06255 int bytes = 0;
06256 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06257 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06258 return bytes;
06259 }
06260
06261 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06262 {
06263 unsigned char buf[256];
06264 int bytes = 0;
06265 int x;
06266 char num[5];
06267
06268 *useadsi = 0;
06269 bytes += ast_adsi_data_mode(buf + bytes);
06270 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06271
06272 bytes = 0;
06273 bytes += adsi_logo(buf);
06274 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06275 #ifdef DISPLAY
06276 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06277 #endif
06278 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06279 bytes += ast_adsi_data_mode(buf + bytes);
06280 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06281
06282 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06283 bytes = 0;
06284 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06285 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06286 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06287 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06288 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06289 return 0;
06290 }
06291
06292 #ifdef DISPLAY
06293
06294 bytes = 0;
06295 bytes += ast_adsi_logo(buf);
06296 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06297 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06298 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06299 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06300 #endif
06301 bytes = 0;
06302 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06303 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06304 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06305 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06306 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06307 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06308 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06309
06310 #ifdef DISPLAY
06311
06312 bytes = 0;
06313 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06314 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06315
06316 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06317 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06318 #endif
06319
06320 bytes = 0;
06321
06322 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06323 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06324 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06325 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06326 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06327 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06328 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06329
06330 #ifdef DISPLAY
06331
06332 bytes = 0;
06333 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06334 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06335 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06336 #endif
06337
06338 bytes = 0;
06339 for (x = 0; x < 5; x++) {
06340 snprintf(num, sizeof(num), "%d", x);
06341 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06342 }
06343 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06344 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06345
06346 #ifdef DISPLAY
06347
06348 bytes = 0;
06349 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06350 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06351 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06352 #endif
06353
06354 if (ast_adsi_end_download(chan)) {
06355 bytes = 0;
06356 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06357 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06358 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06359 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06360 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06361 return 0;
06362 }
06363 bytes = 0;
06364 bytes += ast_adsi_download_disconnect(buf + bytes);
06365 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06366 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06367
06368 ast_debug(1, "Done downloading scripts...\n");
06369
06370 #ifdef DISPLAY
06371
06372 bytes = 0;
06373 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06374 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06375 #endif
06376 ast_debug(1, "Restarting session...\n");
06377
06378 bytes = 0;
06379
06380 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06381 *useadsi = 1;
06382 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06383 } else
06384 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06385
06386 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06387 return 0;
06388 }
06389
06390 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06391 {
06392 int x;
06393 if (!ast_adsi_available(chan))
06394 return;
06395 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06396 if (x < 0)
06397 return;
06398 if (!x) {
06399 if (adsi_load_vmail(chan, useadsi)) {
06400 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06401 return;
06402 }
06403 } else
06404 *useadsi = 1;
06405 }
06406
06407 static void adsi_login(struct ast_channel *chan)
06408 {
06409 unsigned char buf[256];
06410 int bytes = 0;
06411 unsigned char keys[8];
06412 int x;
06413 if (!ast_adsi_available(chan))
06414 return;
06415
06416 for (x = 0; x < 8; x++)
06417 keys[x] = 0;
06418
06419 keys[3] = ADSI_KEY_APPS + 3;
06420
06421 bytes += adsi_logo(buf + bytes);
06422 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06423 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06424 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06425 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06426 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06427 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06428 bytes += ast_adsi_set_keys(buf + bytes, keys);
06429 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06430 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06431 }
06432
06433 static void adsi_password(struct ast_channel *chan)
06434 {
06435 unsigned char buf[256];
06436 int bytes = 0;
06437 unsigned char keys[8];
06438 int x;
06439 if (!ast_adsi_available(chan))
06440 return;
06441
06442 for (x = 0; x < 8; x++)
06443 keys[x] = 0;
06444
06445 keys[3] = ADSI_KEY_APPS + 3;
06446
06447 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06448 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06449 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06450 bytes += ast_adsi_set_keys(buf + bytes, keys);
06451 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06452 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06453 }
06454
06455 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06456 {
06457 unsigned char buf[256];
06458 int bytes = 0;
06459 unsigned char keys[8];
06460 int x, y;
06461
06462 if (!ast_adsi_available(chan))
06463 return;
06464
06465 for (x = 0; x < 5; x++) {
06466 y = ADSI_KEY_APPS + 12 + start + x;
06467 if (y > ADSI_KEY_APPS + 12 + 4)
06468 y = 0;
06469 keys[x] = ADSI_KEY_SKT | y;
06470 }
06471 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06472 keys[6] = 0;
06473 keys[7] = 0;
06474
06475 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06476 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06477 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06478 bytes += ast_adsi_set_keys(buf + bytes, keys);
06479 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06480
06481 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06482 }
06483
06484 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06485 {
06486 int bytes = 0;
06487 unsigned char buf[256];
06488 char buf1[256], buf2[256];
06489 char fn2[PATH_MAX];
06490
06491 char cid[256] = "";
06492 char *val;
06493 char *name, *num;
06494 char datetime[21] = "";
06495 FILE *f;
06496
06497 unsigned char keys[8];
06498
06499 int x;
06500
06501 if (!ast_adsi_available(chan))
06502 return;
06503
06504
06505 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06506 f = fopen(fn2, "r");
06507 if (f) {
06508 while (!feof(f)) {
06509 if (!fgets((char *) buf, sizeof(buf), f)) {
06510 continue;
06511 }
06512 if (!feof(f)) {
06513 char *stringp = NULL;
06514 stringp = (char *) buf;
06515 strsep(&stringp, "=");
06516 val = strsep(&stringp, "=");
06517 if (!ast_strlen_zero(val)) {
06518 if (!strcmp((char *) buf, "callerid"))
06519 ast_copy_string(cid, val, sizeof(cid));
06520 if (!strcmp((char *) buf, "origdate"))
06521 ast_copy_string(datetime, val, sizeof(datetime));
06522 }
06523 }
06524 }
06525 fclose(f);
06526 }
06527
06528 for (x = 0; x < 5; x++)
06529 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06530 keys[6] = 0x0;
06531 keys[7] = 0x0;
06532
06533 if (!vms->curmsg) {
06534
06535 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06536 }
06537 if (vms->curmsg >= vms->lastmsg) {
06538
06539 if (vms->curmsg) {
06540
06541 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06542 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06543
06544 } else {
06545
06546 keys[3] = 1;
06547 }
06548 }
06549
06550 if (!ast_strlen_zero(cid)) {
06551 ast_callerid_parse(cid, &name, &num);
06552 if (!name)
06553 name = num;
06554 } else
06555 name = "Unknown Caller";
06556
06557
06558
06559 if (vms->deleted[vms->curmsg])
06560 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06561
06562
06563 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06564 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06565 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06566 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06567
06568 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06569 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06570 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06571 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06572 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06573 bytes += ast_adsi_set_keys(buf + bytes, keys);
06574 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06575
06576 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06577 }
06578
06579 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06580 {
06581 int bytes = 0;
06582 unsigned char buf[256];
06583 unsigned char keys[8];
06584
06585 int x;
06586
06587 if (!ast_adsi_available(chan))
06588 return;
06589
06590
06591 for (x = 0; x < 5; x++)
06592 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06593
06594 keys[6] = 0x0;
06595 keys[7] = 0x0;
06596
06597 if (!vms->curmsg) {
06598
06599 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06600 }
06601 if (vms->curmsg >= vms->lastmsg) {
06602
06603 if (vms->curmsg) {
06604
06605 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06606 } else {
06607
06608 keys[3] = 1;
06609 }
06610 }
06611
06612
06613 if (vms->deleted[vms->curmsg])
06614 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06615
06616
06617 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06618 bytes += ast_adsi_set_keys(buf + bytes, keys);
06619 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06620
06621 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06622 }
06623
06624 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06625 {
06626 unsigned char buf[256] = "";
06627 char buf1[256] = "", buf2[256] = "";
06628 int bytes = 0;
06629 unsigned char keys[8];
06630 int x;
06631
06632 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06633 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06634 if (!ast_adsi_available(chan))
06635 return;
06636 if (vms->newmessages) {
06637 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06638 if (vms->oldmessages) {
06639 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06640 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06641 } else {
06642 snprintf(buf2, sizeof(buf2), "%s.", newm);
06643 }
06644 } else if (vms->oldmessages) {
06645 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06646 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06647 } else {
06648 strcpy(buf1, "You have no messages.");
06649 buf2[0] = ' ';
06650 buf2[1] = '\0';
06651 }
06652 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06653 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06654 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06655
06656 for (x = 0; x < 6; x++)
06657 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06658 keys[6] = 0;
06659 keys[7] = 0;
06660
06661
06662 if (vms->lastmsg < 0)
06663 keys[0] = 1;
06664 bytes += ast_adsi_set_keys(buf + bytes, keys);
06665
06666 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06667
06668 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06669 }
06670
06671 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06672 {
06673 unsigned char buf[256] = "";
06674 char buf1[256] = "", buf2[256] = "";
06675 int bytes = 0;
06676 unsigned char keys[8];
06677 int x;
06678
06679 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06680
06681 if (!ast_adsi_available(chan))
06682 return;
06683
06684
06685 for (x = 0; x < 6; x++)
06686 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06687
06688 keys[6] = 0;
06689 keys[7] = 0;
06690
06691 if ((vms->lastmsg + 1) < 1)
06692 keys[0] = 0;
06693
06694 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06695 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06696
06697 if (vms->lastmsg + 1)
06698 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06699 else
06700 strcpy(buf2, "no messages.");
06701 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06702 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06703 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06704 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06705 bytes += ast_adsi_set_keys(buf + bytes, keys);
06706
06707 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06708
06709 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06710
06711 }
06712
06713
06714
06715
06716
06717
06718
06719
06720
06721
06722
06723
06724
06725
06726
06727 static void adsi_goodbye(struct ast_channel *chan)
06728 {
06729 unsigned char buf[256];
06730 int bytes = 0;
06731
06732 if (!ast_adsi_available(chan))
06733 return;
06734 bytes += adsi_logo(buf + bytes);
06735 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06736 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06737 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06738 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06739
06740 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06741 }
06742
06743
06744
06745
06746
06747 static int get_folder(struct ast_channel *chan, int start)
06748 {
06749 int x;
06750 int d;
06751 char fn[PATH_MAX];
06752 d = ast_play_and_wait(chan, "vm-press");
06753 if (d)
06754 return d;
06755 for (x = start; x < 5; x++) {
06756 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06757 return d;
06758 d = ast_play_and_wait(chan, "vm-for");
06759 if (d)
06760 return d;
06761 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06762
06763
06764
06765
06766 if (x == 0) {
06767 if (ast_fileexists(fn, NULL, NULL)) {
06768 d = vm_play_folder_name(chan, fn);
06769 } else {
06770 ast_verb(1, "failed to find %s\n", fn);
06771 d = vm_play_folder_name(chan, "vm-INBOX");
06772 }
06773 } else {
06774 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06775 d = vm_play_folder_name(chan, fn);
06776 }
06777
06778 if (d)
06779 return d;
06780 d = ast_waitfordigit(chan, 500);
06781 if (d)
06782 return d;
06783 }
06784
06785 d = ast_play_and_wait(chan, "vm-tocancel");
06786 if (d)
06787 return d;
06788 d = ast_waitfordigit(chan, 4000);
06789 return d;
06790 }
06791
06792
06793
06794
06795
06796
06797
06798
06799
06800
06801
06802
06803
06804 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06805 {
06806 int res = 0;
06807 int loops = 0;
06808
06809 res = ast_play_and_wait(chan, fn);
06810 while (((res < '0') || (res > '9')) &&
06811 (res != '#') && (res >= 0) &&
06812 loops < 4) {
06813 res = get_folder(chan, 0);
06814 loops++;
06815 }
06816 if (loops == 4) {
06817 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06818 return '#';
06819 }
06820 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06821 return res;
06822 }
06823
06824
06825
06826
06827
06828
06829
06830
06831
06832
06833
06834
06835
06836
06837
06838
06839
06840
06841
06842 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06843 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06844 {
06845 int cmd = 0;
06846 int retries = 0, prepend_duration = 0, already_recorded = 0;
06847 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06848 char textfile[PATH_MAX];
06849 struct ast_config *msg_cfg;
06850 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06851 #ifndef IMAP_STORAGE
06852 signed char zero_gain = 0;
06853 #endif
06854 const char *duration_str;
06855
06856
06857 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06858 strcpy(textfile, msgfile);
06859 strcpy(backup, msgfile);
06860 strcpy(backup_textfile, msgfile);
06861 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06862 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06863 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06864
06865 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06866 *duration = atoi(duration_str);
06867 } else {
06868 *duration = 0;
06869 }
06870
06871 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06872 if (cmd)
06873 retries = 0;
06874 switch (cmd) {
06875 case '1':
06876
06877 #ifdef IMAP_STORAGE
06878
06879 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06880 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06881 ast_play_and_wait(chan, INTRO);
06882 ast_play_and_wait(chan, "beep");
06883 play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06884 cmd = 't';
06885 #else
06886
06887
06888
06889 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06890 strcpy(textfile, msgfile);
06891 strncat(textfile, ".txt", sizeof(textfile) - 1);
06892 *duration = 0;
06893
06894
06895 if (!msg_cfg) {
06896 cmd = 0;
06897 break;
06898 }
06899
06900
06901 #ifndef IMAP_STORAGE
06902 if (already_recorded) {
06903 ast_filecopy(backup, msgfile, NULL);
06904 copy(backup_textfile, textfile);
06905 }
06906 else {
06907 ast_filecopy(msgfile, backup, NULL);
06908 copy(textfile, backup_textfile);
06909 }
06910 #endif
06911 already_recorded = 1;
06912
06913 if (record_gain)
06914 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06915
06916 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06917
06918 if (cmd == 'S') {
06919 ast_stream_and_wait(chan, vm_pls_try_again, "");
06920 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06921 ast_filerename(backup, msgfile, NULL);
06922 }
06923
06924 if (record_gain)
06925 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06926
06927
06928 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06929 *duration = atoi(duration_str);
06930
06931 if (prepend_duration) {
06932 struct ast_category *msg_cat;
06933
06934 char duration_buf[12];
06935
06936 *duration += prepend_duration;
06937 msg_cat = ast_category_get(msg_cfg, "message");
06938 snprintf(duration_buf, 11, "%ld", *duration);
06939 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06940 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06941 }
06942 }
06943
06944 #endif
06945 break;
06946 case '2':
06947
06948 #ifdef IMAP_STORAGE
06949 *vms->introfn = '\0';
06950 #endif
06951 cmd = 't';
06952 break;
06953 case '*':
06954 cmd = '*';
06955 break;
06956 default:
06957
06958 already_recorded = 0;
06959
06960 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06961
06962 if (!cmd) {
06963 cmd = ast_play_and_wait(chan, "vm-starmain");
06964
06965 }
06966 if (!cmd) {
06967 cmd = ast_waitfordigit(chan, 6000);
06968 }
06969 if (!cmd) {
06970 retries++;
06971 }
06972 if (retries > 3) {
06973 cmd = '*';
06974 }
06975 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
06976 }
06977 }
06978
06979 if (msg_cfg)
06980 ast_config_destroy(msg_cfg);
06981 if (prepend_duration)
06982 *duration = prepend_duration;
06983
06984 if (already_recorded && cmd == -1) {
06985
06986 ast_filerename(backup, msgfile, NULL);
06987 rename(backup_textfile, textfile);
06988 }
06989
06990 if (cmd == 't' || cmd == 'S')
06991 cmd = 0;
06992 return cmd;
06993 }
06994
06995 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06996 {
06997 struct ast_event *event;
06998 char *mailbox, *context;
06999
07000
07001 context = mailbox = ast_strdupa(box);
07002 strsep(&context, "@");
07003 if (ast_strlen_zero(context))
07004 context = "default";
07005
07006 if (!(event = ast_event_new(AST_EVENT_MWI,
07007 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07008 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07009 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07010 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07011 AST_EVENT_IE_END))) {
07012 return;
07013 }
07014
07015 ast_event_queue_and_cache(event);
07016 }
07017
07018
07019
07020
07021
07022
07023
07024
07025
07026
07027
07028
07029
07030
07031
07032 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)
07033 {
07034 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07035 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07036 const char *category;
07037 char *myserveremail = serveremail;
07038
07039 ast_channel_lock(chan);
07040 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07041 category = ast_strdupa(category);
07042 }
07043 ast_channel_unlock(chan);
07044
07045 #ifndef IMAP_STORAGE
07046 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07047 #else
07048 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07049 #endif
07050 make_file(fn, sizeof(fn), todir, msgnum);
07051 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07052
07053 if (!ast_strlen_zero(vmu->attachfmt)) {
07054 if (strstr(fmt, vmu->attachfmt))
07055 fmt = vmu->attachfmt;
07056 else
07057 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);
07058 }
07059
07060
07061 fmt = ast_strdupa(fmt);
07062 stringp = fmt;
07063 strsep(&stringp, "|");
07064
07065 if (!ast_strlen_zero(vmu->serveremail))
07066 myserveremail = vmu->serveremail;
07067
07068 if (!ast_strlen_zero(vmu->email)) {
07069 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07070
07071 if (attach_user_voicemail)
07072 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07073
07074
07075 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07076
07077 if (attach_user_voicemail)
07078 DISPOSE(todir, msgnum);
07079 }
07080
07081 if (!ast_strlen_zero(vmu->pager)) {
07082 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07083 }
07084
07085 if (ast_test_flag(vmu, VM_DELETE))
07086 DELETE(todir, msgnum, fn, vmu);
07087
07088
07089 if (ast_app_has_voicemail(ext_context, NULL))
07090 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07091
07092 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07093
07094 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);
07095 run_externnotify(vmu->context, vmu->mailbox, flag);
07096
07097 #ifdef IMAP_STORAGE
07098 vm_delete(fn);
07099 if (ast_test_flag(vmu, VM_DELETE)) {
07100 vm_imap_delete(NULL, vms->curmsg, vmu);
07101 vms->newmessages--;
07102 }
07103 #endif
07104
07105 return 0;
07106 }
07107
07108
07109
07110
07111
07112
07113
07114
07115
07116
07117
07118
07119
07120
07121
07122
07123
07124
07125
07126
07127
07128
07129
07130
07131
07132
07133
07134
07135 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)
07136 {
07137 #ifdef IMAP_STORAGE
07138 int todircount = 0;
07139 struct vm_state *dstvms;
07140 #endif
07141 char username[70]="";
07142 char fn[PATH_MAX];
07143 char ecodes[16] = "#";
07144 int res = 0, cmd = 0;
07145 struct ast_vm_user *receiver = NULL, *vmtmp;
07146 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07147 char *stringp;
07148 const char *s;
07149 int saved_messages = 0;
07150 int valid_extensions = 0;
07151 char *dir;
07152 int curmsg;
07153 char urgent_str[7] = "";
07154 int prompt_played = 0;
07155 #ifndef IMAP_STORAGE
07156 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07157 #endif
07158 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07159 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07160 }
07161
07162 if (vms == NULL) return -1;
07163 dir = vms->curdir;
07164 curmsg = vms->curmsg;
07165
07166 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07167 while (!res && !valid_extensions) {
07168 int use_directory = 0;
07169 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07170 int done = 0;
07171 int retries = 0;
07172 cmd = 0;
07173 while ((cmd >= 0) && !done ){
07174 if (cmd)
07175 retries = 0;
07176 switch (cmd) {
07177 case '1':
07178 use_directory = 0;
07179 done = 1;
07180 break;
07181 case '2':
07182 use_directory = 1;
07183 done = 1;
07184 break;
07185 case '*':
07186 cmd = 't';
07187 done = 1;
07188 break;
07189 default:
07190
07191 cmd = ast_play_and_wait(chan, "vm-forward");
07192 if (!cmd) {
07193 cmd = ast_waitfordigit(chan, 3000);
07194 }
07195 if (!cmd) {
07196 retries++;
07197 }
07198 if (retries > 3) {
07199 cmd = 't';
07200 done = 1;
07201 }
07202 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07203 }
07204 }
07205 if (cmd < 0 || cmd == 't')
07206 break;
07207 }
07208
07209 if (use_directory) {
07210
07211
07212 char old_context[sizeof(chan->context)];
07213 char old_exten[sizeof(chan->exten)];
07214 int old_priority;
07215 struct ast_app* directory_app;
07216
07217 directory_app = pbx_findapp("Directory");
07218 if (directory_app) {
07219 char vmcontext[256];
07220
07221 memcpy(old_context, chan->context, sizeof(chan->context));
07222 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07223 old_priority = chan->priority;
07224
07225
07226 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07227 res = pbx_exec(chan, directory_app, vmcontext);
07228
07229 ast_copy_string(username, chan->exten, sizeof(username));
07230
07231
07232 memcpy(chan->context, old_context, sizeof(chan->context));
07233 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07234 chan->priority = old_priority;
07235 } else {
07236 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07237 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07238 }
07239 } else {
07240
07241 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07242 res = ast_streamfile(chan, "vm-extension", chan->language);
07243 prompt_played++;
07244 if (res || prompt_played > 4)
07245 break;
07246 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07247 break;
07248 }
07249
07250
07251 if (ast_strlen_zero(username))
07252 continue;
07253 stringp = username;
07254 s = strsep(&stringp, "*");
07255
07256 valid_extensions = 1;
07257 while (s) {
07258 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07259 int oldmsgs;
07260 int newmsgs;
07261 int capacity;
07262 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07263 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07264
07265 res = ast_play_and_wait(chan, "pbx-invalid");
07266 valid_extensions = 0;
07267 break;
07268 }
07269 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07270 if ((newmsgs + oldmsgs) >= capacity) {
07271 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07272 res = ast_play_and_wait(chan, "vm-mailboxfull");
07273 valid_extensions = 0;
07274 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07275 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07276 free_user(vmtmp);
07277 }
07278 inprocess_count(receiver->mailbox, receiver->context, -1);
07279 break;
07280 }
07281 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07282 } else {
07283
07284
07285
07286
07287
07288 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07289 free_user(receiver);
07290 }
07291 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07292
07293 res = ast_play_and_wait(chan, "pbx-invalid");
07294 valid_extensions = 0;
07295 break;
07296 }
07297
07298
07299 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07300 RETRIEVE(fn, -1, s, receiver->context);
07301 if (ast_fileexists(fn, NULL, NULL) > 0) {
07302 res = ast_stream_and_wait(chan, fn, ecodes);
07303 if (res) {
07304 DISPOSE(fn, -1);
07305 return res;
07306 }
07307 } else {
07308 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07309 }
07310 DISPOSE(fn, -1);
07311
07312 s = strsep(&stringp, "*");
07313 }
07314
07315 if (valid_extensions)
07316 break;
07317 }
07318
07319 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07320 return res;
07321 if (is_new_message == 1) {
07322 struct leave_vm_options leave_options;
07323 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07324 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07325
07326
07327 memset(&leave_options, 0, sizeof(leave_options));
07328 leave_options.record_gain = record_gain;
07329 cmd = leave_voicemail(chan, mailbox, &leave_options);
07330 } else {
07331
07332 long duration = 0;
07333 struct vm_state vmstmp;
07334 int copy_msg_result = 0;
07335 memcpy(&vmstmp, vms, sizeof(vmstmp));
07336
07337 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07338
07339 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07340 if (!cmd) {
07341 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07342 #ifdef IMAP_STORAGE
07343 int attach_user_voicemail;
07344 char *myserveremail = serveremail;
07345
07346
07347 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07348 if (!dstvms) {
07349 dstvms = create_vm_state_from_user(vmtmp);
07350 }
07351 if (dstvms) {
07352 init_mailstream(dstvms, 0);
07353 if (!dstvms->mailstream) {
07354 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07355 } else {
07356 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07357 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07358 }
07359 } else {
07360 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07361 }
07362 if (!ast_strlen_zero(vmtmp->serveremail))
07363 myserveremail = vmtmp->serveremail;
07364 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07365
07366 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07367 dstvms->curbox,
07368 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07369 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07370 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07371 NULL, urgent_str);
07372 #else
07373 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07374 #endif
07375 saved_messages++;
07376 AST_LIST_REMOVE_CURRENT(list);
07377 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07378 free_user(vmtmp);
07379 if (res)
07380 break;
07381 }
07382 AST_LIST_TRAVERSE_SAFE_END;
07383 if (saved_messages > 0 && !copy_msg_result) {
07384
07385
07386
07387
07388
07389
07390
07391
07392 #ifdef IMAP_STORAGE
07393
07394 if (ast_strlen_zero(vmstmp.introfn))
07395 #endif
07396 res = ast_play_and_wait(chan, "vm-msgsaved");
07397 }
07398 #ifndef IMAP_STORAGE
07399 else {
07400
07401 res = ast_play_and_wait(chan, "vm-mailboxfull");
07402 }
07403
07404 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07405 strcpy(textfile, msgfile);
07406 strcpy(backup, msgfile);
07407 strcpy(backup_textfile, msgfile);
07408 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07409 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07410 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07411 if (ast_fileexists(backup, NULL, NULL) > 0) {
07412 ast_filerename(backup, msgfile, NULL);
07413 rename(backup_textfile, textfile);
07414 }
07415 #endif
07416 }
07417 DISPOSE(dir, curmsg);
07418 #ifndef IMAP_STORAGE
07419 if (cmd) {
07420 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07421 strcpy(textfile, msgfile);
07422 strcpy(backup_textfile, msgfile);
07423 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07424 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07425 rename(backup_textfile, textfile);
07426 }
07427 #endif
07428 }
07429
07430
07431 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07432 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07433 free_user(vmtmp);
07434 }
07435 return res ? res : cmd;
07436 }
07437
07438 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07439 {
07440 int res;
07441 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07442 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07443 return res;
07444 }
07445
07446 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07447 {
07448 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07449 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);
07450 }
07451
07452 static int play_message_category(struct ast_channel *chan, const char *category)
07453 {
07454 int res = 0;
07455
07456 if (!ast_strlen_zero(category))
07457 res = ast_play_and_wait(chan, category);
07458
07459 if (res) {
07460 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07461 res = 0;
07462 }
07463
07464 return res;
07465 }
07466
07467 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07468 {
07469 int res = 0;
07470 struct vm_zone *the_zone = NULL;
07471 time_t t;
07472
07473 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07474 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07475 return 0;
07476 }
07477
07478
07479 if (!ast_strlen_zero(vmu->zonetag)) {
07480
07481 struct vm_zone *z;
07482 AST_LIST_LOCK(&zones);
07483 AST_LIST_TRAVERSE(&zones, z, list) {
07484 if (!strcmp(z->name, vmu->zonetag)) {
07485 the_zone = z;
07486 break;
07487 }
07488 }
07489 AST_LIST_UNLOCK(&zones);
07490 }
07491
07492
07493 #if 0
07494
07495 ast_localtime(&t, &time_now, NULL);
07496 tv_now = ast_tvnow();
07497 ast_localtime(&tv_now, &time_then, NULL);
07498
07499
07500 if (time_now.tm_year == time_then.tm_year)
07501 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07502 else
07503 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07504 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07505
07506
07507 #endif
07508 if (the_zone) {
07509 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07510 } else if (!strncasecmp(chan->language, "de", 2)) {
07511 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07512 } else if (!strncasecmp(chan->language, "gr", 2)) {
07513 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07514 } else if (!strncasecmp(chan->language, "it", 2)) {
07515 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);
07516 } else if (!strncasecmp(chan->language, "nl", 2)) {
07517 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07518 } else if (!strncasecmp(chan->language, "no", 2)) {
07519 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07520 } else if (!strncasecmp(chan->language, "pl", 2)) {
07521 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07522 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07523 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);
07524 } else if (!strncasecmp(chan->language, "se", 2)) {
07525 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07526 } else if (!strncasecmp(chan->language, "zh", 2)) {
07527 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07528 } else if (!strncasecmp(chan->language, "vi", 2)) {
07529 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);
07530 } else {
07531 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07532 }
07533 #if 0
07534 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07535 #endif
07536 return res;
07537 }
07538
07539
07540
07541 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07542 {
07543 int res = 0;
07544 int i;
07545 char *callerid, *name;
07546 char prefile[PATH_MAX] = "";
07547
07548
07549
07550
07551
07552
07553
07554
07555
07556 if ((cid == NULL)||(context == NULL))
07557 return res;
07558
07559
07560 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07561 ast_callerid_parse(cid, &name, &callerid);
07562 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07563
07564
07565 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07566 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07567 if ((strcmp(cidinternalcontexts[i], context) == 0))
07568 break;
07569 }
07570 if (i != MAX_NUM_CID_CONTEXTS){
07571 if (!res) {
07572 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07573 if (!ast_strlen_zero(prefile)) {
07574
07575 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07576 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07577 if (!callback)
07578 res = wait_file2(chan, vms, "vm-from");
07579 res = ast_stream_and_wait(chan, prefile, "");
07580 } else {
07581 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07582
07583 if (!callback)
07584 res = wait_file2(chan, vms, "vm-from-extension");
07585 res = ast_say_digit_str(chan, callerid, "", chan->language);
07586 }
07587 }
07588 }
07589 } else if (!res) {
07590 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07591
07592 if (!callback)
07593 res = wait_file2(chan, vms, "vm-from-phonenumber");
07594 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07595 }
07596 } else {
07597
07598 ast_debug(1, "VM-CID: From an unknown number\n");
07599
07600 res = wait_file2(chan, vms, "vm-unknown-caller");
07601 }
07602 return res;
07603 }
07604
07605 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07606 {
07607 int res = 0;
07608 int durationm;
07609 int durations;
07610
07611 if (duration == NULL)
07612 return res;
07613
07614
07615 durations = atoi(duration);
07616 durationm = (durations / 60);
07617
07618 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07619
07620 if ((!res) && (durationm >= minduration)) {
07621 res = wait_file2(chan, vms, "vm-duration");
07622
07623
07624 if (!strncasecmp(chan->language, "pl", 2)) {
07625 div_t num = div(durationm, 10);
07626
07627 if (durationm == 1) {
07628 res = ast_play_and_wait(chan, "digits/1z");
07629 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07630 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07631 if (num.rem == 2) {
07632 if (!num.quot) {
07633 res = ast_play_and_wait(chan, "digits/2-ie");
07634 } else {
07635 res = say_and_wait(chan, durationm - 2 , chan->language);
07636 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07637 }
07638 } else {
07639 res = say_and_wait(chan, durationm, chan->language);
07640 }
07641 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07642 } else {
07643 res = say_and_wait(chan, durationm, chan->language);
07644 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07645 }
07646
07647 } else {
07648 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07649 res = wait_file2(chan, vms, "vm-minutes");
07650 }
07651 }
07652 return res;
07653 }
07654
07655 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07656 {
07657 int res = 0;
07658 char filename[256], *cid;
07659 const char *origtime, *context, *category, *duration, *flag;
07660 struct ast_config *msg_cfg;
07661 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07662
07663 vms->starting = 0;
07664 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07665 adsi_message(chan, vms);
07666 if (!vms->curmsg) {
07667 res = wait_file2(chan, vms, "vm-first");
07668 } else if (vms->curmsg == vms->lastmsg) {
07669 res = wait_file2(chan, vms, "vm-last");
07670 }
07671
07672 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07673 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07674 msg_cfg = ast_config_load(filename, config_flags);
07675 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07676 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07677 return 0;
07678 }
07679 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07680
07681
07682 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07683 res = wait_file2(chan, vms, "vm-Urgent");
07684 }
07685
07686 if (!res) {
07687
07688
07689 if (!strncasecmp(chan->language, "pl", 2)) {
07690 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07691 int ten, one;
07692 char nextmsg[256];
07693 ten = (vms->curmsg + 1) / 10;
07694 one = (vms->curmsg + 1) % 10;
07695
07696 if (vms->curmsg < 20) {
07697 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07698 res = wait_file2(chan, vms, nextmsg);
07699 } else {
07700 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07701 res = wait_file2(chan, vms, nextmsg);
07702 if (one > 0) {
07703 if (!res) {
07704 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07705 res = wait_file2(chan, vms, nextmsg);
07706 }
07707 }
07708 }
07709 }
07710 if (!res)
07711 res = wait_file2(chan, vms, "vm-message");
07712
07713 } else if (!strncasecmp(chan->language, "he", 2)) {
07714 if (!vms->curmsg) {
07715 res = wait_file2(chan, vms, "vm-message");
07716 res = wait_file2(chan, vms, "vm-first");
07717 } else if (vms->curmsg == vms->lastmsg) {
07718 res = wait_file2(chan, vms, "vm-message");
07719 res = wait_file2(chan, vms, "vm-last");
07720 } else {
07721 res = wait_file2(chan, vms, "vm-message");
07722 res = wait_file2(chan, vms, "vm-number");
07723 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07724 }
07725
07726 } else if (!strncasecmp(chan->language, "vi", 2)) {
07727 if (!vms->curmsg) {
07728 res = wait_file2(chan, vms, "vm-message");
07729 res = wait_file2(chan, vms, "vm-first");
07730 } else if (vms->curmsg == vms->lastmsg) {
07731 res = wait_file2(chan, vms, "vm-message");
07732 res = wait_file2(chan, vms, "vm-last");
07733 } else {
07734 res = wait_file2(chan, vms, "vm-message");
07735 res = wait_file2(chan, vms, "vm-number");
07736 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07737 }
07738 } else {
07739 if (!strncasecmp(chan->language, "se", 2)) {
07740 res = wait_file2(chan, vms, "vm-meddelandet");
07741 } else {
07742 res = wait_file2(chan, vms, "vm-message");
07743 }
07744 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07745 if (!res) {
07746 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07747 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07748 }
07749 }
07750 }
07751 }
07752
07753 if (!msg_cfg) {
07754 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07755 return 0;
07756 }
07757
07758 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07759 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07760 DISPOSE(vms->curdir, vms->curmsg);
07761 ast_config_destroy(msg_cfg);
07762 return 0;
07763 }
07764
07765 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07766 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07767 category = ast_variable_retrieve(msg_cfg, "message", "category");
07768
07769 context = ast_variable_retrieve(msg_cfg, "message", "context");
07770 if (!strncasecmp("macro", context, 5))
07771 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07772 if (!res) {
07773 res = play_message_category(chan, category);
07774 }
07775 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07776 res = play_message_datetime(chan, vmu, origtime, filename);
07777 }
07778 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07779 res = play_message_callerid(chan, vms, cid, context, 0);
07780 }
07781 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07782 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07783 }
07784
07785 if (res == '1') {
07786 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07787 res = 0;
07788 }
07789 ast_config_destroy(msg_cfg);
07790
07791 if (!res) {
07792 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07793 vms->heard[vms->curmsg] = 1;
07794 #ifdef IMAP_STORAGE
07795
07796
07797
07798 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07799 wait_file(chan, vms, vms->introfn);
07800 }
07801 #endif
07802 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07803 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07804 res = 0;
07805 }
07806 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07807 }
07808 DISPOSE(vms->curdir, vms->curmsg);
07809 return res;
07810 }
07811
07812 #ifdef IMAP_STORAGE
07813 static int imap_remove_file(char *dir, int msgnum)
07814 {
07815 char fn[PATH_MAX];
07816 char full_fn[PATH_MAX];
07817 char intro[PATH_MAX] = {0,};
07818
07819 if (msgnum > -1) {
07820 make_file(fn, sizeof(fn), dir, msgnum);
07821 snprintf(intro, sizeof(intro), "%sintro", fn);
07822 } else
07823 ast_copy_string(fn, dir, sizeof(fn));
07824
07825 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07826 ast_filedelete(fn, NULL);
07827 if (!ast_strlen_zero(intro)) {
07828 ast_filedelete(intro, NULL);
07829 }
07830 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07831 unlink(full_fn);
07832 }
07833 return 0;
07834 }
07835
07836
07837
07838 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07839 {
07840 char *file, *filename;
07841 char *attachment;
07842 char arg[10];
07843 int i;
07844 BODY* body;
07845
07846 file = strrchr(ast_strdupa(dir), '/');
07847 if (file) {
07848 *file++ = '\0';
07849 } else {
07850 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07851 return -1;
07852 }
07853
07854 ast_mutex_lock(&vms->lock);
07855 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07856 mail_fetchstructure(vms->mailstream, i + 1, &body);
07857
07858 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07859 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07860 } else {
07861 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07862 ast_mutex_unlock(&vms->lock);
07863 return -1;
07864 }
07865 filename = strsep(&attachment, ".");
07866 if (!strcmp(filename, file)) {
07867 sprintf(arg, "%d", i + 1);
07868 mail_setflag(vms->mailstream, arg, "\\DELETED");
07869 }
07870 }
07871 mail_expunge(vms->mailstream);
07872 ast_mutex_unlock(&vms->lock);
07873 return 0;
07874 }
07875
07876 #elif !defined(IMAP_STORAGE)
07877 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07878 {
07879 int count_msg, last_msg;
07880
07881 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07882
07883
07884
07885
07886 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07887
07888
07889 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07890
07891
07892 count_msg = count_messages(vmu, vms->curdir);
07893 if (count_msg < 0) {
07894 return count_msg;
07895 } else {
07896 vms->lastmsg = count_msg - 1;
07897 }
07898
07899 if (vm_allocate_dh(vms, vmu, count_msg)) {
07900 return -1;
07901 }
07902
07903
07904
07905
07906
07907
07908
07909
07910 if (vm_lock_path(vms->curdir)) {
07911 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07912 return ERROR_LOCK_PATH;
07913 }
07914
07915
07916 last_msg = last_message_index(vmu, vms->curdir);
07917 ast_unlock_path(vms->curdir);
07918
07919 if (last_msg < -1) {
07920 return last_msg;
07921 } else if (vms->lastmsg != last_msg) {
07922 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);
07923 resequence_mailbox(vmu, vms->curdir, count_msg);
07924 }
07925
07926 return 0;
07927 }
07928 #endif
07929
07930 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07931 {
07932 int x = 0;
07933
07934 #ifndef IMAP_STORAGE
07935 int last_msg_idx;
07936 int res = 0, nummsg;
07937 char fn2[PATH_MAX];
07938 #endif
07939
07940 if (vms->lastmsg <= -1) {
07941 goto done;
07942 }
07943
07944 vms->curmsg = -1;
07945 #ifndef IMAP_STORAGE
07946
07947 if (vm_lock_path(vms->curdir)) {
07948 return ERROR_LOCK_PATH;
07949 }
07950
07951
07952 last_msg_idx = last_message_index(vmu, vms->curdir);
07953 if (last_msg_idx != vms->lastmsg) {
07954 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07955 }
07956
07957
07958 for (x = 0; x < last_msg_idx + 1; x++) {
07959 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07960
07961 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07962 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07963 break;
07964 }
07965 vms->curmsg++;
07966 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07967 if (strcmp(vms->fn, fn2)) {
07968 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07969 }
07970 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07971
07972 res = save_to_folder(vmu, vms, x, 1);
07973 if (res == ERROR_LOCK_PATH) {
07974
07975 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07976 vms->deleted[x] = 0;
07977 vms->heard[x] = 0;
07978 --x;
07979 }
07980 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07981
07982 res = save_to_folder(vmu, vms, x, 10);
07983 if (res == ERROR_LOCK_PATH) {
07984
07985 vms->deleted[x] = 0;
07986 vms->heard[x] = 0;
07987 --x;
07988 }
07989 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07990
07991
07992 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07993 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07994 DELETE(vms->curdir, x, vms->fn, vmu);
07995 }
07996 }
07997 }
07998
07999
08000 nummsg = x - 1;
08001 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08002 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08003 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08004 DELETE(vms->curdir, x, vms->fn, vmu);
08005 }
08006 }
08007 ast_unlock_path(vms->curdir);
08008 #else
08009 if (vms->deleted) {
08010
08011
08012 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
08013 if (vms->deleted[x]) {
08014 ast_debug(3, "IMAP delete of %d\n", x);
08015 DELETE(vms->curdir, x, vms->fn, vmu);
08016 }
08017 }
08018 }
08019 #endif
08020
08021 done:
08022 if (vms->deleted && vmu->maxmsg) {
08023 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
08024 }
08025 if (vms->heard && vmu->maxmsg) {
08026 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
08027 }
08028
08029 return 0;
08030 }
08031
08032
08033
08034
08035
08036
08037
08038 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08039 {
08040 int cmd;
08041 char *buf;
08042
08043 buf = alloca(strlen(box) + 2);
08044 strcpy(buf, box);
08045 strcat(buf, "s");
08046
08047 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08048 cmd = ast_play_and_wait(chan, buf);
08049 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08050 } else {
08051 cmd = ast_play_and_wait(chan, "vm-messages");
08052 return cmd ? cmd : ast_play_and_wait(chan, box);
08053 }
08054 }
08055
08056 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08057 {
08058 int cmd;
08059
08060 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08061 if (!strcasecmp(box, "vm-INBOX"))
08062 cmd = ast_play_and_wait(chan, "vm-new-e");
08063 else
08064 cmd = ast_play_and_wait(chan, "vm-old-e");
08065 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08066 } else {
08067 cmd = ast_play_and_wait(chan, "vm-messages");
08068 return cmd ? cmd : ast_play_and_wait(chan, box);
08069 }
08070 }
08071
08072 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08073 {
08074 int cmd;
08075
08076 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08077 cmd = ast_play_and_wait(chan, "vm-messages");
08078 return cmd ? cmd : ast_play_and_wait(chan, box);
08079 } else {
08080 cmd = ast_play_and_wait(chan, box);
08081 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08082 }
08083 }
08084
08085 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08086 {
08087 int cmd;
08088
08089 if ( !strncasecmp(chan->language, "it", 2) ||
08090 !strncasecmp(chan->language, "es", 2) ||
08091 !strncasecmp(chan->language, "pt", 2)) {
08092 cmd = ast_play_and_wait(chan, "vm-messages");
08093 return cmd ? cmd : ast_play_and_wait(chan, box);
08094 } else if (!strncasecmp(chan->language, "gr", 2)) {
08095 return vm_play_folder_name_gr(chan, box);
08096 } else if (!strncasecmp(chan->language, "he", 2)) {
08097 return ast_play_and_wait(chan, box);
08098 } else if (!strncasecmp(chan->language, "pl", 2)) {
08099 return vm_play_folder_name_pl(chan, box);
08100 } else if (!strncasecmp(chan->language, "ua", 2)) {
08101 return vm_play_folder_name_ua(chan, box);
08102 } else if (!strncasecmp(chan->language, "vi", 2)) {
08103 return ast_play_and_wait(chan, box);
08104 } else {
08105 cmd = ast_play_and_wait(chan, box);
08106 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08107 }
08108 }
08109
08110
08111
08112
08113
08114
08115
08116
08117
08118
08119
08120
08121
08122 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08123 {
08124 int res = 0;
08125
08126 if (vms->newmessages) {
08127 res = ast_play_and_wait(chan, "vm-youhave");
08128 if (!res)
08129 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08130 if (!res) {
08131 if ((vms->newmessages == 1)) {
08132 res = ast_play_and_wait(chan, "vm-INBOX");
08133 if (!res)
08134 res = ast_play_and_wait(chan, "vm-message");
08135 } else {
08136 res = ast_play_and_wait(chan, "vm-INBOXs");
08137 if (!res)
08138 res = ast_play_and_wait(chan, "vm-messages");
08139 }
08140 }
08141 } else if (vms->oldmessages){
08142 res = ast_play_and_wait(chan, "vm-youhave");
08143 if (!res)
08144 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08145 if ((vms->oldmessages == 1)){
08146 res = ast_play_and_wait(chan, "vm-Old");
08147 if (!res)
08148 res = ast_play_and_wait(chan, "vm-message");
08149 } else {
08150 res = ast_play_and_wait(chan, "vm-Olds");
08151 if (!res)
08152 res = ast_play_and_wait(chan, "vm-messages");
08153 }
08154 } else if (!vms->oldmessages && !vms->newmessages)
08155 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08156 return res;
08157 }
08158
08159
08160
08161
08162
08163
08164
08165
08166
08167
08168
08169
08170
08171
08172
08173
08174
08175
08176
08177
08178
08179
08180
08181
08182
08183
08184
08185
08186
08187
08188
08189
08190
08191
08192
08193
08194
08195
08196
08197
08198
08199
08200
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212
08213
08214
08215
08216 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08217 {
08218 int res;
08219 int lastnum = 0;
08220
08221 res = ast_play_and_wait(chan, "vm-youhave");
08222
08223 if (!res && vms->newmessages) {
08224 lastnum = vms->newmessages;
08225
08226 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08227 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08228 }
08229
08230 if (!res && vms->oldmessages) {
08231 res = ast_play_and_wait(chan, "vm-and");
08232 }
08233 }
08234
08235 if (!res && vms->oldmessages) {
08236 lastnum = vms->oldmessages;
08237
08238 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08239 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08240 }
08241 }
08242
08243 if (!res) {
08244 if (lastnum == 0) {
08245 res = ast_play_and_wait(chan, "vm-no");
08246 }
08247 if (!res) {
08248 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08249 }
08250 }
08251
08252 return res;
08253 }
08254
08255
08256 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08257 {
08258 int res = 0;
08259
08260
08261 if (!res) {
08262 if ((vms->newmessages) || (vms->oldmessages)) {
08263 res = ast_play_and_wait(chan, "vm-youhave");
08264 }
08265
08266
08267
08268
08269
08270 if (vms->newmessages) {
08271 if (!res) {
08272 if (vms->newmessages == 1) {
08273 res = ast_play_and_wait(chan, "vm-INBOX1");
08274 } else {
08275 if (vms->newmessages == 2) {
08276 res = ast_play_and_wait(chan, "vm-shtei");
08277 } else {
08278 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08279 }
08280 res = ast_play_and_wait(chan, "vm-INBOX");
08281 }
08282 }
08283 if (vms->oldmessages && !res) {
08284 res = ast_play_and_wait(chan, "vm-and");
08285 if (vms->oldmessages == 1) {
08286 res = ast_play_and_wait(chan, "vm-Old1");
08287 } else {
08288 if (vms->oldmessages == 2) {
08289 res = ast_play_and_wait(chan, "vm-shtei");
08290 } else {
08291 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08292 }
08293 res = ast_play_and_wait(chan, "vm-Old");
08294 }
08295 }
08296 }
08297 if (!res && vms->oldmessages && !vms->newmessages) {
08298 if (!res) {
08299 if (vms->oldmessages == 1) {
08300 res = ast_play_and_wait(chan, "vm-Old1");
08301 } else {
08302 if (vms->oldmessages == 2) {
08303 res = ast_play_and_wait(chan, "vm-shtei");
08304 } else {
08305 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08306 }
08307 res = ast_play_and_wait(chan, "vm-Old");
08308 }
08309 }
08310 }
08311 if (!res) {
08312 if (!vms->oldmessages && !vms->newmessages) {
08313 if (!res) {
08314 res = ast_play_and_wait(chan, "vm-nomessages");
08315 }
08316 }
08317 }
08318 }
08319 return res;
08320 }
08321
08322
08323 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08324 {
08325 int res;
08326
08327
08328 res = ast_play_and_wait(chan, "vm-youhave");
08329 if (!res) {
08330 if (vms->urgentmessages) {
08331 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08332 if (!res)
08333 res = ast_play_and_wait(chan, "vm-Urgent");
08334 if ((vms->oldmessages || vms->newmessages) && !res) {
08335 res = ast_play_and_wait(chan, "vm-and");
08336 } else if (!res) {
08337 if ((vms->urgentmessages == 1))
08338 res = ast_play_and_wait(chan, "vm-message");
08339 else
08340 res = ast_play_and_wait(chan, "vm-messages");
08341 }
08342 }
08343 if (vms->newmessages) {
08344 res = say_and_wait(chan, vms->newmessages, chan->language);
08345 if (!res)
08346 res = ast_play_and_wait(chan, "vm-INBOX");
08347 if (vms->oldmessages && !res)
08348 res = ast_play_and_wait(chan, "vm-and");
08349 else if (!res) {
08350 if ((vms->newmessages == 1))
08351 res = ast_play_and_wait(chan, "vm-message");
08352 else
08353 res = ast_play_and_wait(chan, "vm-messages");
08354 }
08355
08356 }
08357 if (!res && vms->oldmessages) {
08358 res = say_and_wait(chan, vms->oldmessages, chan->language);
08359 if (!res)
08360 res = ast_play_and_wait(chan, "vm-Old");
08361 if (!res) {
08362 if (vms->oldmessages == 1)
08363 res = ast_play_and_wait(chan, "vm-message");
08364 else
08365 res = ast_play_and_wait(chan, "vm-messages");
08366 }
08367 }
08368 if (!res) {
08369 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08370 res = ast_play_and_wait(chan, "vm-no");
08371 if (!res)
08372 res = ast_play_and_wait(chan, "vm-messages");
08373 }
08374 }
08375 }
08376 return res;
08377 }
08378
08379
08380 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08381 {
08382
08383 int res;
08384 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08385 res = ast_play_and_wait(chan, "vm-no") ||
08386 ast_play_and_wait(chan, "vm-message");
08387 else
08388 res = ast_play_and_wait(chan, "vm-youhave");
08389 if (!res && vms->newmessages) {
08390 res = (vms->newmessages == 1) ?
08391 ast_play_and_wait(chan, "digits/un") ||
08392 ast_play_and_wait(chan, "vm-nuovo") ||
08393 ast_play_and_wait(chan, "vm-message") :
08394
08395 say_and_wait(chan, vms->newmessages, chan->language) ||
08396 ast_play_and_wait(chan, "vm-nuovi") ||
08397 ast_play_and_wait(chan, "vm-messages");
08398 if (!res && vms->oldmessages)
08399 res = ast_play_and_wait(chan, "vm-and");
08400 }
08401 if (!res && vms->oldmessages) {
08402 res = (vms->oldmessages == 1) ?
08403 ast_play_and_wait(chan, "digits/un") ||
08404 ast_play_and_wait(chan, "vm-vecchio") ||
08405 ast_play_and_wait(chan, "vm-message") :
08406
08407 say_and_wait(chan, vms->oldmessages, chan->language) ||
08408 ast_play_and_wait(chan, "vm-vecchi") ||
08409 ast_play_and_wait(chan, "vm-messages");
08410 }
08411 return res;
08412 }
08413
08414
08415 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08416 {
08417
08418 int res;
08419 div_t num;
08420
08421 if (!vms->oldmessages && !vms->newmessages) {
08422 res = ast_play_and_wait(chan, "vm-no");
08423 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08424 return res;
08425 } else {
08426 res = ast_play_and_wait(chan, "vm-youhave");
08427 }
08428
08429 if (vms->newmessages) {
08430 num = div(vms->newmessages, 10);
08431 if (vms->newmessages == 1) {
08432 res = ast_play_and_wait(chan, "digits/1-a");
08433 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08434 res = res ? res : ast_play_and_wait(chan, "vm-message");
08435 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08436 if (num.rem == 2) {
08437 if (!num.quot) {
08438 res = ast_play_and_wait(chan, "digits/2-ie");
08439 } else {
08440 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08441 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08442 }
08443 } else {
08444 res = say_and_wait(chan, vms->newmessages, chan->language);
08445 }
08446 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08447 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08448 } else {
08449 res = say_and_wait(chan, vms->newmessages, chan->language);
08450 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08451 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08452 }
08453 if (!res && vms->oldmessages)
08454 res = ast_play_and_wait(chan, "vm-and");
08455 }
08456 if (!res && vms->oldmessages) {
08457 num = div(vms->oldmessages, 10);
08458 if (vms->oldmessages == 1) {
08459 res = ast_play_and_wait(chan, "digits/1-a");
08460 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08461 res = res ? res : ast_play_and_wait(chan, "vm-message");
08462 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08463 if (num.rem == 2) {
08464 if (!num.quot) {
08465 res = ast_play_and_wait(chan, "digits/2-ie");
08466 } else {
08467 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08468 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08469 }
08470 } else {
08471 res = say_and_wait(chan, vms->oldmessages, chan->language);
08472 }
08473 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08474 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08475 } else {
08476 res = say_and_wait(chan, vms->oldmessages, chan->language);
08477 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08478 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08479 }
08480 }
08481
08482 return res;
08483 }
08484
08485
08486 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08487 {
08488
08489 int res;
08490
08491 res = ast_play_and_wait(chan, "vm-youhave");
08492 if (res)
08493 return res;
08494
08495 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08496 res = ast_play_and_wait(chan, "vm-no");
08497 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08498 return res;
08499 }
08500
08501 if (vms->newmessages) {
08502 if ((vms->newmessages == 1)) {
08503 res = ast_play_and_wait(chan, "digits/ett");
08504 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08505 res = res ? res : ast_play_and_wait(chan, "vm-message");
08506 } else {
08507 res = say_and_wait(chan, vms->newmessages, chan->language);
08508 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08509 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08510 }
08511 if (!res && vms->oldmessages)
08512 res = ast_play_and_wait(chan, "vm-and");
08513 }
08514 if (!res && vms->oldmessages) {
08515 if (vms->oldmessages == 1) {
08516 res = ast_play_and_wait(chan, "digits/ett");
08517 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08518 res = res ? res : ast_play_and_wait(chan, "vm-message");
08519 } else {
08520 res = say_and_wait(chan, vms->oldmessages, chan->language);
08521 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08522 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08523 }
08524 }
08525
08526 return res;
08527 }
08528
08529
08530 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08531 {
08532
08533 int res;
08534
08535 res = ast_play_and_wait(chan, "vm-youhave");
08536 if (res)
08537 return res;
08538
08539 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08540 res = ast_play_and_wait(chan, "vm-no");
08541 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08542 return res;
08543 }
08544
08545 if (vms->newmessages) {
08546 if ((vms->newmessages == 1)) {
08547 res = ast_play_and_wait(chan, "digits/1");
08548 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08549 res = res ? res : ast_play_and_wait(chan, "vm-message");
08550 } else {
08551 res = say_and_wait(chan, vms->newmessages, chan->language);
08552 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08553 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08554 }
08555 if (!res && vms->oldmessages)
08556 res = ast_play_and_wait(chan, "vm-and");
08557 }
08558 if (!res && vms->oldmessages) {
08559 if (vms->oldmessages == 1) {
08560 res = ast_play_and_wait(chan, "digits/1");
08561 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08562 res = res ? res : ast_play_and_wait(chan, "vm-message");
08563 } else {
08564 res = say_and_wait(chan, vms->oldmessages, chan->language);
08565 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08566 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08567 }
08568 }
08569
08570 return res;
08571 }
08572
08573
08574 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08575 {
08576
08577 int res;
08578 res = ast_play_and_wait(chan, "vm-youhave");
08579 if (!res) {
08580 if (vms->newmessages) {
08581 if ((vms->newmessages == 1))
08582 res = ast_play_and_wait(chan, "digits/1F");
08583 else
08584 res = say_and_wait(chan, vms->newmessages, chan->language);
08585 if (!res)
08586 res = ast_play_and_wait(chan, "vm-INBOX");
08587 if (vms->oldmessages && !res)
08588 res = ast_play_and_wait(chan, "vm-and");
08589 else if (!res) {
08590 if ((vms->newmessages == 1))
08591 res = ast_play_and_wait(chan, "vm-message");
08592 else
08593 res = ast_play_and_wait(chan, "vm-messages");
08594 }
08595
08596 }
08597 if (!res && vms->oldmessages) {
08598 if (vms->oldmessages == 1)
08599 res = ast_play_and_wait(chan, "digits/1F");
08600 else
08601 res = say_and_wait(chan, vms->oldmessages, chan->language);
08602 if (!res)
08603 res = ast_play_and_wait(chan, "vm-Old");
08604 if (!res) {
08605 if (vms->oldmessages == 1)
08606 res = ast_play_and_wait(chan, "vm-message");
08607 else
08608 res = ast_play_and_wait(chan, "vm-messages");
08609 }
08610 }
08611 if (!res) {
08612 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08613 res = ast_play_and_wait(chan, "vm-no");
08614 if (!res)
08615 res = ast_play_and_wait(chan, "vm-messages");
08616 }
08617 }
08618 }
08619 return res;
08620 }
08621
08622
08623 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08624 {
08625
08626 int res;
08627 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08628 res = ast_play_and_wait(chan, "vm-youhaveno");
08629 if (!res)
08630 res = ast_play_and_wait(chan, "vm-messages");
08631 } else {
08632 res = ast_play_and_wait(chan, "vm-youhave");
08633 }
08634 if (!res) {
08635 if (vms->newmessages) {
08636 if (!res) {
08637 if ((vms->newmessages == 1)) {
08638 res = ast_play_and_wait(chan, "digits/1M");
08639 if (!res)
08640 res = ast_play_and_wait(chan, "vm-message");
08641 if (!res)
08642 res = ast_play_and_wait(chan, "vm-INBOXs");
08643 } else {
08644 res = say_and_wait(chan, vms->newmessages, chan->language);
08645 if (!res)
08646 res = ast_play_and_wait(chan, "vm-messages");
08647 if (!res)
08648 res = ast_play_and_wait(chan, "vm-INBOX");
08649 }
08650 }
08651 if (vms->oldmessages && !res)
08652 res = ast_play_and_wait(chan, "vm-and");
08653 }
08654 if (vms->oldmessages) {
08655 if (!res) {
08656 if (vms->oldmessages == 1) {
08657 res = ast_play_and_wait(chan, "digits/1M");
08658 if (!res)
08659 res = ast_play_and_wait(chan, "vm-message");
08660 if (!res)
08661 res = ast_play_and_wait(chan, "vm-Olds");
08662 } else {
08663 res = say_and_wait(chan, vms->oldmessages, chan->language);
08664 if (!res)
08665 res = ast_play_and_wait(chan, "vm-messages");
08666 if (!res)
08667 res = ast_play_and_wait(chan, "vm-Old");
08668 }
08669 }
08670 }
08671 }
08672 return res;
08673 }
08674
08675
08676 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08677
08678 int res;
08679 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08680 res = ast_play_and_wait(chan, "vm-nomessages");
08681 return res;
08682 } else {
08683 res = ast_play_and_wait(chan, "vm-youhave");
08684 }
08685 if (vms->newmessages) {
08686 if (!res)
08687 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08688 if ((vms->newmessages == 1)) {
08689 if (!res)
08690 res = ast_play_and_wait(chan, "vm-message");
08691 if (!res)
08692 res = ast_play_and_wait(chan, "vm-INBOXs");
08693 } else {
08694 if (!res)
08695 res = ast_play_and_wait(chan, "vm-messages");
08696 if (!res)
08697 res = ast_play_and_wait(chan, "vm-INBOX");
08698 }
08699 if (vms->oldmessages && !res)
08700 res = ast_play_and_wait(chan, "vm-and");
08701 }
08702 if (vms->oldmessages) {
08703 if (!res)
08704 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08705 if (vms->oldmessages == 1) {
08706 if (!res)
08707 res = ast_play_and_wait(chan, "vm-message");
08708 if (!res)
08709 res = ast_play_and_wait(chan, "vm-Olds");
08710 } else {
08711 if (!res)
08712 res = ast_play_and_wait(chan, "vm-messages");
08713 if (!res)
08714 res = ast_play_and_wait(chan, "vm-Old");
08715 }
08716 }
08717 return res;
08718 }
08719
08720
08721 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08722 {
08723
08724 int res;
08725 res = ast_play_and_wait(chan, "vm-youhave");
08726 if (!res) {
08727 if (vms->newmessages) {
08728 res = say_and_wait(chan, vms->newmessages, chan->language);
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-INBOX");
08731 if (vms->oldmessages && !res)
08732 res = ast_play_and_wait(chan, "vm-and");
08733 else if (!res) {
08734 if ((vms->newmessages == 1))
08735 res = ast_play_and_wait(chan, "vm-message");
08736 else
08737 res = ast_play_and_wait(chan, "vm-messages");
08738 }
08739
08740 }
08741 if (!res && vms->oldmessages) {
08742 res = say_and_wait(chan, vms->oldmessages, chan->language);
08743 if (!res)
08744 res = ast_play_and_wait(chan, "vm-Old");
08745 if (!res) {
08746 if (vms->oldmessages == 1)
08747 res = ast_play_and_wait(chan, "vm-message");
08748 else
08749 res = ast_play_and_wait(chan, "vm-messages");
08750 }
08751 }
08752 if (!res) {
08753 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08754 res = ast_play_and_wait(chan, "vm-no");
08755 if (!res)
08756 res = ast_play_and_wait(chan, "vm-messages");
08757 }
08758 }
08759 }
08760 return res;
08761 }
08762
08763
08764 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08765 {
08766
08767 int res;
08768 res = ast_play_and_wait(chan, "vm-youhave");
08769 if (!res) {
08770 if (vms->newmessages) {
08771 res = say_and_wait(chan, vms->newmessages, chan->language);
08772 if (!res) {
08773 if (vms->newmessages == 1)
08774 res = ast_play_and_wait(chan, "vm-INBOXs");
08775 else
08776 res = ast_play_and_wait(chan, "vm-INBOX");
08777 }
08778 if (vms->oldmessages && !res)
08779 res = ast_play_and_wait(chan, "vm-and");
08780 else if (!res) {
08781 if ((vms->newmessages == 1))
08782 res = ast_play_and_wait(chan, "vm-message");
08783 else
08784 res = ast_play_and_wait(chan, "vm-messages");
08785 }
08786
08787 }
08788 if (!res && vms->oldmessages) {
08789 res = say_and_wait(chan, vms->oldmessages, chan->language);
08790 if (!res) {
08791 if (vms->oldmessages == 1)
08792 res = ast_play_and_wait(chan, "vm-Olds");
08793 else
08794 res = ast_play_and_wait(chan, "vm-Old");
08795 }
08796 if (!res) {
08797 if (vms->oldmessages == 1)
08798 res = ast_play_and_wait(chan, "vm-message");
08799 else
08800 res = ast_play_and_wait(chan, "vm-messages");
08801 }
08802 }
08803 if (!res) {
08804 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08805 res = ast_play_and_wait(chan, "vm-no");
08806 if (!res)
08807 res = ast_play_and_wait(chan, "vm-messages");
08808 }
08809 }
08810 }
08811 return res;
08812 }
08813
08814
08815 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08816 {
08817
08818 int res;
08819 res = ast_play_and_wait(chan, "vm-youhave");
08820 if (!res) {
08821 if (vms->newmessages) {
08822 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08823 if (!res) {
08824 if ((vms->newmessages == 1)) {
08825 res = ast_play_and_wait(chan, "vm-message");
08826 if (!res)
08827 res = ast_play_and_wait(chan, "vm-INBOXs");
08828 } else {
08829 res = ast_play_and_wait(chan, "vm-messages");
08830 if (!res)
08831 res = ast_play_and_wait(chan, "vm-INBOX");
08832 }
08833 }
08834 if (vms->oldmessages && !res)
08835 res = ast_play_and_wait(chan, "vm-and");
08836 }
08837 if (!res && vms->oldmessages) {
08838 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08839 if (!res) {
08840 if (vms->oldmessages == 1) {
08841 res = ast_play_and_wait(chan, "vm-message");
08842 if (!res)
08843 res = ast_play_and_wait(chan, "vm-Olds");
08844 } else {
08845 res = ast_play_and_wait(chan, "vm-messages");
08846 if (!res)
08847 res = ast_play_and_wait(chan, "vm-Old");
08848 }
08849 }
08850 }
08851 if (!res) {
08852 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08853 res = ast_play_and_wait(chan, "vm-no");
08854 if (!res)
08855 res = ast_play_and_wait(chan, "vm-messages");
08856 }
08857 }
08858 }
08859 return res;
08860 }
08861
08862
08863
08864
08865
08866
08867
08868
08869
08870
08871
08872
08873
08874
08875
08876
08877
08878 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08879 {
08880 int res;
08881 res = ast_play_and_wait(chan, "vm-youhave");
08882 if (!res) {
08883 if (vms->newmessages) {
08884 if (vms->newmessages == 1) {
08885 res = ast_play_and_wait(chan, "digits/jednu");
08886 } else {
08887 res = say_and_wait(chan, vms->newmessages, chan->language);
08888 }
08889 if (!res) {
08890 if ((vms->newmessages == 1))
08891 res = ast_play_and_wait(chan, "vm-novou");
08892 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08893 res = ast_play_and_wait(chan, "vm-nove");
08894 if (vms->newmessages > 4)
08895 res = ast_play_and_wait(chan, "vm-novych");
08896 }
08897 if (vms->oldmessages && !res)
08898 res = ast_play_and_wait(chan, "vm-and");
08899 else if (!res) {
08900 if ((vms->newmessages == 1))
08901 res = ast_play_and_wait(chan, "vm-zpravu");
08902 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08903 res = ast_play_and_wait(chan, "vm-zpravy");
08904 if (vms->newmessages > 4)
08905 res = ast_play_and_wait(chan, "vm-zprav");
08906 }
08907 }
08908 if (!res && vms->oldmessages) {
08909 res = say_and_wait(chan, vms->oldmessages, chan->language);
08910 if (!res) {
08911 if ((vms->oldmessages == 1))
08912 res = ast_play_and_wait(chan, "vm-starou");
08913 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08914 res = ast_play_and_wait(chan, "vm-stare");
08915 if (vms->oldmessages > 4)
08916 res = ast_play_and_wait(chan, "vm-starych");
08917 }
08918 if (!res) {
08919 if ((vms->oldmessages == 1))
08920 res = ast_play_and_wait(chan, "vm-zpravu");
08921 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08922 res = ast_play_and_wait(chan, "vm-zpravy");
08923 if (vms->oldmessages > 4)
08924 res = ast_play_and_wait(chan, "vm-zprav");
08925 }
08926 }
08927 if (!res) {
08928 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08929 res = ast_play_and_wait(chan, "vm-no");
08930 if (!res)
08931 res = ast_play_and_wait(chan, "vm-zpravy");
08932 }
08933 }
08934 }
08935 return res;
08936 }
08937
08938
08939 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08940 {
08941 int res;
08942
08943 res = ast_play_and_wait(chan, "vm-you");
08944
08945 if (!res && vms->newmessages) {
08946 res = ast_play_and_wait(chan, "vm-have");
08947 if (!res)
08948 res = say_and_wait(chan, vms->newmessages, chan->language);
08949 if (!res)
08950 res = ast_play_and_wait(chan, "vm-tong");
08951 if (!res)
08952 res = ast_play_and_wait(chan, "vm-INBOX");
08953 if (vms->oldmessages && !res)
08954 res = ast_play_and_wait(chan, "vm-and");
08955 else if (!res)
08956 res = ast_play_and_wait(chan, "vm-messages");
08957 }
08958 if (!res && vms->oldmessages) {
08959 res = ast_play_and_wait(chan, "vm-have");
08960 if (!res)
08961 res = say_and_wait(chan, vms->oldmessages, chan->language);
08962 if (!res)
08963 res = ast_play_and_wait(chan, "vm-tong");
08964 if (!res)
08965 res = ast_play_and_wait(chan, "vm-Old");
08966 if (!res)
08967 res = ast_play_and_wait(chan, "vm-messages");
08968 }
08969 if (!res && !vms->oldmessages && !vms->newmessages) {
08970 res = ast_play_and_wait(chan, "vm-haveno");
08971 if (!res)
08972 res = ast_play_and_wait(chan, "vm-messages");
08973 }
08974 return res;
08975 }
08976
08977
08978 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08979 {
08980 int res;
08981
08982
08983 res = ast_play_and_wait(chan, "vm-youhave");
08984 if (!res) {
08985 if (vms->newmessages) {
08986 res = say_and_wait(chan, vms->newmessages, chan->language);
08987 if (!res)
08988 res = ast_play_and_wait(chan, "vm-INBOX");
08989 if (vms->oldmessages && !res)
08990 res = ast_play_and_wait(chan, "vm-and");
08991 }
08992 if (!res && vms->oldmessages) {
08993 res = say_and_wait(chan, vms->oldmessages, chan->language);
08994 if (!res)
08995 res = ast_play_and_wait(chan, "vm-Old");
08996 }
08997 if (!res) {
08998 if (!vms->oldmessages && !vms->newmessages) {
08999 res = ast_play_and_wait(chan, "vm-no");
09000 if (!res)
09001 res = ast_play_and_wait(chan, "vm-message");
09002 }
09003 }
09004 }
09005 return res;
09006 }
09007
09008 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09009 {
09010 char prefile[256];
09011
09012
09013 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09014 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09015 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09016 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09017 ast_play_and_wait(chan, "vm-tempgreetactive");
09018 }
09019 DISPOSE(prefile, -1);
09020 }
09021
09022
09023 if (0) {
09024 return 0;
09025 } else if (!strncasecmp(chan->language, "cs", 2)) {
09026 return vm_intro_cs(chan, vms);
09027 } else if (!strncasecmp(chan->language, "cz", 2)) {
09028 static int deprecation_warning = 0;
09029 if (deprecation_warning++ % 10 == 0) {
09030 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09031 }
09032 return vm_intro_cs(chan, vms);
09033 } else if (!strncasecmp(chan->language, "de", 2)) {
09034 return vm_intro_de(chan, vms);
09035 } else if (!strncasecmp(chan->language, "es", 2)) {
09036 return vm_intro_es(chan, vms);
09037 } else if (!strncasecmp(chan->language, "fr", 2)) {
09038 return vm_intro_fr(chan, vms);
09039 } else if (!strncasecmp(chan->language, "gr", 2)) {
09040 return vm_intro_gr(chan, vms);
09041 } else if (!strncasecmp(chan->language, "he", 2)) {
09042 return vm_intro_he(chan, vms);
09043 } else if (!strncasecmp(chan->language, "it", 2)) {
09044 return vm_intro_it(chan, vms);
09045 } else if (!strncasecmp(chan->language, "nl", 2)) {
09046 return vm_intro_nl(chan, vms);
09047 } else if (!strncasecmp(chan->language, "no", 2)) {
09048 return vm_intro_no(chan, vms);
09049 } else if (!strncasecmp(chan->language, "pl", 2)) {
09050 return vm_intro_pl(chan, vms);
09051 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09052 return vm_intro_pt_BR(chan, vms);
09053 } else if (!strncasecmp(chan->language, "pt", 2)) {
09054 return vm_intro_pt(chan, vms);
09055 } else if (!strncasecmp(chan->language, "ru", 2)) {
09056 return vm_intro_multilang(chan, vms, "n");
09057 } else if (!strncasecmp(chan->language, "se", 2)) {
09058 return vm_intro_se(chan, vms);
09059 } else if (!strncasecmp(chan->language, "ua", 2)) {
09060 return vm_intro_multilang(chan, vms, "n");
09061 } else if (!strncasecmp(chan->language, "vi", 2)) {
09062 return vm_intro_vi(chan, vms);
09063 } else if (!strncasecmp(chan->language, "zh", 2)) {
09064 return vm_intro_zh(chan, vms);
09065 } else {
09066 return vm_intro_en(chan, vms);
09067 }
09068 }
09069
09070 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09071 {
09072 int res = 0;
09073
09074 while (!res) {
09075 if (vms->starting) {
09076 if (vms->lastmsg > -1) {
09077 if (skipadvanced)
09078 res = ast_play_and_wait(chan, "vm-onefor-full");
09079 else
09080 res = ast_play_and_wait(chan, "vm-onefor");
09081 if (!res)
09082 res = vm_play_folder_name(chan, vms->vmbox);
09083 }
09084 if (!res) {
09085 if (skipadvanced)
09086 res = ast_play_and_wait(chan, "vm-opts-full");
09087 else
09088 res = ast_play_and_wait(chan, "vm-opts");
09089 }
09090 } else {
09091
09092 if (skipadvanced) {
09093 res = ast_play_and_wait(chan, "vm-onefor-full");
09094 if (!res)
09095 res = vm_play_folder_name(chan, vms->vmbox);
09096 res = ast_play_and_wait(chan, "vm-opts-full");
09097 }
09098
09099
09100
09101
09102
09103
09104 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09105 res = ast_play_and_wait(chan, "vm-prev");
09106 }
09107 if (!res && !skipadvanced)
09108 res = ast_play_and_wait(chan, "vm-advopts");
09109 if (!res)
09110 res = ast_play_and_wait(chan, "vm-repeat");
09111
09112
09113
09114
09115
09116
09117 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09118 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09119 res = ast_play_and_wait(chan, "vm-next");
09120 }
09121 if (!res) {
09122 if (!vms->deleted[vms->curmsg])
09123 res = ast_play_and_wait(chan, "vm-delete");
09124 else
09125 res = ast_play_and_wait(chan, "vm-undelete");
09126 if (!res)
09127 res = ast_play_and_wait(chan, "vm-toforward");
09128 if (!res)
09129 res = ast_play_and_wait(chan, "vm-savemessage");
09130 }
09131 }
09132 if (!res) {
09133 res = ast_play_and_wait(chan, "vm-helpexit");
09134 }
09135 if (!res)
09136 res = ast_waitfordigit(chan, 6000);
09137 if (!res) {
09138 vms->repeats++;
09139 if (vms->repeats > 2) {
09140 res = 't';
09141 }
09142 }
09143 }
09144 return res;
09145 }
09146
09147 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09148 {
09149 int res = 0;
09150
09151 while (!res) {
09152 if (vms->lastmsg > -1) {
09153 res = ast_play_and_wait(chan, "vm-listen");
09154 if (!res)
09155 res = vm_play_folder_name(chan, vms->vmbox);
09156 if (!res)
09157 res = ast_play_and_wait(chan, "press");
09158 if (!res)
09159 res = ast_play_and_wait(chan, "digits/1");
09160 }
09161 if (!res)
09162 res = ast_play_and_wait(chan, "vm-opts");
09163 if (!res) {
09164 vms->starting = 0;
09165 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09166 }
09167 }
09168 return res;
09169 }
09170
09171 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09172 {
09173 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09174 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09175 } else {
09176 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09177 }
09178 }
09179
09180
09181 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09182 {
09183 int cmd = 0;
09184 int duration = 0;
09185 int tries = 0;
09186 char newpassword[80] = "";
09187 char newpassword2[80] = "";
09188 char prefile[PATH_MAX] = "";
09189 unsigned char buf[256];
09190 int bytes = 0;
09191
09192 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09193 if (ast_adsi_available(chan)) {
09194 bytes += adsi_logo(buf + bytes);
09195 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09196 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09197 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09198 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09199 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09200 }
09201
09202
09203 if (ast_test_flag(vmu, VM_FORCENAME)) {
09204 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09205 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09206 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09207 if (cmd < 0 || cmd == 't' || cmd == '#')
09208 return cmd;
09209 }
09210 }
09211
09212
09213 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09214 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09215 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09216 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09217 if (cmd < 0 || cmd == 't' || cmd == '#')
09218 return cmd;
09219 }
09220
09221 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09222 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09223 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09224 if (cmd < 0 || cmd == 't' || cmd == '#')
09225 return cmd;
09226 }
09227 }
09228
09229
09230
09231
09232
09233 for (;;) {
09234 newpassword[1] = '\0';
09235 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09236 if (cmd == '#')
09237 newpassword[0] = '\0';
09238 if (cmd < 0 || cmd == 't' || cmd == '#')
09239 return cmd;
09240 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09241 if (cmd < 0 || cmd == 't' || cmd == '#')
09242 return cmd;
09243 cmd = check_password(vmu, newpassword);
09244 if (cmd != 0) {
09245 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09246 cmd = ast_play_and_wait(chan, vm_invalid_password);
09247 } else {
09248 newpassword2[1] = '\0';
09249 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09250 if (cmd == '#')
09251 newpassword2[0] = '\0';
09252 if (cmd < 0 || cmd == 't' || cmd == '#')
09253 return cmd;
09254 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09255 if (cmd < 0 || cmd == 't' || cmd == '#')
09256 return cmd;
09257 if (!strcmp(newpassword, newpassword2))
09258 break;
09259 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09260 cmd = ast_play_and_wait(chan, vm_mismatch);
09261 }
09262 if (++tries == 3)
09263 return -1;
09264 if (cmd != 0) {
09265 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09266 }
09267 }
09268 if (pwdchange & PWDCHANGE_INTERNAL)
09269 vm_change_password(vmu, newpassword);
09270 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09271 vm_change_password_shell(vmu, newpassword);
09272
09273 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09274 cmd = ast_play_and_wait(chan, vm_passchanged);
09275
09276 return cmd;
09277 }
09278
09279 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09280 {
09281 int cmd = 0;
09282 int retries = 0;
09283 int duration = 0;
09284 char newpassword[80] = "";
09285 char newpassword2[80] = "";
09286 char prefile[PATH_MAX] = "";
09287 unsigned char buf[256];
09288 int bytes = 0;
09289
09290 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09291 if (ast_adsi_available(chan)) {
09292 bytes += adsi_logo(buf + bytes);
09293 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09294 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09295 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09296 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09297 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09298 }
09299 while ((cmd >= 0) && (cmd != 't')) {
09300 if (cmd)
09301 retries = 0;
09302 switch (cmd) {
09303 case '1':
09304 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09305 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09306 break;
09307 case '2':
09308 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09309 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09310 break;
09311 case '3':
09312 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09313 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09314 break;
09315 case '4':
09316 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09317 break;
09318 case '5':
09319 if (vmu->password[0] == '-') {
09320 cmd = ast_play_and_wait(chan, "vm-no");
09321 break;
09322 }
09323 newpassword[1] = '\0';
09324 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09325 if (cmd == '#')
09326 newpassword[0] = '\0';
09327 else {
09328 if (cmd < 0)
09329 break;
09330 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09331 break;
09332 }
09333 }
09334 cmd = check_password(vmu, newpassword);
09335 if (cmd != 0) {
09336 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09337 cmd = ast_play_and_wait(chan, vm_invalid_password);
09338 if (!cmd) {
09339 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09340 }
09341 break;
09342 }
09343 newpassword2[1] = '\0';
09344 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09345 if (cmd == '#')
09346 newpassword2[0] = '\0';
09347 else {
09348 if (cmd < 0)
09349 break;
09350
09351 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09352 break;
09353 }
09354 }
09355 if (strcmp(newpassword, newpassword2)) {
09356 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09357 cmd = ast_play_and_wait(chan, vm_mismatch);
09358 if (!cmd) {
09359 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09360 }
09361 break;
09362 }
09363
09364 if (pwdchange & PWDCHANGE_INTERNAL) {
09365 vm_change_password(vmu, newpassword);
09366 }
09367 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09368 vm_change_password_shell(vmu, newpassword);
09369 }
09370
09371 ast_debug(1, "User %s set password to %s of length %d\n",
09372 vms->username, newpassword, (int) strlen(newpassword));
09373 cmd = ast_play_and_wait(chan, vm_passchanged);
09374 break;
09375 case '*':
09376 cmd = 't';
09377 break;
09378 default:
09379 cmd = 0;
09380 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09381 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09382 if (ast_fileexists(prefile, NULL, NULL)) {
09383 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09384 }
09385 DISPOSE(prefile, -1);
09386 if (!cmd) {
09387 cmd = ast_play_and_wait(chan, "vm-options");
09388 }
09389 if (!cmd) {
09390 cmd = ast_waitfordigit(chan, 6000);
09391 }
09392 if (!cmd) {
09393 retries++;
09394 }
09395 if (retries > 3) {
09396 cmd = 't';
09397 }
09398 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09399 }
09400 }
09401 if (cmd == 't')
09402 cmd = 0;
09403 return cmd;
09404 }
09405
09406
09407
09408
09409
09410
09411
09412
09413
09414
09415
09416
09417
09418
09419
09420
09421
09422 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09423 {
09424 int cmd = 0;
09425 int retries = 0;
09426 int duration = 0;
09427 char prefile[PATH_MAX] = "";
09428 unsigned char buf[256];
09429 int bytes = 0;
09430
09431 if (ast_adsi_available(chan)) {
09432 bytes += adsi_logo(buf + bytes);
09433 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09434 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09435 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09436 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09437 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09438 }
09439
09440 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09441 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09442 while ((cmd >= 0) && (cmd != 't')) {
09443 if (cmd)
09444 retries = 0;
09445 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09446 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09447 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09448 cmd = 't';
09449 } else {
09450 switch (cmd) {
09451 case '1':
09452 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09453 break;
09454 case '2':
09455 DELETE(prefile, -1, prefile, vmu);
09456 ast_play_and_wait(chan, "vm-tempremoved");
09457 cmd = 't';
09458 break;
09459 case '*':
09460 cmd = 't';
09461 break;
09462 default:
09463 cmd = ast_play_and_wait(chan,
09464 ast_fileexists(prefile, NULL, NULL) > 0 ?
09465 "vm-tempgreeting2" : "vm-tempgreeting");
09466 if (!cmd) {
09467 cmd = ast_waitfordigit(chan, 6000);
09468 }
09469 if (!cmd) {
09470 retries++;
09471 }
09472 if (retries > 3) {
09473 cmd = 't';
09474 }
09475 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09476 }
09477 }
09478 DISPOSE(prefile, -1);
09479 }
09480 if (cmd == 't')
09481 cmd = 0;
09482 return cmd;
09483 }
09484
09485
09486
09487
09488
09489
09490
09491
09492
09493 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09494 {
09495 int cmd = 0;
09496
09497 if (vms->lastmsg > -1) {
09498 cmd = play_message(chan, vmu, vms);
09499 } else {
09500 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09501 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09502 if (!cmd) {
09503 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09504 cmd = ast_play_and_wait(chan, vms->fn);
09505 }
09506 if (!cmd)
09507 cmd = ast_play_and_wait(chan, "vm-messages");
09508 } else {
09509 if (!cmd)
09510 cmd = ast_play_and_wait(chan, "vm-messages");
09511 if (!cmd) {
09512 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09513 cmd = ast_play_and_wait(chan, vms->fn);
09514 }
09515 }
09516 }
09517 return cmd;
09518 }
09519
09520
09521 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09522 {
09523 int cmd = 0;
09524
09525 if (vms->lastmsg > -1) {
09526 cmd = play_message(chan, vmu, vms);
09527 } else {
09528 if (!strcasecmp(vms->fn, "INBOX")) {
09529 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09530 } else {
09531 cmd = ast_play_and_wait(chan, "vm-nomessages");
09532 }
09533 }
09534 return cmd;
09535 }
09536
09537
09538
09539
09540
09541
09542
09543
09544
09545 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09546 {
09547 int cmd = 0;
09548
09549 if (vms->lastmsg > -1) {
09550 cmd = play_message(chan, vmu, vms);
09551 } else {
09552 cmd = ast_play_and_wait(chan, "vm-youhave");
09553 if (!cmd)
09554 cmd = ast_play_and_wait(chan, "vm-no");
09555 if (!cmd) {
09556 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09557 cmd = ast_play_and_wait(chan, vms->fn);
09558 }
09559 if (!cmd)
09560 cmd = ast_play_and_wait(chan, "vm-messages");
09561 }
09562 return cmd;
09563 }
09564
09565
09566
09567
09568
09569
09570
09571
09572
09573 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09574 {
09575 int cmd;
09576
09577 if (vms->lastmsg > -1) {
09578 cmd = play_message(chan, vmu, vms);
09579 } else {
09580 cmd = ast_play_and_wait(chan, "vm-no");
09581 if (!cmd)
09582 cmd = ast_play_and_wait(chan, "vm-message");
09583 if (!cmd) {
09584 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09585 cmd = ast_play_and_wait(chan, vms->fn);
09586 }
09587 }
09588 return cmd;
09589 }
09590
09591
09592
09593
09594
09595
09596
09597
09598
09599 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09600 {
09601 int cmd;
09602
09603 if (vms->lastmsg > -1) {
09604 cmd = play_message(chan, vmu, vms);
09605 } else {
09606 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09607 if (!cmd)
09608 cmd = ast_play_and_wait(chan, "vm-messages");
09609 if (!cmd) {
09610 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09611 cmd = ast_play_and_wait(chan, vms->fn);
09612 }
09613 }
09614 return cmd;
09615 }
09616
09617
09618
09619
09620
09621
09622
09623
09624
09625 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09626 {
09627 int cmd;
09628
09629 if (vms->lastmsg > -1) {
09630 cmd = play_message(chan, vmu, vms);
09631 } else {
09632 cmd = ast_play_and_wait(chan, "vm-no");
09633 if (!cmd) {
09634 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09635 cmd = ast_play_and_wait(chan, vms->fn);
09636 }
09637 if (!cmd)
09638 cmd = ast_play_and_wait(chan, "vm-messages");
09639 }
09640 return cmd;
09641 }
09642
09643
09644
09645
09646
09647
09648
09649
09650
09651 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09652 {
09653 int cmd;
09654
09655 if (vms->lastmsg > -1) {
09656 cmd = play_message(chan, vmu, vms);
09657 } else {
09658 cmd = ast_play_and_wait(chan, "vm-you");
09659 if (!cmd)
09660 cmd = ast_play_and_wait(chan, "vm-haveno");
09661 if (!cmd)
09662 cmd = ast_play_and_wait(chan, "vm-messages");
09663 if (!cmd) {
09664 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09665 cmd = ast_play_and_wait(chan, vms->fn);
09666 }
09667 }
09668 return cmd;
09669 }
09670
09671
09672
09673
09674
09675
09676
09677
09678
09679 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09680 {
09681 int cmd = 0;
09682
09683 if (vms->lastmsg > -1) {
09684 cmd = play_message(chan, vmu, vms);
09685 } else {
09686 cmd = ast_play_and_wait(chan, "vm-no");
09687 if (!cmd) {
09688 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09689 cmd = ast_play_and_wait(chan, vms->fn);
09690 }
09691 }
09692 return cmd;
09693 }
09694
09695
09696
09697
09698
09699
09700
09701
09702
09703
09704
09705
09706 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09707 {
09708 if (!strncasecmp(chan->language, "es", 2)) {
09709 return vm_browse_messages_es(chan, vms, vmu);
09710 } else if (!strncasecmp(chan->language, "gr", 2)) {
09711 return vm_browse_messages_gr(chan, vms, vmu);
09712 } else if (!strncasecmp(chan->language, "he", 2)) {
09713 return vm_browse_messages_he(chan, vms, vmu);
09714 } else if (!strncasecmp(chan->language, "it", 2)) {
09715 return vm_browse_messages_it(chan, vms, vmu);
09716 } else if (!strncasecmp(chan->language, "pt", 2)) {
09717 return vm_browse_messages_pt(chan, vms, vmu);
09718 } else if (!strncasecmp(chan->language, "vi", 2)) {
09719 return vm_browse_messages_vi(chan, vms, vmu);
09720 } else if (!strncasecmp(chan->language, "zh", 2)) {
09721 return vm_browse_messages_zh(chan, vms, vmu);
09722 } else {
09723 return vm_browse_messages_en(chan, vms, vmu);
09724 }
09725 }
09726
09727 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09728 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09729 int skipuser, int max_logins, int silent)
09730 {
09731 int useadsi = 0, valid = 0, logretries = 0;
09732 char password[AST_MAX_EXTENSION]="", *passptr;
09733 struct ast_vm_user vmus, *vmu = NULL;
09734
09735
09736 adsi_begin(chan, &useadsi);
09737 if (!skipuser && useadsi)
09738 adsi_login(chan);
09739 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09740 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09741 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09742 return -1;
09743 }
09744
09745
09746
09747 while (!valid && (logretries < max_logins)) {
09748
09749 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09750 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09751 return -1;
09752 }
09753 if (ast_strlen_zero(mailbox)) {
09754 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09755 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09756 } else {
09757 ast_verb(3, "Username not entered\n");
09758 return -1;
09759 }
09760 } else if (mailbox[0] == '*') {
09761
09762 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09763 if (ast_exists_extension(chan, chan->context, "a", 1,
09764 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09765 return -1;
09766 }
09767 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09768 mailbox[0] = '\0';
09769 }
09770
09771 if (useadsi)
09772 adsi_password(chan);
09773
09774 if (!ast_strlen_zero(prefix)) {
09775 char fullusername[80] = "";
09776 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09777 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09778 ast_copy_string(mailbox, fullusername, mailbox_size);
09779 }
09780
09781 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09782 vmu = find_user(&vmus, context, mailbox);
09783 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09784
09785 password[0] = '\0';
09786 } else {
09787 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09788 if (ast_streamfile(chan, vm_password, chan->language)) {
09789 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09790 return -1;
09791 }
09792 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09793 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09794 return -1;
09795 } else if (password[0] == '*') {
09796
09797 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09798 if (ast_exists_extension(chan, chan->context, "a", 1,
09799 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09800 mailbox[0] = '*';
09801 return -1;
09802 }
09803 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09804 mailbox[0] = '\0';
09805
09806 vmu = NULL;
09807 }
09808 }
09809
09810 if (vmu) {
09811 passptr = vmu->password;
09812 if (passptr[0] == '-') passptr++;
09813 }
09814 if (vmu && !strcmp(passptr, password))
09815 valid++;
09816 else {
09817 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09818 if (!ast_strlen_zero(prefix))
09819 mailbox[0] = '\0';
09820 }
09821 logretries++;
09822 if (!valid) {
09823 if (skipuser || logretries >= max_logins) {
09824 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09825 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09826 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09827 return -1;
09828 }
09829 } else {
09830 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09831 if (useadsi)
09832 adsi_login(chan);
09833 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09834 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09835 return -1;
09836 }
09837 }
09838 if (ast_waitstream(chan, ""))
09839 return -1;
09840 }
09841 }
09842 if (!valid && (logretries >= max_logins)) {
09843 ast_stopstream(chan);
09844 ast_play_and_wait(chan, "vm-goodbye");
09845 return -1;
09846 }
09847 if (vmu && !skipuser) {
09848 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09849 }
09850 return 0;
09851 }
09852
09853 static int vm_execmain(struct ast_channel *chan, const char *data)
09854 {
09855
09856
09857
09858 int res = -1;
09859 int cmd = 0;
09860 int valid = 0;
09861 char prefixstr[80] ="";
09862 char ext_context[256]="";
09863 int box;
09864 int useadsi = 0;
09865 int skipuser = 0;
09866 struct vm_state vms;
09867 struct ast_vm_user *vmu = NULL, vmus;
09868 char *context = NULL;
09869 int silentexit = 0;
09870 struct ast_flags flags = { 0 };
09871 signed char record_gain = 0;
09872 int play_auto = 0;
09873 int play_folder = 0;
09874 int in_urgent = 0;
09875 #ifdef IMAP_STORAGE
09876 int deleted = 0;
09877 #endif
09878
09879
09880 memset(&vms, 0, sizeof(vms));
09881
09882 vms.lastmsg = -1;
09883
09884 memset(&vmus, 0, sizeof(vmus));
09885
09886 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09887 if (chan->_state != AST_STATE_UP) {
09888 ast_debug(1, "Before ast_answer\n");
09889 ast_answer(chan);
09890 }
09891
09892 if (!ast_strlen_zero(data)) {
09893 char *opts[OPT_ARG_ARRAY_SIZE];
09894 char *parse;
09895 AST_DECLARE_APP_ARGS(args,
09896 AST_APP_ARG(argv0);
09897 AST_APP_ARG(argv1);
09898 );
09899
09900 parse = ast_strdupa(data);
09901
09902 AST_STANDARD_APP_ARGS(args, parse);
09903
09904 if (args.argc == 2) {
09905 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09906 return -1;
09907 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09908 int gain;
09909 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09910 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09911 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09912 return -1;
09913 } else {
09914 record_gain = (signed char) gain;
09915 }
09916 } else {
09917 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09918 }
09919 }
09920 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09921 play_auto = 1;
09922 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09923
09924 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09925 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09926 play_folder = -1;
09927 }
09928 } else {
09929 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09930 }
09931 } else {
09932 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09933 }
09934 if (play_folder > 9 || play_folder < 0) {
09935 ast_log(AST_LOG_WARNING,
09936 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09937 opts[OPT_ARG_PLAYFOLDER]);
09938 play_folder = 0;
09939 }
09940 }
09941 } else {
09942
09943 while (*(args.argv0)) {
09944 if (*(args.argv0) == 's')
09945 ast_set_flag(&flags, OPT_SILENT);
09946 else if (*(args.argv0) == 'p')
09947 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09948 else
09949 break;
09950 (args.argv0)++;
09951 }
09952
09953 }
09954
09955 valid = ast_test_flag(&flags, OPT_SILENT);
09956
09957 if ((context = strchr(args.argv0, '@')))
09958 *context++ = '\0';
09959
09960 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09961 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09962 else
09963 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09964
09965 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09966 skipuser++;
09967 else
09968 valid = 0;
09969 }
09970
09971 if (!valid)
09972 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09973
09974 ast_debug(1, "After vm_authenticate\n");
09975
09976 if (vms.username[0] == '*') {
09977 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09978
09979
09980 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09981 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
09982 res = 0;
09983 goto out;
09984 }
09985 }
09986
09987 if (!res) {
09988 valid = 1;
09989 if (!skipuser)
09990 vmu = &vmus;
09991 } else {
09992 res = 0;
09993 }
09994
09995
09996 adsi_begin(chan, &useadsi);
09997
09998 ast_test_suite_assert(valid);
09999 if (!valid) {
10000 goto out;
10001 }
10002 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10003
10004 #ifdef IMAP_STORAGE
10005 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10006 pthread_setspecific(ts_vmstate.key, &vms);
10007
10008 vms.interactive = 1;
10009 vms.updated = 1;
10010 if (vmu)
10011 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10012 vmstate_insert(&vms);
10013 init_vm_state(&vms);
10014 #endif
10015
10016 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
10017 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
10018 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10019 return -1;
10020 }
10021 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
10022 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
10023 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10024 return -1;
10025 }
10026
10027
10028 if (!ast_strlen_zero(vmu->language))
10029 ast_string_field_set(chan, language, vmu->language);
10030
10031
10032 ast_debug(1, "Before open_mailbox\n");
10033 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10034 if (res < 0)
10035 goto out;
10036 vms.oldmessages = vms.lastmsg + 1;
10037 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10038
10039 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10040 if (res < 0)
10041 goto out;
10042 vms.newmessages = vms.lastmsg + 1;
10043 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10044
10045 in_urgent = 1;
10046 res = open_mailbox(&vms, vmu, 11);
10047 if (res < 0)
10048 goto out;
10049 vms.urgentmessages = vms.lastmsg + 1;
10050 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10051
10052
10053 if (play_auto) {
10054 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10055 if (vms.urgentmessages) {
10056 in_urgent = 1;
10057 res = open_mailbox(&vms, vmu, 11);
10058 } else {
10059 in_urgent = 0;
10060 res = open_mailbox(&vms, vmu, play_folder);
10061 }
10062 if (res < 0)
10063 goto out;
10064
10065
10066 if (vms.lastmsg == -1) {
10067 in_urgent = 0;
10068 cmd = vm_browse_messages(chan, &vms, vmu);
10069 res = 0;
10070 goto out;
10071 }
10072 } else {
10073 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10074
10075 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10076 in_urgent = 0;
10077 play_folder = 1;
10078 if (res < 0)
10079 goto out;
10080 } else if (!vms.urgentmessages && vms.newmessages) {
10081
10082 in_urgent = 0;
10083 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10084 if (res < 0)
10085 goto out;
10086 }
10087 }
10088
10089 if (useadsi)
10090 adsi_status(chan, &vms);
10091 res = 0;
10092
10093
10094 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10095 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10096 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10097 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10098 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10099 if ((cmd == 't') || (cmd == '#')) {
10100
10101 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10102 res = 0;
10103 goto out;
10104 } else if (cmd < 0) {
10105
10106 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10107 res = -1;
10108 goto out;
10109 }
10110 }
10111 #ifdef IMAP_STORAGE
10112 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10113 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10114 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10115 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10116 }
10117 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10118 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10119 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10120 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10121 }
10122 #endif
10123
10124 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10125 if (play_auto) {
10126 cmd = '1';
10127 } else {
10128 cmd = vm_intro(chan, vmu, &vms);
10129 }
10130 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10131
10132 vms.repeats = 0;
10133 vms.starting = 1;
10134 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10135
10136 switch (cmd) {
10137 case '1':
10138 vms.curmsg = 0;
10139
10140 case '5':
10141 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10142 cmd = vm_browse_messages(chan, &vms, vmu);
10143 break;
10144 case '2':
10145 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10146 if (useadsi)
10147 adsi_folders(chan, 0, "Change to folder...");
10148
10149 cmd = get_folder2(chan, "vm-changeto", 0);
10150 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10151 if (cmd == '#') {
10152 cmd = 0;
10153 } else if (cmd > 0) {
10154 cmd = cmd - '0';
10155 res = close_mailbox(&vms, vmu);
10156 if (res == ERROR_LOCK_PATH)
10157 goto out;
10158
10159 if (cmd != 11) in_urgent = 0;
10160 res = open_mailbox(&vms, vmu, cmd);
10161 if (res < 0)
10162 goto out;
10163 play_folder = cmd;
10164 cmd = 0;
10165 }
10166 if (useadsi)
10167 adsi_status2(chan, &vms);
10168
10169 if (!cmd) {
10170 cmd = vm_play_folder_name(chan, vms.vmbox);
10171 }
10172
10173 vms.starting = 1;
10174 break;
10175 case '3':
10176 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10177 cmd = 0;
10178 vms.repeats = 0;
10179 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10180 switch (cmd) {
10181 case '1':
10182 if (vms.lastmsg > -1 && !vms.starting) {
10183 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10184 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10185 res = cmd;
10186 goto out;
10187 }
10188 } else {
10189 cmd = ast_play_and_wait(chan, "vm-sorry");
10190 }
10191 cmd = 't';
10192 break;
10193 case '2':
10194 if (!vms.starting)
10195 ast_verb(3, "Callback Requested\n");
10196 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10197 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10198 if (cmd == 9) {
10199 silentexit = 1;
10200 goto out;
10201 } else if (cmd == ERROR_LOCK_PATH) {
10202 res = cmd;
10203 goto out;
10204 }
10205 } else {
10206 cmd = ast_play_and_wait(chan, "vm-sorry");
10207 }
10208 cmd = 't';
10209 break;
10210 case '3':
10211 if (vms.lastmsg > -1 && !vms.starting) {
10212 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10213 if (cmd == ERROR_LOCK_PATH) {
10214 res = cmd;
10215 goto out;
10216 }
10217 } else {
10218 cmd = ast_play_and_wait(chan, "vm-sorry");
10219 }
10220 cmd = 't';
10221 break;
10222 case '4':
10223 if (!ast_strlen_zero(vmu->dialout)) {
10224 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10225 if (cmd == 9) {
10226 silentexit = 1;
10227 goto out;
10228 }
10229 } else {
10230 cmd = ast_play_and_wait(chan, "vm-sorry");
10231 }
10232 cmd = 't';
10233 break;
10234
10235 case '5':
10236 if (ast_test_flag(vmu, VM_SVMAIL)) {
10237 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10238 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10239 res = cmd;
10240 goto out;
10241 }
10242 } else {
10243 cmd = ast_play_and_wait(chan, "vm-sorry");
10244 }
10245 cmd = 't';
10246 break;
10247
10248 case '*':
10249 cmd = 't';
10250 break;
10251
10252 default:
10253 cmd = 0;
10254 if (!vms.starting) {
10255 cmd = ast_play_and_wait(chan, "vm-toreply");
10256 }
10257 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10258 cmd = ast_play_and_wait(chan, "vm-tocallback");
10259 }
10260 if (!cmd && !vms.starting) {
10261 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10262 }
10263 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10264 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10265 }
10266 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10267 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10268 }
10269 if (!cmd) {
10270 cmd = ast_play_and_wait(chan, "vm-starmain");
10271 }
10272 if (!cmd) {
10273 cmd = ast_waitfordigit(chan, 6000);
10274 }
10275 if (!cmd) {
10276 vms.repeats++;
10277 }
10278 if (vms.repeats > 3) {
10279 cmd = 't';
10280 }
10281 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10282 }
10283 }
10284 if (cmd == 't') {
10285 cmd = 0;
10286 vms.repeats = 0;
10287 }
10288 break;
10289 case '4':
10290 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10291 if (vms.curmsg > 0) {
10292 vms.curmsg--;
10293 cmd = play_message(chan, vmu, &vms);
10294 } else {
10295
10296
10297
10298
10299 if (in_urgent == 0 && vms.urgentmessages > 0) {
10300
10301 in_urgent = 1;
10302 res = close_mailbox(&vms, vmu);
10303 if (res == ERROR_LOCK_PATH)
10304 goto out;
10305 res = open_mailbox(&vms, vmu, 11);
10306 if (res < 0)
10307 goto out;
10308 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10309 vms.curmsg = vms.lastmsg;
10310 if (vms.lastmsg < 0) {
10311 cmd = ast_play_and_wait(chan, "vm-nomore");
10312 }
10313 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10314 vms.curmsg = vms.lastmsg;
10315 cmd = play_message(chan, vmu, &vms);
10316 } else {
10317 cmd = ast_play_and_wait(chan, "vm-nomore");
10318 }
10319 }
10320 break;
10321 case '6':
10322 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10323 if (vms.curmsg < vms.lastmsg) {
10324 vms.curmsg++;
10325 cmd = play_message(chan, vmu, &vms);
10326 } else {
10327 if (in_urgent && vms.newmessages > 0) {
10328
10329
10330
10331
10332 in_urgent = 0;
10333 res = close_mailbox(&vms, vmu);
10334 if (res == ERROR_LOCK_PATH)
10335 goto out;
10336 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10337 if (res < 0)
10338 goto out;
10339 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10340 vms.curmsg = -1;
10341 if (vms.lastmsg < 0) {
10342 cmd = ast_play_and_wait(chan, "vm-nomore");
10343 }
10344 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10345 vms.curmsg = 0;
10346 cmd = play_message(chan, vmu, &vms);
10347 } else {
10348 cmd = ast_play_and_wait(chan, "vm-nomore");
10349 }
10350 }
10351 break;
10352 case '7':
10353 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10354 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10355 if (useadsi)
10356 adsi_delete(chan, &vms);
10357 if (vms.deleted[vms.curmsg]) {
10358 if (play_folder == 0) {
10359 if (in_urgent) {
10360 vms.urgentmessages--;
10361 } else {
10362 vms.newmessages--;
10363 }
10364 }
10365 else if (play_folder == 1)
10366 vms.oldmessages--;
10367 cmd = ast_play_and_wait(chan, "vm-deleted");
10368 } else {
10369 if (play_folder == 0) {
10370 if (in_urgent) {
10371 vms.urgentmessages++;
10372 } else {
10373 vms.newmessages++;
10374 }
10375 }
10376 else if (play_folder == 1)
10377 vms.oldmessages++;
10378 cmd = ast_play_and_wait(chan, "vm-undeleted");
10379 }
10380 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10381 if (vms.curmsg < vms.lastmsg) {
10382 vms.curmsg++;
10383 cmd = play_message(chan, vmu, &vms);
10384 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10385 vms.curmsg = 0;
10386 cmd = play_message(chan, vmu, &vms);
10387 } else {
10388
10389
10390
10391
10392 if (in_urgent == 1) {
10393
10394 in_urgent = 0;
10395 res = close_mailbox(&vms, vmu);
10396 if (res == ERROR_LOCK_PATH)
10397 goto out;
10398 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10399 if (res < 0)
10400 goto out;
10401 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10402 vms.curmsg = -1;
10403 if (vms.lastmsg < 0) {
10404 cmd = ast_play_and_wait(chan, "vm-nomore");
10405 }
10406 } else {
10407 cmd = ast_play_and_wait(chan, "vm-nomore");
10408 }
10409 }
10410 }
10411 } else
10412 cmd = 0;
10413 #ifdef IMAP_STORAGE
10414 deleted = 1;
10415 #endif
10416 break;
10417
10418 case '8':
10419 if (vms.lastmsg > -1) {
10420 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10421 if (cmd == ERROR_LOCK_PATH) {
10422 res = cmd;
10423 goto out;
10424 }
10425 } else {
10426
10427
10428
10429
10430 if (in_urgent == 1 && vms.newmessages > 0) {
10431
10432 in_urgent = 0;
10433 res = close_mailbox(&vms, vmu);
10434 if (res == ERROR_LOCK_PATH)
10435 goto out;
10436 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10437 if (res < 0)
10438 goto out;
10439 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10440 vms.curmsg = -1;
10441 if (vms.lastmsg < 0) {
10442 cmd = ast_play_and_wait(chan, "vm-nomore");
10443 }
10444 } else {
10445 cmd = ast_play_and_wait(chan, "vm-nomore");
10446 }
10447 }
10448 break;
10449 case '9':
10450 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10451 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10452
10453 cmd = 0;
10454 break;
10455 }
10456 if (useadsi)
10457 adsi_folders(chan, 1, "Save to folder...");
10458 cmd = get_folder2(chan, "vm-savefolder", 1);
10459 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10460 box = 0;
10461 if (cmd == '#') {
10462 cmd = 0;
10463 break;
10464 } else if (cmd > 0) {
10465 box = cmd = cmd - '0';
10466 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10467 if (cmd == ERROR_LOCK_PATH) {
10468 res = cmd;
10469 goto out;
10470 #ifndef IMAP_STORAGE
10471 } else if (!cmd) {
10472 vms.deleted[vms.curmsg] = 1;
10473 #endif
10474 } else {
10475 vms.deleted[vms.curmsg] = 0;
10476 vms.heard[vms.curmsg] = 0;
10477 }
10478 }
10479 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10480 if (useadsi)
10481 adsi_message(chan, &vms);
10482 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10483 if (!cmd) {
10484 cmd = ast_play_and_wait(chan, "vm-message");
10485 if (!cmd)
10486 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10487 if (!cmd)
10488 cmd = ast_play_and_wait(chan, "vm-savedto");
10489 if (!cmd)
10490 cmd = vm_play_folder_name(chan, vms.fn);
10491 } else {
10492 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10493 }
10494 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10495 if (vms.curmsg < vms.lastmsg) {
10496 vms.curmsg++;
10497 cmd = play_message(chan, vmu, &vms);
10498 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10499 vms.curmsg = 0;
10500 cmd = play_message(chan, vmu, &vms);
10501 } else {
10502
10503
10504
10505
10506 if (in_urgent == 1 && vms.newmessages > 0) {
10507
10508 in_urgent = 0;
10509 res = close_mailbox(&vms, vmu);
10510 if (res == ERROR_LOCK_PATH)
10511 goto out;
10512 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10513 if (res < 0)
10514 goto out;
10515 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10516 vms.curmsg = -1;
10517 if (vms.lastmsg < 0) {
10518 cmd = ast_play_and_wait(chan, "vm-nomore");
10519 }
10520 } else {
10521 cmd = ast_play_and_wait(chan, "vm-nomore");
10522 }
10523 }
10524 }
10525 break;
10526 case '*':
10527 if (!vms.starting) {
10528 cmd = ast_play_and_wait(chan, "vm-onefor");
10529 if (!strncasecmp(chan->language, "he", 2)) {
10530 cmd = ast_play_and_wait(chan, "vm-for");
10531 }
10532 if (!cmd)
10533 cmd = vm_play_folder_name(chan, vms.vmbox);
10534 if (!cmd)
10535 cmd = ast_play_and_wait(chan, "vm-opts");
10536 if (!cmd)
10537 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10538 } else
10539 cmd = 0;
10540 break;
10541 case '0':
10542 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10543 if (useadsi)
10544 adsi_status(chan, &vms);
10545 break;
10546 default:
10547 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10548 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10549 break;
10550 }
10551 }
10552 if ((cmd == 't') || (cmd == '#')) {
10553
10554 res = 0;
10555 } else {
10556
10557 res = -1;
10558 }
10559
10560 out:
10561 if (res > -1) {
10562 ast_stopstream(chan);
10563 adsi_goodbye(chan);
10564 if (valid && res != OPERATOR_EXIT) {
10565 if (silentexit)
10566 res = ast_play_and_wait(chan, "vm-dialout");
10567 else
10568 res = ast_play_and_wait(chan, "vm-goodbye");
10569 }
10570 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10571 res = 0;
10572 }
10573 if (useadsi)
10574 ast_adsi_unload_session(chan);
10575 }
10576 if (vmu)
10577 close_mailbox(&vms, vmu);
10578 if (valid) {
10579 int new = 0, old = 0, urgent = 0;
10580 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10581 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10582
10583 run_externnotify(vmu->context, vmu->mailbox, NULL);
10584 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10585 queue_mwi_event(ext_context, urgent, new, old);
10586 }
10587 #ifdef IMAP_STORAGE
10588
10589 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10590 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10591 ast_mutex_lock(&vms.lock);
10592 #ifdef HAVE_IMAP_TK2006
10593 if (LEVELUIDPLUS (vms.mailstream)) {
10594 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10595 } else
10596 #endif
10597 mail_expunge(vms.mailstream);
10598 ast_mutex_unlock(&vms.lock);
10599 }
10600
10601
10602 if (vmu) {
10603 vmstate_delete(&vms);
10604 }
10605 #endif
10606 if (vmu)
10607 free_user(vmu);
10608 if (vms.deleted)
10609 ast_free(vms.deleted);
10610 if (vms.heard)
10611 ast_free(vms.heard);
10612
10613 #ifdef IMAP_STORAGE
10614 pthread_setspecific(ts_vmstate.key, NULL);
10615 #endif
10616 return res;
10617 }
10618
10619 static int vm_exec(struct ast_channel *chan, const char *data)
10620 {
10621 int res = 0;
10622 char *tmp;
10623 struct leave_vm_options leave_options;
10624 struct ast_flags flags = { 0 };
10625 char *opts[OPT_ARG_ARRAY_SIZE];
10626 AST_DECLARE_APP_ARGS(args,
10627 AST_APP_ARG(argv0);
10628 AST_APP_ARG(argv1);
10629 );
10630
10631 memset(&leave_options, 0, sizeof(leave_options));
10632
10633 if (chan->_state != AST_STATE_UP)
10634 ast_answer(chan);
10635
10636 if (!ast_strlen_zero(data)) {
10637 tmp = ast_strdupa(data);
10638 AST_STANDARD_APP_ARGS(args, tmp);
10639 if (args.argc == 2) {
10640 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10641 return -1;
10642 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10643 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10644 int gain;
10645
10646 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10647 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10648 return -1;
10649 } else {
10650 leave_options.record_gain = (signed char) gain;
10651 }
10652 }
10653 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10654 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10655 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10656 }
10657 }
10658 } else {
10659 char temp[256];
10660 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10661 if (res < 0)
10662 return res;
10663 if (ast_strlen_zero(temp))
10664 return 0;
10665 args.argv0 = ast_strdupa(temp);
10666 }
10667
10668 res = leave_voicemail(chan, args.argv0, &leave_options);
10669 if (res == 't') {
10670 ast_play_and_wait(chan, "vm-goodbye");
10671 res = 0;
10672 }
10673
10674 if (res == OPERATOR_EXIT) {
10675 res = 0;
10676 }
10677
10678 if (res == ERROR_LOCK_PATH) {
10679 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10680 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10681 res = 0;
10682 }
10683
10684 return res;
10685 }
10686
10687 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10688 {
10689 struct ast_vm_user *vmu;
10690
10691 if (!ast_strlen_zero(box) && box[0] == '*') {
10692 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10693 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10694 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10695 "\n\tand will be ignored.\n", box, context);
10696 return NULL;
10697 }
10698
10699 AST_LIST_TRAVERSE(&users, vmu, list) {
10700 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10701 if (strcasecmp(vmu->context, context)) {
10702 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10703 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10704 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10705 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10706 }
10707 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10708 return NULL;
10709 }
10710 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10711 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10712 return NULL;
10713 }
10714 }
10715
10716 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10717 return NULL;
10718
10719 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10720 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10721
10722 AST_LIST_INSERT_TAIL(&users, vmu, list);
10723
10724 return vmu;
10725 }
10726
10727 static int append_mailbox(const char *context, const char *box, const char *data)
10728 {
10729
10730 char *tmp;
10731 char *stringp;
10732 char *s;
10733 struct ast_vm_user *vmu;
10734 char *mailbox_full;
10735 int new = 0, old = 0, urgent = 0;
10736 char secretfn[PATH_MAX] = "";
10737
10738 tmp = ast_strdupa(data);
10739
10740 if (!(vmu = find_or_create(context, box)))
10741 return -1;
10742
10743 populate_defaults(vmu);
10744
10745 stringp = tmp;
10746 if ((s = strsep(&stringp, ","))) {
10747 if (!ast_strlen_zero(s) && s[0] == '*') {
10748 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10749 "\n\tmust be reset in voicemail.conf.\n", box);
10750 }
10751
10752 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10753 }
10754 if (stringp && (s = strsep(&stringp, ","))) {
10755 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10756 }
10757 if (stringp && (s = strsep(&stringp, ","))) {
10758 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10759 }
10760 if (stringp && (s = strsep(&stringp, ","))) {
10761 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10762 }
10763 if (stringp && (s = strsep(&stringp, ","))) {
10764 apply_options(vmu, s);
10765 }
10766
10767 switch (vmu->passwordlocation) {
10768 case OPT_PWLOC_SPOOLDIR:
10769 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10770 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10771 }
10772
10773 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10774 strcpy(mailbox_full, box);
10775 strcat(mailbox_full, "@");
10776 strcat(mailbox_full, context);
10777
10778 inboxcount2(mailbox_full, &urgent, &new, &old);
10779 queue_mwi_event(mailbox_full, urgent, new, old);
10780
10781 return 0;
10782 }
10783
10784 AST_TEST_DEFINE(test_voicemail_vmuser)
10785 {
10786 int res = 0;
10787 struct ast_vm_user *vmu;
10788
10789 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10790 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10791 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10792 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10793 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10794 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10795 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10796 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10797 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10798 #ifdef IMAP_STORAGE
10799 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10800 "imapfolder=INBOX|imapvmshareid=6000";
10801 #endif
10802
10803 switch (cmd) {
10804 case TEST_INIT:
10805 info->name = "vmuser";
10806 info->category = "/apps/app_voicemail/";
10807 info->summary = "Vmuser unit test";
10808 info->description =
10809 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10810 return AST_TEST_NOT_RUN;
10811 case TEST_EXECUTE:
10812 break;
10813 }
10814
10815 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10816 return AST_TEST_NOT_RUN;
10817 }
10818 ast_set_flag(vmu, VM_ALLOCED);
10819 populate_defaults(vmu);
10820
10821 apply_options(vmu, options_string);
10822
10823 if (!ast_test_flag(vmu, VM_ATTACH)) {
10824 ast_test_status_update(test, "Parse failure for attach option\n");
10825 res = 1;
10826 }
10827 if (strcasecmp(vmu->attachfmt, "wav49")) {
10828 ast_test_status_update(test, "Parse failure for attachftm option\n");
10829 res = 1;
10830 }
10831 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10832 ast_test_status_update(test, "Parse failure for serveremail option\n");
10833 res = 1;
10834 }
10835 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10836 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10837 res = 1;
10838 }
10839 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10840 ast_test_status_update(test, "Parse failure for emailbody option\n");
10841 res = 1;
10842 }
10843 if (strcasecmp(vmu->zonetag, "central")) {
10844 ast_test_status_update(test, "Parse failure for tz option\n");
10845 res = 1;
10846 }
10847 if (!ast_test_flag(vmu, VM_DELETE)) {
10848 ast_test_status_update(test, "Parse failure for delete option\n");
10849 res = 1;
10850 }
10851 if (!ast_test_flag(vmu, VM_SAYCID)) {
10852 ast_test_status_update(test, "Parse failure for saycid option\n");
10853 res = 1;
10854 }
10855 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10856 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10857 res = 1;
10858 }
10859 if (!ast_test_flag(vmu, VM_REVIEW)) {
10860 ast_test_status_update(test, "Parse failure for review option\n");
10861 res = 1;
10862 }
10863 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10864 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10865 res = 1;
10866 }
10867 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10868 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10869 res = 1;
10870 }
10871 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10872 ast_test_status_update(test, "Parse failure for operator option\n");
10873 res = 1;
10874 }
10875 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10876 ast_test_status_update(test, "Parse failure for envelope option\n");
10877 res = 1;
10878 }
10879 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10880 ast_test_status_update(test, "Parse failure for moveheard option\n");
10881 res = 1;
10882 }
10883 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10884 ast_test_status_update(test, "Parse failure for sayduration option\n");
10885 res = 1;
10886 }
10887 if (vmu->saydurationm != 5) {
10888 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10889 res = 1;
10890 }
10891 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10892 ast_test_status_update(test, "Parse failure for forcename option\n");
10893 res = 1;
10894 }
10895 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10896 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10897 res = 1;
10898 }
10899 if (strcasecmp(vmu->callback, "somecontext")) {
10900 ast_test_status_update(test, "Parse failure for callbacks option\n");
10901 res = 1;
10902 }
10903 if (strcasecmp(vmu->dialout, "somecontext2")) {
10904 ast_test_status_update(test, "Parse failure for dialout option\n");
10905 res = 1;
10906 }
10907 if (strcasecmp(vmu->exit, "somecontext3")) {
10908 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10909 res = 1;
10910 }
10911 if (vmu->minsecs != 10) {
10912 ast_test_status_update(test, "Parse failure for minsecs option\n");
10913 res = 1;
10914 }
10915 if (vmu->maxsecs != 100) {
10916 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10917 res = 1;
10918 }
10919 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10920 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10921 res = 1;
10922 }
10923 if (vmu->maxdeletedmsg != 50) {
10924 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10925 res = 1;
10926 }
10927 if (vmu->volgain != 1.3) {
10928 ast_test_status_update(test, "Parse failure for volgain option\n");
10929 res = 1;
10930 }
10931 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10932 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10933 res = 1;
10934 }
10935 #ifdef IMAP_STORAGE
10936 apply_options(vmu, option_string2);
10937
10938 if (strcasecmp(vmu->imapuser, "imapuser")) {
10939 ast_test_status_update(test, "Parse failure for imapuser option\n");
10940 res = 1;
10941 }
10942 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10943 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10944 res = 1;
10945 }
10946 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10947 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10948 res = 1;
10949 }
10950 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10951 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10952 res = 1;
10953 }
10954 #endif
10955
10956 free_user(vmu);
10957 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10958 }
10959
10960 static int vm_box_exists(struct ast_channel *chan, const char *data)
10961 {
10962 struct ast_vm_user svm;
10963 char *context, *box;
10964 AST_DECLARE_APP_ARGS(args,
10965 AST_APP_ARG(mbox);
10966 AST_APP_ARG(options);
10967 );
10968 static int dep_warning = 0;
10969
10970 if (ast_strlen_zero(data)) {
10971 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10972 return -1;
10973 }
10974
10975 if (!dep_warning) {
10976 dep_warning = 1;
10977 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10978 }
10979
10980 box = ast_strdupa(data);
10981
10982 AST_STANDARD_APP_ARGS(args, box);
10983
10984 if (args.options) {
10985 }
10986
10987 if ((context = strchr(args.mbox, '@'))) {
10988 *context = '\0';
10989 context++;
10990 }
10991
10992 if (find_user(&svm, context, args.mbox)) {
10993 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10994 } else
10995 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10996
10997 return 0;
10998 }
10999
11000 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11001 {
11002 struct ast_vm_user svm;
11003 AST_DECLARE_APP_ARGS(arg,
11004 AST_APP_ARG(mbox);
11005 AST_APP_ARG(context);
11006 );
11007
11008 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11009
11010 if (ast_strlen_zero(arg.mbox)) {
11011 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11012 return -1;
11013 }
11014
11015 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11016 return 0;
11017 }
11018
11019 static struct ast_custom_function mailbox_exists_acf = {
11020 .name = "MAILBOX_EXISTS",
11021 .read = acf_mailbox_exists,
11022 };
11023
11024 static int vmauthenticate(struct ast_channel *chan, const char *data)
11025 {
11026 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11027 struct ast_vm_user vmus;
11028 char *options = NULL;
11029 int silent = 0, skipuser = 0;
11030 int res = -1;
11031
11032 if (data) {
11033 s = ast_strdupa(data);
11034 user = strsep(&s, ",");
11035 options = strsep(&s, ",");
11036 if (user) {
11037 s = user;
11038 user = strsep(&s, "@");
11039 context = strsep(&s, "");
11040 if (!ast_strlen_zero(user))
11041 skipuser++;
11042 ast_copy_string(mailbox, user, sizeof(mailbox));
11043 }
11044 }
11045
11046 if (options) {
11047 silent = (strchr(options, 's')) != NULL;
11048 }
11049
11050 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11051 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11052 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11053 ast_play_and_wait(chan, "auth-thankyou");
11054 res = 0;
11055 } else if (mailbox[0] == '*') {
11056
11057 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11058 res = 0;
11059 }
11060 }
11061
11062 return res;
11063 }
11064
11065 static char *show_users_realtime(int fd, const char *context)
11066 {
11067 struct ast_config *cfg;
11068 const char *cat = NULL;
11069
11070 if (!(cfg = ast_load_realtime_multientry("voicemail",
11071 "context", context, SENTINEL))) {
11072 return CLI_FAILURE;
11073 }
11074
11075 ast_cli(fd,
11076 "\n"
11077 "=============================================================\n"
11078 "=== Configured Voicemail Users ==============================\n"
11079 "=============================================================\n"
11080 "===\n");
11081
11082 while ((cat = ast_category_browse(cfg, cat))) {
11083 struct ast_variable *var = NULL;
11084 ast_cli(fd,
11085 "=== Mailbox ...\n"
11086 "===\n");
11087 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11088 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11089 ast_cli(fd,
11090 "===\n"
11091 "=== ---------------------------------------------------------\n"
11092 "===\n");
11093 }
11094
11095 ast_cli(fd,
11096 "=============================================================\n"
11097 "\n");
11098
11099 ast_config_destroy(cfg);
11100
11101 return CLI_SUCCESS;
11102 }
11103
11104 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11105 {
11106 int which = 0;
11107 int wordlen;
11108 struct ast_vm_user *vmu;
11109 const char *context = "";
11110
11111
11112 if (pos > 4)
11113 return NULL;
11114 if (pos == 3)
11115 return (state == 0) ? ast_strdup("for") : NULL;
11116 wordlen = strlen(word);
11117 AST_LIST_TRAVERSE(&users, vmu, list) {
11118 if (!strncasecmp(word, vmu->context, wordlen)) {
11119 if (context && strcmp(context, vmu->context) && ++which > state)
11120 return ast_strdup(vmu->context);
11121
11122 context = vmu->context;
11123 }
11124 }
11125 return NULL;
11126 }
11127
11128
11129 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11130 {
11131 struct ast_vm_user *vmu;
11132 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11133 const char *context = NULL;
11134 int users_counter = 0;
11135
11136 switch (cmd) {
11137 case CLI_INIT:
11138 e->command = "voicemail show users";
11139 e->usage =
11140 "Usage: voicemail show users [for <context>]\n"
11141 " Lists all mailboxes currently set up\n";
11142 return NULL;
11143 case CLI_GENERATE:
11144 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11145 }
11146
11147 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11148 return CLI_SHOWUSAGE;
11149 if (a->argc == 5) {
11150 if (strcmp(a->argv[3],"for"))
11151 return CLI_SHOWUSAGE;
11152 context = a->argv[4];
11153 }
11154
11155 if (ast_check_realtime("voicemail")) {
11156 if (!context) {
11157 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11158 return CLI_SHOWUSAGE;
11159 }
11160 return show_users_realtime(a->fd, context);
11161 }
11162
11163 AST_LIST_LOCK(&users);
11164 if (AST_LIST_EMPTY(&users)) {
11165 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11166 AST_LIST_UNLOCK(&users);
11167 return CLI_FAILURE;
11168 }
11169 if (a->argc == 3)
11170 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11171 else {
11172 int count = 0;
11173 AST_LIST_TRAVERSE(&users, vmu, list) {
11174 if (!strcmp(context, vmu->context))
11175 count++;
11176 }
11177 if (count) {
11178 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11179 } else {
11180 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11181 AST_LIST_UNLOCK(&users);
11182 return CLI_FAILURE;
11183 }
11184 }
11185 AST_LIST_TRAVERSE(&users, vmu, list) {
11186 int newmsgs = 0, oldmsgs = 0;
11187 char count[12], tmp[256] = "";
11188
11189 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
11190 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11191 inboxcount(tmp, &newmsgs, &oldmsgs);
11192 snprintf(count, sizeof(count), "%d", newmsgs);
11193 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11194 users_counter++;
11195 }
11196 }
11197 AST_LIST_UNLOCK(&users);
11198 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11199 return CLI_SUCCESS;
11200 }
11201
11202
11203 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11204 {
11205 struct vm_zone *zone;
11206 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11207 char *res = CLI_SUCCESS;
11208
11209 switch (cmd) {
11210 case CLI_INIT:
11211 e->command = "voicemail show zones";
11212 e->usage =
11213 "Usage: voicemail show zones\n"
11214 " Lists zone message formats\n";
11215 return NULL;
11216 case CLI_GENERATE:
11217 return NULL;
11218 }
11219
11220 if (a->argc != 3)
11221 return CLI_SHOWUSAGE;
11222
11223 AST_LIST_LOCK(&zones);
11224 if (!AST_LIST_EMPTY(&zones)) {
11225 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11226 AST_LIST_TRAVERSE(&zones, zone, list) {
11227 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11228 }
11229 } else {
11230 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11231 res = CLI_FAILURE;
11232 }
11233 AST_LIST_UNLOCK(&zones);
11234
11235 return res;
11236 }
11237
11238
11239 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11240 {
11241 switch (cmd) {
11242 case CLI_INIT:
11243 e->command = "voicemail reload";
11244 e->usage =
11245 "Usage: voicemail reload\n"
11246 " Reload voicemail configuration\n";
11247 return NULL;
11248 case CLI_GENERATE:
11249 return NULL;
11250 }
11251
11252 if (a->argc != 2)
11253 return CLI_SHOWUSAGE;
11254
11255 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11256 load_config(1);
11257
11258 return CLI_SUCCESS;
11259 }
11260
11261 static struct ast_cli_entry cli_voicemail[] = {
11262 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11263 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11264 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11265 };
11266
11267 #ifdef IMAP_STORAGE
11268 #define DATA_EXPORT_VM_USERS(USER) \
11269 USER(ast_vm_user, context, AST_DATA_STRING) \
11270 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11271 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11272 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11273 USER(ast_vm_user, email, AST_DATA_STRING) \
11274 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11275 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11276 USER(ast_vm_user, pager, AST_DATA_STRING) \
11277 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11278 USER(ast_vm_user, mailcmd, 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, mailcmd, AST_DATA_STRING) \
11307 USER(ast_vm_user, language, AST_DATA_STRING) \
11308 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11309 USER(ast_vm_user, callback, AST_DATA_STRING) \
11310 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11311 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11312 USER(ast_vm_user, exit, AST_DATA_STRING) \
11313 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11314 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11315 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11316 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11317 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11318 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11319 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11320 #endif
11321
11322 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11323
11324 #define DATA_EXPORT_VM_ZONES(ZONE) \
11325 ZONE(vm_zone, name, AST_DATA_STRING) \
11326 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11327 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11328
11329 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11330
11331
11332
11333
11334
11335
11336
11337
11338 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11339 struct ast_data *data_root, struct ast_vm_user *user)
11340 {
11341 struct ast_data *data_user, *data_zone;
11342 struct ast_data *data_state;
11343 struct vm_zone *zone = NULL;
11344 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11345 char ext_context[256] = "";
11346
11347 data_user = ast_data_add_node(data_root, "user");
11348 if (!data_user) {
11349 return -1;
11350 }
11351
11352 ast_data_add_structure(ast_vm_user, data_user, user);
11353
11354 AST_LIST_LOCK(&zones);
11355 AST_LIST_TRAVERSE(&zones, zone, list) {
11356 if (!strcmp(zone->name, user->zonetag)) {
11357 break;
11358 }
11359 }
11360 AST_LIST_UNLOCK(&zones);
11361
11362
11363 data_state = ast_data_add_node(data_user, "state");
11364 if (!data_state) {
11365 return -1;
11366 }
11367 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11368 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11369 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11370 ast_data_add_int(data_state, "newmsg", newmsg);
11371 ast_data_add_int(data_state, "oldmsg", oldmsg);
11372
11373 if (zone) {
11374 data_zone = ast_data_add_node(data_user, "zone");
11375 ast_data_add_structure(vm_zone, data_zone, zone);
11376 }
11377
11378 if (!ast_data_search_match(search, data_user)) {
11379 ast_data_remove_node(data_root, data_user);
11380 }
11381
11382 return 0;
11383 }
11384
11385 static int vm_users_data_provider_get(const struct ast_data_search *search,
11386 struct ast_data *data_root)
11387 {
11388 struct ast_vm_user *user;
11389
11390 AST_LIST_LOCK(&users);
11391 AST_LIST_TRAVERSE(&users, user, list) {
11392 vm_users_data_provider_get_helper(search, data_root, user);
11393 }
11394 AST_LIST_UNLOCK(&users);
11395
11396 return 0;
11397 }
11398
11399 static const struct ast_data_handler vm_users_data_provider = {
11400 .version = AST_DATA_HANDLER_VERSION,
11401 .get = vm_users_data_provider_get
11402 };
11403
11404 static const struct ast_data_entry vm_data_providers[] = {
11405 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11406 };
11407
11408 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11409 {
11410 int new = 0, old = 0, urgent = 0;
11411
11412 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11413
11414 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11415 mwi_sub->old_urgent = urgent;
11416 mwi_sub->old_new = new;
11417 mwi_sub->old_old = old;
11418 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11419 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11420 }
11421 }
11422
11423 static void poll_subscribed_mailboxes(void)
11424 {
11425 struct mwi_sub *mwi_sub;
11426
11427 AST_RWLIST_RDLOCK(&mwi_subs);
11428 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11429 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11430 poll_subscribed_mailbox(mwi_sub);
11431 }
11432 }
11433 AST_RWLIST_UNLOCK(&mwi_subs);
11434 }
11435
11436 static void *mb_poll_thread(void *data)
11437 {
11438 while (poll_thread_run) {
11439 struct timespec ts = { 0, };
11440 struct timeval wait;
11441
11442 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11443 ts.tv_sec = wait.tv_sec;
11444 ts.tv_nsec = wait.tv_usec * 1000;
11445
11446 ast_mutex_lock(&poll_lock);
11447 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11448 ast_mutex_unlock(&poll_lock);
11449
11450 if (!poll_thread_run)
11451 break;
11452
11453 poll_subscribed_mailboxes();
11454 }
11455
11456 return NULL;
11457 }
11458
11459 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11460 {
11461 ast_free(mwi_sub);
11462 }
11463
11464 static int handle_unsubscribe(void *datap)
11465 {
11466 struct mwi_sub *mwi_sub;
11467 uint32_t *uniqueid = datap;
11468
11469 AST_RWLIST_WRLOCK(&mwi_subs);
11470 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11471 if (mwi_sub->uniqueid == *uniqueid) {
11472 AST_LIST_REMOVE_CURRENT(entry);
11473 break;
11474 }
11475 }
11476 AST_RWLIST_TRAVERSE_SAFE_END
11477 AST_RWLIST_UNLOCK(&mwi_subs);
11478
11479 if (mwi_sub)
11480 mwi_sub_destroy(mwi_sub);
11481
11482 ast_free(uniqueid);
11483 return 0;
11484 }
11485
11486 static int handle_subscribe(void *datap)
11487 {
11488 unsigned int len;
11489 struct mwi_sub *mwi_sub;
11490 struct mwi_sub_task *p = datap;
11491
11492 len = sizeof(*mwi_sub);
11493 if (!ast_strlen_zero(p->mailbox))
11494 len += strlen(p->mailbox);
11495
11496 if (!ast_strlen_zero(p->context))
11497 len += strlen(p->context) + 1;
11498
11499 if (!(mwi_sub = ast_calloc(1, len)))
11500 return -1;
11501
11502 mwi_sub->uniqueid = p->uniqueid;
11503 if (!ast_strlen_zero(p->mailbox))
11504 strcpy(mwi_sub->mailbox, p->mailbox);
11505
11506 if (!ast_strlen_zero(p->context)) {
11507 strcat(mwi_sub->mailbox, "@");
11508 strcat(mwi_sub->mailbox, p->context);
11509 }
11510
11511 AST_RWLIST_WRLOCK(&mwi_subs);
11512 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11513 AST_RWLIST_UNLOCK(&mwi_subs);
11514 ast_free((void *) p->mailbox);
11515 ast_free((void *) p->context);
11516 ast_free(p);
11517 poll_subscribed_mailbox(mwi_sub);
11518 return 0;
11519 }
11520
11521 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11522 {
11523 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11524 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11525 return;
11526
11527 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11528 return;
11529
11530 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11531 *uniqueid = u;
11532 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11533 ast_free(uniqueid);
11534 }
11535 }
11536
11537 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11538 {
11539 struct mwi_sub_task *mwist;
11540
11541 if (ast_event_get_type(event) != AST_EVENT_SUB)
11542 return;
11543
11544 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11545 return;
11546
11547 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11548 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11549 return;
11550 }
11551 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11552 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11553 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11554
11555 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11556 ast_free(mwist);
11557 }
11558 }
11559
11560 static void start_poll_thread(void)
11561 {
11562 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11563 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11564 AST_EVENT_IE_END);
11565
11566 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11567 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11568 AST_EVENT_IE_END);
11569
11570 if (mwi_sub_sub)
11571 ast_event_report_subs(mwi_sub_sub);
11572
11573 poll_thread_run = 1;
11574
11575 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11576 }
11577
11578 static void stop_poll_thread(void)
11579 {
11580 poll_thread_run = 0;
11581
11582 if (mwi_sub_sub) {
11583 ast_event_unsubscribe(mwi_sub_sub);
11584 mwi_sub_sub = NULL;
11585 }
11586
11587 if (mwi_unsub_sub) {
11588 ast_event_unsubscribe(mwi_unsub_sub);
11589 mwi_unsub_sub = NULL;
11590 }
11591
11592 ast_mutex_lock(&poll_lock);
11593 ast_cond_signal(&poll_cond);
11594 ast_mutex_unlock(&poll_lock);
11595
11596 pthread_join(poll_thread, NULL);
11597
11598 poll_thread = AST_PTHREADT_NULL;
11599 }
11600
11601
11602 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11603 {
11604 struct ast_vm_user *vmu = NULL;
11605 const char *id = astman_get_header(m, "ActionID");
11606 char actionid[128] = "";
11607
11608 if (!ast_strlen_zero(id))
11609 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11610
11611 AST_LIST_LOCK(&users);
11612
11613 if (AST_LIST_EMPTY(&users)) {
11614 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11615 AST_LIST_UNLOCK(&users);
11616 return RESULT_SUCCESS;
11617 }
11618
11619 astman_send_ack(s, m, "Voicemail user list will follow");
11620
11621 AST_LIST_TRAVERSE(&users, vmu, list) {
11622 char dirname[256];
11623
11624 #ifdef IMAP_STORAGE
11625 int new, old;
11626 inboxcount(vmu->mailbox, &new, &old);
11627 #endif
11628
11629 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11630 astman_append(s,
11631 "%s"
11632 "Event: VoicemailUserEntry\r\n"
11633 "VMContext: %s\r\n"
11634 "VoiceMailbox: %s\r\n"
11635 "Fullname: %s\r\n"
11636 "Email: %s\r\n"
11637 "Pager: %s\r\n"
11638 "ServerEmail: %s\r\n"
11639 "MailCommand: %s\r\n"
11640 "Language: %s\r\n"
11641 "TimeZone: %s\r\n"
11642 "Callback: %s\r\n"
11643 "Dialout: %s\r\n"
11644 "UniqueID: %s\r\n"
11645 "ExitContext: %s\r\n"
11646 "SayDurationMinimum: %d\r\n"
11647 "SayEnvelope: %s\r\n"
11648 "SayCID: %s\r\n"
11649 "AttachMessage: %s\r\n"
11650 "AttachmentFormat: %s\r\n"
11651 "DeleteMessage: %s\r\n"
11652 "VolumeGain: %.2f\r\n"
11653 "CanReview: %s\r\n"
11654 "CallOperator: %s\r\n"
11655 "MaxMessageCount: %d\r\n"
11656 "MaxMessageLength: %d\r\n"
11657 "NewMessageCount: %d\r\n"
11658 #ifdef IMAP_STORAGE
11659 "OldMessageCount: %d\r\n"
11660 "IMAPUser: %s\r\n"
11661 #endif
11662 "\r\n",
11663 actionid,
11664 vmu->context,
11665 vmu->mailbox,
11666 vmu->fullname,
11667 vmu->email,
11668 vmu->pager,
11669 vmu->serveremail,
11670 vmu->mailcmd,
11671 vmu->language,
11672 vmu->zonetag,
11673 vmu->callback,
11674 vmu->dialout,
11675 vmu->uniqueid,
11676 vmu->exit,
11677 vmu->saydurationm,
11678 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11679 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11680 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11681 vmu->attachfmt,
11682 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11683 vmu->volgain,
11684 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11685 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11686 vmu->maxmsg,
11687 vmu->maxsecs,
11688 #ifdef IMAP_STORAGE
11689 new, old, vmu->imapuser
11690 #else
11691 count_messages(vmu, dirname)
11692 #endif
11693 );
11694 }
11695 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11696
11697 AST_LIST_UNLOCK(&users);
11698
11699 return RESULT_SUCCESS;
11700 }
11701
11702
11703 static void free_vm_users(void)
11704 {
11705 struct ast_vm_user *current;
11706 AST_LIST_LOCK(&users);
11707 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11708 ast_set_flag(current, VM_ALLOCED);
11709 free_user(current);
11710 }
11711 AST_LIST_UNLOCK(&users);
11712 }
11713
11714
11715 static void free_vm_zones(void)
11716 {
11717 struct vm_zone *zcur;
11718 AST_LIST_LOCK(&zones);
11719 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11720 free_zone(zcur);
11721 AST_LIST_UNLOCK(&zones);
11722 }
11723
11724 static const char *substitute_escapes(const char *value)
11725 {
11726 char *current;
11727
11728
11729 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11730
11731 ast_str_reset(str);
11732
11733
11734 for (current = (char *) value; *current; current++) {
11735 if (*current == '\\') {
11736 current++;
11737 if (!*current) {
11738 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11739 break;
11740 }
11741 switch (*current) {
11742 case '\\':
11743 ast_str_append(&str, 0, "\\");
11744 break;
11745 case 'r':
11746 ast_str_append(&str, 0, "\r");
11747 break;
11748 case 'n':
11749 #ifdef IMAP_STORAGE
11750 if (!str->used || str->str[str->used - 1] != '\r') {
11751 ast_str_append(&str, 0, "\r");
11752 }
11753 #endif
11754 ast_str_append(&str, 0, "\n");
11755 break;
11756 case 't':
11757 ast_str_append(&str, 0, "\t");
11758 break;
11759 default:
11760 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11761 break;
11762 }
11763 } else {
11764 ast_str_append(&str, 0, "%c", *current);
11765 }
11766 }
11767
11768 return ast_str_buffer(str);
11769 }
11770
11771 static int load_config(int reload)
11772 {
11773 struct ast_config *cfg, *ucfg;
11774 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11775 int res;
11776
11777 ast_unload_realtime("voicemail");
11778 ast_unload_realtime("voicemail_data");
11779
11780 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11781 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11782 return 0;
11783 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11784 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11785 ucfg = NULL;
11786 }
11787 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11788 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11789 ast_config_destroy(ucfg);
11790 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11791 return 0;
11792 }
11793 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11794 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11795 return 0;
11796 } else {
11797 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11798 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11799 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11800 ucfg = NULL;
11801 }
11802 }
11803
11804 res = actual_load_config(reload, cfg, ucfg);
11805
11806 ast_config_destroy(cfg);
11807 ast_config_destroy(ucfg);
11808
11809 return res;
11810 }
11811
11812 #ifdef TEST_FRAMEWORK
11813 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11814 {
11815 ast_unload_realtime("voicemail");
11816 ast_unload_realtime("voicemail_data");
11817 return actual_load_config(reload, cfg, ucfg);
11818 }
11819 #endif
11820
11821 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11822 {
11823 struct ast_vm_user *current;
11824 char *cat;
11825 struct ast_variable *var;
11826 const char *val;
11827 char *q, *stringp, *tmp;
11828 int x;
11829 int tmpadsi[4];
11830 char secretfn[PATH_MAX] = "";
11831
11832 #ifdef IMAP_STORAGE
11833 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11834 #endif
11835
11836 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11837 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11838 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11839 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11840 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11841
11842
11843 free_vm_users();
11844
11845
11846 free_vm_zones();
11847
11848 AST_LIST_LOCK(&users);
11849
11850 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11851 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11852
11853 if (cfg) {
11854
11855
11856 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11857 val = "default";
11858 ast_copy_string(userscontext, val, sizeof(userscontext));
11859
11860 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11861 val = "yes";
11862 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11863
11864 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11865 val = "no";
11866 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11867
11868 volgain = 0.0;
11869 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11870 sscanf(val, "%30lf", &volgain);
11871
11872 #ifdef ODBC_STORAGE
11873 strcpy(odbc_database, "asterisk");
11874 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11875 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11876 }
11877 strcpy(odbc_table, "voicemessages");
11878 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11879 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11880 }
11881 #endif
11882
11883 strcpy(mailcmd, SENDMAIL);
11884 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11885 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11886
11887 maxsilence = 0;
11888 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11889 maxsilence = atoi(val);
11890 if (maxsilence > 0)
11891 maxsilence *= 1000;
11892 }
11893
11894 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11895 maxmsg = MAXMSG;
11896 } else {
11897 maxmsg = atoi(val);
11898 if (maxmsg < 0) {
11899 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11900 maxmsg = MAXMSG;
11901 } else if (maxmsg > MAXMSGLIMIT) {
11902 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11903 maxmsg = MAXMSGLIMIT;
11904 }
11905 }
11906
11907 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11908 maxdeletedmsg = 0;
11909 } else {
11910 if (sscanf(val, "%30d", &x) == 1)
11911 maxdeletedmsg = x;
11912 else if (ast_true(val))
11913 maxdeletedmsg = MAXMSG;
11914 else
11915 maxdeletedmsg = 0;
11916
11917 if (maxdeletedmsg < 0) {
11918 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11919 maxdeletedmsg = MAXMSG;
11920 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11921 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11922 maxdeletedmsg = MAXMSGLIMIT;
11923 }
11924 }
11925
11926
11927 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11928 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11929 }
11930
11931
11932 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11933 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11934 }
11935
11936
11937 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11938 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11939 pwdchange = PWDCHANGE_EXTERNAL;
11940 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11941 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11942 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11943 }
11944
11945
11946 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11947 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11948 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11949 }
11950
11951 #ifdef IMAP_STORAGE
11952
11953 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11954 ast_copy_string(imapserver, val, sizeof(imapserver));
11955 } else {
11956 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11957 }
11958
11959 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11960 ast_copy_string(imapport, val, sizeof(imapport));
11961 } else {
11962 ast_copy_string(imapport, "143", sizeof(imapport));
11963 }
11964
11965 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11966 ast_copy_string(imapflags, val, sizeof(imapflags));
11967 }
11968
11969 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11970 ast_copy_string(authuser, val, sizeof(authuser));
11971 }
11972
11973 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11974 ast_copy_string(authpassword, val, sizeof(authpassword));
11975 }
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11978 if (ast_false(val))
11979 expungeonhangup = 0;
11980 else
11981 expungeonhangup = 1;
11982 } else {
11983 expungeonhangup = 1;
11984 }
11985
11986 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11987 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11988 } else {
11989 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11990 }
11991 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11992 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11993 }
11994 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11995 imapgreetings = ast_true(val);
11996 } else {
11997 imapgreetings = 0;
11998 }
11999 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12000 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12001 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12002
12003 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12004 } else {
12005 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12006 }
12007
12008
12009
12010
12011
12012 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12013 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12014 } else {
12015 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12016 }
12017
12018 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12019 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12020 } else {
12021 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12022 }
12023
12024 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12025 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12026 } else {
12027 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12028 }
12029
12030 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12031 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12032 } else {
12033 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12034 }
12035
12036
12037 imapversion++;
12038 #endif
12039
12040 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12041 ast_copy_string(externnotify, val, sizeof(externnotify));
12042 ast_debug(1, "found externnotify: %s\n", externnotify);
12043 } else {
12044 externnotify[0] = '\0';
12045 }
12046
12047
12048 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12049 ast_debug(1, "Enabled SMDI voicemail notification\n");
12050 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12051 smdi_iface = ast_smdi_interface_find(val);
12052 } else {
12053 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12054 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12055 }
12056 if (!smdi_iface) {
12057 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12058 }
12059 }
12060
12061
12062 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12063 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12064 silencethreshold = atoi(val);
12065
12066 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12067 val = ASTERISK_USERNAME;
12068 ast_copy_string(serveremail, val, sizeof(serveremail));
12069
12070 vmmaxsecs = 0;
12071 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12072 if (sscanf(val, "%30d", &x) == 1) {
12073 vmmaxsecs = x;
12074 } else {
12075 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12076 }
12077 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12078 static int maxmessage_deprecate = 0;
12079 if (maxmessage_deprecate == 0) {
12080 maxmessage_deprecate = 1;
12081 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12082 }
12083 if (sscanf(val, "%30d", &x) == 1) {
12084 vmmaxsecs = x;
12085 } else {
12086 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12087 }
12088 }
12089
12090 vmminsecs = 0;
12091 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12092 if (sscanf(val, "%30d", &x) == 1) {
12093 vmminsecs = x;
12094 if (maxsilence / 1000 >= vmminsecs) {
12095 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12096 }
12097 } else {
12098 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12099 }
12100 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12101 static int maxmessage_deprecate = 0;
12102 if (maxmessage_deprecate == 0) {
12103 maxmessage_deprecate = 1;
12104 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12105 }
12106 if (sscanf(val, "%30d", &x) == 1) {
12107 vmminsecs = x;
12108 if (maxsilence / 1000 >= vmminsecs) {
12109 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12110 }
12111 } else {
12112 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12113 }
12114 }
12115
12116 val = ast_variable_retrieve(cfg, "general", "format");
12117 if (!val) {
12118 val = "wav";
12119 } else {
12120 tmp = ast_strdupa(val);
12121 val = ast_format_str_reduce(tmp);
12122 if (!val) {
12123 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12124 val = "wav";
12125 }
12126 }
12127 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12128
12129 skipms = 3000;
12130 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12131 if (sscanf(val, "%30d", &x) == 1) {
12132 maxgreet = x;
12133 } else {
12134 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12135 }
12136 }
12137
12138 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12139 if (sscanf(val, "%30d", &x) == 1) {
12140 skipms = x;
12141 } else {
12142 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12143 }
12144 }
12145
12146 maxlogins = 3;
12147 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12148 if (sscanf(val, "%30d", &x) == 1) {
12149 maxlogins = x;
12150 } else {
12151 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12152 }
12153 }
12154
12155 minpassword = MINPASSWORD;
12156 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12157 if (sscanf(val, "%30d", &x) == 1) {
12158 minpassword = x;
12159 } else {
12160 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12161 }
12162 }
12163
12164
12165 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12166 val = "no";
12167 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12168
12169
12170 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12171 val = "no";
12172 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12173
12174 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12175 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12176 stringp = ast_strdupa(val);
12177 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12178 if (!ast_strlen_zero(stringp)) {
12179 q = strsep(&stringp, ",");
12180 while ((*q == ' ')||(*q == '\t'))
12181 q++;
12182 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12183 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12184 } else {
12185 cidinternalcontexts[x][0] = '\0';
12186 }
12187 }
12188 }
12189 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12190 ast_debug(1, "VM Review Option disabled globally\n");
12191 val = "no";
12192 }
12193 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12194
12195
12196 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12197 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12198 val = "no";
12199 } else {
12200 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12201 }
12202 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12203 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12204 ast_debug(1, "VM next message wrap disabled globally\n");
12205 val = "no";
12206 }
12207 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12208
12209 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12210 ast_debug(1, "VM Operator break disabled globally\n");
12211 val = "no";
12212 }
12213 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12214
12215 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12216 ast_debug(1, "VM CID Info before msg disabled globally\n");
12217 val = "no";
12218 }
12219 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12220
12221 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12222 ast_debug(1, "Send Voicemail msg disabled globally\n");
12223 val = "no";
12224 }
12225 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12226
12227 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12228 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12229 val = "yes";
12230 }
12231 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12232
12233 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12234 ast_debug(1, "Move Heard enabled globally\n");
12235 val = "yes";
12236 }
12237 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12238
12239 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12240 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12241 val = "no";
12242 }
12243 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12244
12245 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12246 ast_debug(1, "Duration info before msg enabled globally\n");
12247 val = "yes";
12248 }
12249 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12250
12251 saydurationminfo = 2;
12252 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12253 if (sscanf(val, "%30d", &x) == 1) {
12254 saydurationminfo = x;
12255 } else {
12256 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12257 }
12258 }
12259
12260 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12261 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12262 val = "no";
12263 }
12264 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12265
12266 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12267 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12268 ast_debug(1, "found dialout context: %s\n", dialcontext);
12269 } else {
12270 dialcontext[0] = '\0';
12271 }
12272
12273 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12274 ast_copy_string(callcontext, val, sizeof(callcontext));
12275 ast_debug(1, "found callback context: %s\n", callcontext);
12276 } else {
12277 callcontext[0] = '\0';
12278 }
12279
12280 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12281 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12282 ast_debug(1, "found operator context: %s\n", exitcontext);
12283 } else {
12284 exitcontext[0] = '\0';
12285 }
12286
12287
12288 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12289 ast_copy_string(vm_password, val, sizeof(vm_password));
12290 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12291 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12292 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12293 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12294 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12295 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12296 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12297 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12298 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12299 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12300 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12301 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12302 }
12303 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12304 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12305 }
12306
12307 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12308 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12309 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12310 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12311 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12312 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12313 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12314 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12315 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12316 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12317
12318 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12319 val = "no";
12320 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12321
12322 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12323 val = "voicemail.conf";
12324 }
12325 if (!(strcmp(val, "spooldir"))) {
12326 passwordlocation = OPT_PWLOC_SPOOLDIR;
12327 } else {
12328 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12329 }
12330
12331 poll_freq = DEFAULT_POLL_FREQ;
12332 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12333 if (sscanf(val, "%30u", &poll_freq) != 1) {
12334 poll_freq = DEFAULT_POLL_FREQ;
12335 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12336 }
12337 }
12338
12339 poll_mailboxes = 0;
12340 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12341 poll_mailboxes = ast_true(val);
12342
12343 memset(fromstring, 0, sizeof(fromstring));
12344 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12345 strcpy(charset, "ISO-8859-1");
12346 if (emailbody) {
12347 ast_free(emailbody);
12348 emailbody = NULL;
12349 }
12350 if (emailsubject) {
12351 ast_free(emailsubject);
12352 emailsubject = NULL;
12353 }
12354 if (pagerbody) {
12355 ast_free(pagerbody);
12356 pagerbody = NULL;
12357 }
12358 if (pagersubject) {
12359 ast_free(pagersubject);
12360 pagersubject = NULL;
12361 }
12362 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12363 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12364 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12365 ast_copy_string(fromstring, val, sizeof(fromstring));
12366 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12367 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12368 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12369 ast_copy_string(charset, val, sizeof(charset));
12370 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12371 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12372 for (x = 0; x < 4; x++) {
12373 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12374 }
12375 }
12376 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12377 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12378 for (x = 0; x < 4; x++) {
12379 memcpy(&adsisec[x], &tmpadsi[x], 1);
12380 }
12381 }
12382 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12383 if (atoi(val)) {
12384 adsiver = atoi(val);
12385 }
12386 }
12387 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12388 ast_copy_string(zonetag, val, sizeof(zonetag));
12389 }
12390 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12391 ast_copy_string(locale, val, sizeof(locale));
12392 }
12393 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12394 emailsubject = ast_strdup(substitute_escapes(val));
12395 }
12396 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12397 emailbody = ast_strdup(substitute_escapes(val));
12398 }
12399 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12400 pagersubject = ast_strdup(substitute_escapes(val));
12401 }
12402 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12403 pagerbody = ast_strdup(substitute_escapes(val));
12404 }
12405
12406
12407 if (ucfg) {
12408 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12409 if (!strcasecmp(cat, "general")) {
12410 continue;
12411 }
12412 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12413 continue;
12414 if ((current = find_or_create(userscontext, cat))) {
12415 populate_defaults(current);
12416 apply_options_full(current, ast_variable_browse(ucfg, cat));
12417 ast_copy_string(current->context, userscontext, sizeof(current->context));
12418 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12419 current->passwordlocation = OPT_PWLOC_USERSCONF;
12420 }
12421
12422 switch (current->passwordlocation) {
12423 case OPT_PWLOC_SPOOLDIR:
12424 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12425 read_password_from_file(secretfn, current->password, sizeof(current->password));
12426 }
12427 }
12428 }
12429 }
12430
12431
12432 cat = ast_category_browse(cfg, NULL);
12433 while (cat) {
12434 if (strcasecmp(cat, "general")) {
12435 var = ast_variable_browse(cfg, cat);
12436 if (strcasecmp(cat, "zonemessages")) {
12437
12438 while (var) {
12439 append_mailbox(cat, var->name, var->value);
12440 var = var->next;
12441 }
12442 } else {
12443
12444 while (var) {
12445 struct vm_zone *z;
12446 if ((z = ast_malloc(sizeof(*z)))) {
12447 char *msg_format, *tzone;
12448 msg_format = ast_strdupa(var->value);
12449 tzone = strsep(&msg_format, "|,");
12450 if (msg_format) {
12451 ast_copy_string(z->name, var->name, sizeof(z->name));
12452 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12453 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12454 AST_LIST_LOCK(&zones);
12455 AST_LIST_INSERT_HEAD(&zones, z, list);
12456 AST_LIST_UNLOCK(&zones);
12457 } else {
12458 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12459 ast_free(z);
12460 }
12461 } else {
12462 AST_LIST_UNLOCK(&users);
12463 return -1;
12464 }
12465 var = var->next;
12466 }
12467 }
12468 }
12469 cat = ast_category_browse(cfg, cat);
12470 }
12471
12472 AST_LIST_UNLOCK(&users);
12473
12474 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12475 start_poll_thread();
12476 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12477 stop_poll_thread();;
12478
12479 return 0;
12480 } else {
12481 AST_LIST_UNLOCK(&users);
12482 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12483 return 0;
12484 }
12485 }
12486
12487 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12488 {
12489 int res = -1;
12490 char dir[PATH_MAX];
12491 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12492 ast_debug(2, "About to try retrieving name file %s\n", dir);
12493 RETRIEVE(dir, -1, mailbox, context);
12494 if (ast_fileexists(dir, NULL, NULL)) {
12495 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12496 }
12497 DISPOSE(dir, -1);
12498 return res;
12499 }
12500
12501 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12502 struct ast_config *pwconf;
12503 struct ast_flags config_flags = { 0 };
12504
12505 pwconf = ast_config_load(secretfn, config_flags);
12506 if (pwconf) {
12507 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12508 if (val) {
12509 ast_copy_string(password, val, passwordlen);
12510 return;
12511 }
12512 }
12513 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12514 }
12515
12516 static int write_password_to_file(const char *secretfn, const char *password) {
12517 struct ast_config *conf;
12518 struct ast_category *cat;
12519 struct ast_variable *var;
12520
12521 if (!(conf=ast_config_new())) {
12522 ast_log(LOG_ERROR, "Error creating new config structure\n");
12523 return -1;
12524 }
12525 if (!(cat=ast_category_new("general","",1))) {
12526 ast_log(LOG_ERROR, "Error creating new category structure\n");
12527 return -1;
12528 }
12529 if (!(var=ast_variable_new("password",password,""))) {
12530 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12531 return -1;
12532 }
12533 ast_category_append(conf,cat);
12534 ast_variable_append(cat,var);
12535 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12536 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12537 return -1;
12538 }
12539 return 0;
12540 }
12541
12542 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12543 {
12544 char *context;
12545 char *args_copy;
12546 int res;
12547
12548 if (ast_strlen_zero(data)) {
12549 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12550 return -1;
12551 }
12552
12553 args_copy = ast_strdupa(data);
12554 if ((context = strchr(args_copy, '@'))) {
12555 *context++ = '\0';
12556 } else {
12557 context = "default";
12558 }
12559
12560 if ((res = sayname(chan, args_copy, context) < 0)) {
12561 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12562 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12563 if (!res) {
12564 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12565 }
12566 }
12567
12568 return res;
12569 }
12570
12571 #ifdef TEST_FRAMEWORK
12572 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12573 {
12574 return 0;
12575 }
12576
12577 static struct ast_frame *fake_read(struct ast_channel *ast)
12578 {
12579 return &ast_null_frame;
12580 }
12581
12582 AST_TEST_DEFINE(test_voicemail_vmsayname)
12583 {
12584 char dir[PATH_MAX];
12585 char dir2[PATH_MAX];
12586 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12587 static const char TEST_EXTENSION[] = "1234";
12588
12589 struct ast_channel *test_channel1 = NULL;
12590 int res = -1;
12591
12592 static const struct ast_channel_tech fake_tech = {
12593 .write = fake_write,
12594 .read = fake_read,
12595 };
12596
12597 switch (cmd) {
12598 case TEST_INIT:
12599 info->name = "vmsayname_exec";
12600 info->category = "/apps/app_voicemail/";
12601 info->summary = "Vmsayname unit test";
12602 info->description =
12603 "This tests passing various parameters to vmsayname";
12604 return AST_TEST_NOT_RUN;
12605 case TEST_EXECUTE:
12606 break;
12607 }
12608
12609 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12610 NULL, NULL, 0, 0, "TestChannel1"))) {
12611 goto exit_vmsayname_test;
12612 }
12613
12614
12615 test_channel1->nativeformats = AST_FORMAT_GSM;
12616 test_channel1->writeformat = AST_FORMAT_GSM;
12617 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12618 test_channel1->readformat = AST_FORMAT_GSM;
12619 test_channel1->rawreadformat = AST_FORMAT_GSM;
12620 test_channel1->tech = &fake_tech;
12621
12622 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12623 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12624 if (!(res = vmsayname_exec(test_channel1, dir))) {
12625 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12626 if (ast_fileexists(dir, NULL, NULL)) {
12627 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12628 res = -1;
12629 goto exit_vmsayname_test;
12630 } else {
12631
12632 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12633 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12634 goto exit_vmsayname_test;
12635 }
12636 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12637 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12638
12639 if ((res = symlink(dir, dir2))) {
12640 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12641 goto exit_vmsayname_test;
12642 }
12643 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12644 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12645 res = vmsayname_exec(test_channel1, dir);
12646
12647
12648 unlink(dir2);
12649 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12650 rmdir(dir2);
12651 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12652 rmdir(dir2);
12653 }
12654 }
12655
12656 exit_vmsayname_test:
12657
12658 if (test_channel1) {
12659 ast_hangup(test_channel1);
12660 }
12661
12662 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12663 }
12664
12665 AST_TEST_DEFINE(test_voicemail_msgcount)
12666 {
12667 int i, j, res = AST_TEST_PASS, syserr;
12668 struct ast_vm_user *vmu;
12669 struct vm_state vms;
12670 #ifdef IMAP_STORAGE
12671 struct ast_channel *chan = NULL;
12672 #endif
12673 struct {
12674 char dir[256];
12675 char file[256];
12676 char txtfile[256];
12677 } tmp[3];
12678 char syscmd[256];
12679 const char origweasels[] = "tt-weasels";
12680 const char testcontext[] = "test";
12681 const char testmailbox[] = "00000000";
12682 const char testspec[] = "00000000@test";
12683 FILE *txt;
12684 int new, old, urgent;
12685 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12686 const int folder2mbox[3] = { 1, 11, 0 };
12687 const int expected_results[3][12] = {
12688
12689 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12690 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12691 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12692 };
12693
12694 switch (cmd) {
12695 case TEST_INIT:
12696 info->name = "test_voicemail_msgcount";
12697 info->category = "/apps/app_voicemail/";
12698 info->summary = "Test Voicemail status checks";
12699 info->description =
12700 "Verify that message counts are correct when retrieved through the public API";
12701 return AST_TEST_NOT_RUN;
12702 case TEST_EXECUTE:
12703 break;
12704 }
12705
12706
12707 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12708 if ((syserr = ast_safe_system(syscmd))) {
12709 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12710 syserr > 0 ? strerror(syserr) : "unable to fork()");
12711 return AST_TEST_FAIL;
12712 }
12713
12714 #ifdef IMAP_STORAGE
12715 if (!(chan = ast_dummy_channel_alloc())) {
12716 ast_test_status_update(test, "Unable to create dummy channel\n");
12717 return AST_TEST_FAIL;
12718 }
12719 #endif
12720
12721 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12722 !(vmu = find_or_create(testcontext, testmailbox))) {
12723 ast_test_status_update(test, "Cannot create vmu structure\n");
12724 ast_unreplace_sigchld();
12725 #ifdef IMAP_STORAGE
12726 chan = ast_channel_unref(chan);
12727 #endif
12728 return AST_TEST_FAIL;
12729 }
12730
12731 populate_defaults(vmu);
12732 memset(&vms, 0, sizeof(vms));
12733
12734
12735 for (i = 0; i < 3; i++) {
12736 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12737 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12738 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12739
12740 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12741 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12742 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12743 if ((syserr = ast_safe_system(syscmd))) {
12744 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12745 syserr > 0 ? strerror(syserr) : "unable to fork()");
12746 ast_unreplace_sigchld();
12747 #ifdef IMAP_STORAGE
12748 chan = ast_channel_unref(chan);
12749 #endif
12750 return AST_TEST_FAIL;
12751 }
12752 }
12753
12754 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12755 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12756 fclose(txt);
12757 } else {
12758 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12759 res = AST_TEST_FAIL;
12760 break;
12761 }
12762 open_mailbox(&vms, vmu, folder2mbox[i]);
12763 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12764
12765
12766 for (j = 0; j < 3; j++) {
12767
12768 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12769 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12770 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12771 res = AST_TEST_FAIL;
12772 }
12773 }
12774
12775 new = old = urgent = 0;
12776 if (ast_app_inboxcount(testspec, &new, &old)) {
12777 ast_test_status_update(test, "inboxcount returned failure\n");
12778 res = AST_TEST_FAIL;
12779 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12780 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12781 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12782 res = AST_TEST_FAIL;
12783 }
12784
12785 new = old = urgent = 0;
12786 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12787 ast_test_status_update(test, "inboxcount2 returned failure\n");
12788 res = AST_TEST_FAIL;
12789 } else if (old != expected_results[i][6 + 0] ||
12790 urgent != expected_results[i][6 + 1] ||
12791 new != expected_results[i][6 + 2] ) {
12792 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12793 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12794 res = AST_TEST_FAIL;
12795 }
12796
12797 new = old = urgent = 0;
12798 for (j = 0; j < 3; j++) {
12799 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12800 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12801 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12802 res = AST_TEST_FAIL;
12803 }
12804 }
12805 }
12806
12807 for (i = 0; i < 3; i++) {
12808
12809
12810
12811 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12812 DISPOSE(tmp[i].dir, 0);
12813 }
12814
12815 if (vms.deleted) {
12816 ast_free(vms.deleted);
12817 }
12818 if (vms.heard) {
12819 ast_free(vms.heard);
12820 }
12821
12822 #ifdef IMAP_STORAGE
12823 chan = ast_channel_unref(chan);
12824 #endif
12825
12826
12827 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12828 if ((syserr = ast_safe_system(syscmd))) {
12829 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12830 syserr > 0 ? strerror(syserr) : "unable to fork()");
12831 }
12832
12833 return res;
12834 }
12835
12836 AST_TEST_DEFINE(test_voicemail_notify_endl)
12837 {
12838 int res = AST_TEST_PASS;
12839 char testcontext[] = "test";
12840 char testmailbox[] = "00000000";
12841 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12842 char attach[256], attach2[256];
12843 char buf[256] = "";
12844 struct ast_channel *chan = NULL;
12845 struct ast_vm_user *vmu, vmus = {
12846 .flags = 0,
12847 };
12848 FILE *file;
12849 struct {
12850 char *name;
12851 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12852 void *location;
12853 union {
12854 int intval;
12855 char *strval;
12856 } u;
12857 } test_items[] = {
12858 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12859 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12860 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12861 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12862 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12863 { "attach2", STRPTR, attach2, .u.strval = "" },
12864 { "attach", STRPTR, attach, .u.strval = "" },
12865 };
12866 int which;
12867
12868 switch (cmd) {
12869 case TEST_INIT:
12870 info->name = "test_voicemail_notify_endl";
12871 info->category = "/apps/app_voicemail/";
12872 info->summary = "Test Voicemail notification end-of-line";
12873 info->description =
12874 "Verify that notification emails use a consistent end-of-line character";
12875 return AST_TEST_NOT_RUN;
12876 case TEST_EXECUTE:
12877 break;
12878 }
12879
12880 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12881 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12882
12883 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12884 !(vmu = find_or_create(testcontext, testmailbox))) {
12885 ast_test_status_update(test, "Cannot create vmu structure\n");
12886 return AST_TEST_NOT_RUN;
12887 }
12888
12889 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12890 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12891 return AST_TEST_NOT_RUN;
12892 }
12893
12894 populate_defaults(vmu);
12895 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12896 #ifdef IMAP_STORAGE
12897
12898 #endif
12899
12900 file = tmpfile();
12901 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12902
12903 rewind(file);
12904 if (ftruncate(fileno(file), 0)) {
12905 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12906 res = AST_TEST_FAIL;
12907 break;
12908 }
12909
12910
12911 if (test_items[which].type == INT) {
12912 *((int *) test_items[which].location) = test_items[which].u.intval;
12913 } else if (test_items[which].type == FLAGVAL) {
12914 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12915 ast_clear_flag(vmu, test_items[which].u.intval);
12916 } else {
12917 ast_set_flag(vmu, test_items[which].u.intval);
12918 }
12919 } else if (test_items[which].type == STATIC) {
12920 strcpy(test_items[which].location, test_items[which].u.strval);
12921 } else if (test_items[which].type == STRPTR) {
12922 test_items[which].location = test_items[which].u.strval;
12923 }
12924
12925 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12926 rewind(file);
12927 while (fgets(buf, sizeof(buf), file)) {
12928 if (
12929 #ifdef IMAP_STORAGE
12930 buf[strlen(buf) - 2] != '\r'
12931 #else
12932 buf[strlen(buf) - 2] == '\r'
12933 #endif
12934 || buf[strlen(buf) - 1] != '\n') {
12935 res = AST_TEST_FAIL;
12936 }
12937 }
12938 }
12939 fclose(file);
12940 return res;
12941 }
12942
12943 AST_TEST_DEFINE(test_voicemail_load_config)
12944 {
12945 int res = AST_TEST_PASS;
12946 struct ast_vm_user *vmu;
12947 struct ast_config *cfg;
12948 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
12949 int fd;
12950 FILE *file;
12951 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
12952
12953 switch (cmd) {
12954 case TEST_INIT:
12955 info->name = "test_voicemail_load_config";
12956 info->category = "/apps/app_voicemail/";
12957 info->summary = "Test loading Voicemail config";
12958 info->description =
12959 "Verify that configuration is loaded consistently. "
12960 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12961 "some options were loaded after the mailboxes were instantiated, causing "
12962 "those options not to be set correctly.";
12963 return AST_TEST_NOT_RUN;
12964 case TEST_EXECUTE:
12965 break;
12966 }
12967
12968
12969 if ((fd = mkstemp(config_filename)) < 0) {
12970 return AST_TEST_FAIL;
12971 }
12972 if (!(file = fdopen(fd, "w"))) {
12973 close(fd);
12974 unlink(config_filename);
12975 return AST_TEST_FAIL;
12976 }
12977 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
12978 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
12979 fputs("00000002 => 9999,Mrs. Test\n", file);
12980 fclose(file);
12981
12982 if (!(cfg = ast_config_load(config_filename, config_flags))) {
12983 res = AST_TEST_FAIL;
12984 goto cleanup;
12985 }
12986
12987 load_config_from_memory(1, cfg, NULL);
12988 ast_config_destroy(cfg);
12989
12990 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
12991 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
12992 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
12993
12994 AST_LIST_LOCK(&users);
12995 AST_LIST_TRAVERSE(&users, vmu, list) {
12996 if (!strcmp(vmu->mailbox, "00000001")) {
12997 if (0);
12998 CHECK(vmu, callback, "othercontext")
12999 CHECK(vmu, locale, "nl_NL.UTF-8")
13000 CHECK(vmu, zonetag, "central")
13001 } else if (!strcmp(vmu->mailbox, "00000002")) {
13002 if (0);
13003 CHECK(vmu, callback, "somecontext")
13004 CHECK(vmu, locale, "de_DE.UTF-8")
13005 CHECK(vmu, zonetag, "european")
13006 }
13007 }
13008 AST_LIST_UNLOCK(&users);
13009
13010 #undef CHECK
13011
13012
13013 load_config(1);
13014
13015 cleanup:
13016 unlink(config_filename);
13017 return res;
13018 }
13019
13020 #endif
13021
13022 static int reload(void)
13023 {
13024 return load_config(1);
13025 }
13026
13027 static int unload_module(void)
13028 {
13029 int res;
13030
13031 res = ast_unregister_application(app);
13032 res |= ast_unregister_application(app2);
13033 res |= ast_unregister_application(app3);
13034 res |= ast_unregister_application(app4);
13035 res |= ast_unregister_application(sayname_app);
13036 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13037 res |= ast_manager_unregister("VoicemailUsersList");
13038 res |= ast_data_unregister(NULL);
13039 #ifdef TEST_FRAMEWORK
13040 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13041 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13042 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13043 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13044 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13045 #endif
13046 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13047 ast_uninstall_vm_functions();
13048 ao2_ref(inprocess_container, -1);
13049
13050 if (poll_thread != AST_PTHREADT_NULL)
13051 stop_poll_thread();
13052
13053 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13054 ast_unload_realtime("voicemail");
13055 ast_unload_realtime("voicemail_data");
13056
13057 free_vm_users();
13058 free_vm_zones();
13059 return res;
13060 }
13061
13062 static int load_module(void)
13063 {
13064 int res;
13065 my_umask = umask(0);
13066 umask(my_umask);
13067
13068 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13069 return AST_MODULE_LOAD_DECLINE;
13070 }
13071
13072
13073 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13074
13075 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13076 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13077 }
13078
13079 if ((res = load_config(0)))
13080 return res;
13081
13082 res = ast_register_application_xml(app, vm_exec);
13083 res |= ast_register_application_xml(app2, vm_execmain);
13084 res |= ast_register_application_xml(app3, vm_box_exists);
13085 res |= ast_register_application_xml(app4, vmauthenticate);
13086 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13087 res |= ast_custom_function_register(&mailbox_exists_acf);
13088 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13089 #ifdef TEST_FRAMEWORK
13090 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13091 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13092 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13093 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13094 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13095 #endif
13096
13097 if (res)
13098 return res;
13099
13100 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13101 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13102
13103 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13104 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13105 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13106
13107 return res;
13108 }
13109
13110 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13111 {
13112 int cmd = 0;
13113 char destination[80] = "";
13114 int retries = 0;
13115
13116 if (!num) {
13117 ast_verb(3, "Destination number will be entered manually\n");
13118 while (retries < 3 && cmd != 't') {
13119 destination[1] = '\0';
13120 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13121 if (!cmd)
13122 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13123 if (!cmd)
13124 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13125 if (!cmd) {
13126 cmd = ast_waitfordigit(chan, 6000);
13127 if (cmd)
13128 destination[0] = cmd;
13129 }
13130 if (!cmd) {
13131 retries++;
13132 } else {
13133
13134 if (cmd < 0)
13135 return 0;
13136 if (cmd == '*') {
13137 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13138 return 0;
13139 }
13140 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13141 retries++;
13142 else
13143 cmd = 't';
13144 }
13145 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13146 }
13147 if (retries >= 3) {
13148 return 0;
13149 }
13150
13151 } else {
13152 if (option_verbose > 2)
13153 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13154 ast_copy_string(destination, num, sizeof(destination));
13155 }
13156
13157 if (!ast_strlen_zero(destination)) {
13158 if (destination[strlen(destination) -1 ] == '*')
13159 return 0;
13160 if (option_verbose > 2)
13161 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13162 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13163 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13164 chan->priority = 0;
13165 return 9;
13166 }
13167 return 0;
13168 }
13169
13170
13171
13172
13173
13174
13175
13176
13177
13178
13179
13180
13181
13182
13183 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)
13184 {
13185 int res = 0;
13186 char filename[PATH_MAX];
13187 struct ast_config *msg_cfg = NULL;
13188 const char *origtime, *context;
13189 char *name, *num;
13190 int retries = 0;
13191 char *cid;
13192 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13193
13194 vms->starting = 0;
13195
13196 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13197
13198
13199 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13200 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13201 msg_cfg = ast_config_load(filename, config_flags);
13202 DISPOSE(vms->curdir, vms->curmsg);
13203 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13204 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13205 return 0;
13206 }
13207
13208 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13209 ast_config_destroy(msg_cfg);
13210 return 0;
13211 }
13212
13213 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13214
13215 context = ast_variable_retrieve(msg_cfg, "message", "context");
13216 if (!strncasecmp("macro", context, 5))
13217 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13218 switch (option) {
13219 case 3:
13220 if (!res)
13221 res = play_message_datetime(chan, vmu, origtime, filename);
13222 if (!res)
13223 res = play_message_callerid(chan, vms, cid, context, 0);
13224
13225 res = 't';
13226 break;
13227
13228 case 2:
13229
13230 if (ast_strlen_zero(cid))
13231 break;
13232
13233 ast_callerid_parse(cid, &name, &num);
13234 while ((res > -1) && (res != 't')) {
13235 switch (res) {
13236 case '1':
13237 if (num) {
13238
13239 res = dialout(chan, vmu, num, vmu->callback);
13240 if (res) {
13241 ast_config_destroy(msg_cfg);
13242 return 9;
13243 }
13244 } else {
13245 res = '2';
13246 }
13247 break;
13248
13249 case '2':
13250
13251 if (!ast_strlen_zero(vmu->dialout)) {
13252 res = dialout(chan, vmu, NULL, vmu->dialout);
13253 if (res) {
13254 ast_config_destroy(msg_cfg);
13255 return 9;
13256 }
13257 } else {
13258 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13259 res = ast_play_and_wait(chan, "vm-sorry");
13260 }
13261 ast_config_destroy(msg_cfg);
13262 return res;
13263 case '*':
13264 res = 't';
13265 break;
13266 case '3':
13267 case '4':
13268 case '5':
13269 case '6':
13270 case '7':
13271 case '8':
13272 case '9':
13273 case '0':
13274
13275 res = ast_play_and_wait(chan, "vm-sorry");
13276 retries++;
13277 break;
13278 default:
13279 if (num) {
13280 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13281 res = ast_play_and_wait(chan, "vm-num-i-have");
13282 if (!res)
13283 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13284 if (!res)
13285 res = ast_play_and_wait(chan, "vm-tocallnum");
13286
13287 if (!ast_strlen_zero(vmu->dialout)) {
13288 if (!res)
13289 res = ast_play_and_wait(chan, "vm-calldiffnum");
13290 }
13291 } else {
13292 res = ast_play_and_wait(chan, "vm-nonumber");
13293 if (!ast_strlen_zero(vmu->dialout)) {
13294 if (!res)
13295 res = ast_play_and_wait(chan, "vm-toenternumber");
13296 }
13297 }
13298 if (!res) {
13299 res = ast_play_and_wait(chan, "vm-star-cancel");
13300 }
13301 if (!res) {
13302 res = ast_waitfordigit(chan, 6000);
13303 }
13304 if (!res) {
13305 retries++;
13306 if (retries > 3) {
13307 res = 't';
13308 }
13309 }
13310 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13311 break;
13312
13313 }
13314 if (res == 't')
13315 res = 0;
13316 else if (res == '*')
13317 res = -1;
13318 }
13319 break;
13320
13321 case 1:
13322
13323 if (ast_strlen_zero(cid))
13324 break;
13325
13326 ast_callerid_parse(cid, &name, &num);
13327 if (!num) {
13328 ast_verb(3, "No CID number available, no reply sent\n");
13329 if (!res)
13330 res = ast_play_and_wait(chan, "vm-nonumber");
13331 ast_config_destroy(msg_cfg);
13332 return res;
13333 } else {
13334 struct ast_vm_user vmu2;
13335 if (find_user(&vmu2, vmu->context, num)) {
13336 struct leave_vm_options leave_options;
13337 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13338 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13339
13340 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13341
13342 memset(&leave_options, 0, sizeof(leave_options));
13343 leave_options.record_gain = record_gain;
13344 res = leave_voicemail(chan, mailbox, &leave_options);
13345 if (!res)
13346 res = 't';
13347 ast_config_destroy(msg_cfg);
13348 return res;
13349 } else {
13350
13351 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13352 ast_play_and_wait(chan, "vm-nobox");
13353 res = 't';
13354 ast_config_destroy(msg_cfg);
13355 return res;
13356 }
13357 }
13358 res = 0;
13359
13360 break;
13361 }
13362
13363 #ifndef IMAP_STORAGE
13364 ast_config_destroy(msg_cfg);
13365
13366 if (!res) {
13367 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13368 vms->heard[msg] = 1;
13369 res = wait_file(chan, vms, vms->fn);
13370 }
13371 #endif
13372 return res;
13373 }
13374
13375 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13376 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13377 signed char record_gain, struct vm_state *vms, char *flag)
13378 {
13379
13380 int res = 0;
13381 int cmd = 0;
13382 int max_attempts = 3;
13383 int attempts = 0;
13384 int recorded = 0;
13385 int msg_exists = 0;
13386 signed char zero_gain = 0;
13387 char tempfile[PATH_MAX];
13388 char *acceptdtmf = "#";
13389 char *canceldtmf = "";
13390 int canceleddtmf = 0;
13391
13392
13393
13394
13395 if (duration == NULL) {
13396 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13397 return -1;
13398 }
13399
13400 if (!outsidecaller)
13401 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13402 else
13403 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13404
13405 cmd = '3';
13406
13407 while ((cmd >= 0) && (cmd != 't')) {
13408 switch (cmd) {
13409 case '1':
13410 if (!msg_exists) {
13411
13412 cmd = '3';
13413 break;
13414 } else {
13415
13416 ast_verb(3, "Saving message as is\n");
13417 if (!outsidecaller)
13418 ast_filerename(tempfile, recordfile, NULL);
13419 ast_stream_and_wait(chan, "vm-msgsaved", "");
13420 if (!outsidecaller) {
13421
13422 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13423 DISPOSE(recordfile, -1);
13424 }
13425 cmd = 't';
13426 return res;
13427 }
13428 case '2':
13429
13430 ast_verb(3, "Reviewing the message\n");
13431 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13432 break;
13433 case '3':
13434 msg_exists = 0;
13435
13436 if (recorded == 1)
13437 ast_verb(3, "Re-recording the message\n");
13438 else
13439 ast_verb(3, "Recording the message\n");
13440
13441 if (recorded && outsidecaller) {
13442 cmd = ast_play_and_wait(chan, INTRO);
13443 cmd = ast_play_and_wait(chan, "beep");
13444 }
13445 recorded = 1;
13446
13447 if (record_gain)
13448 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13449 if (ast_test_flag(vmu, VM_OPERATOR))
13450 canceldtmf = "0";
13451 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13452 if (strchr(canceldtmf, cmd)) {
13453
13454 canceleddtmf = 1;
13455 }
13456 if (record_gain)
13457 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13458 if (cmd == -1) {
13459
13460 if (!outsidecaller) {
13461
13462 ast_filedelete(tempfile, NULL);
13463 }
13464 return cmd;
13465 }
13466 if (cmd == '0') {
13467 break;
13468 } else if (cmd == '*') {
13469 break;
13470 #if 0
13471 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13472
13473 ast_verb(3, "Message too short\n");
13474 cmd = ast_play_and_wait(chan, "vm-tooshort");
13475 cmd = ast_filedelete(tempfile, NULL);
13476 break;
13477 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13478
13479 ast_verb(3, "Nothing recorded\n");
13480 cmd = ast_filedelete(tempfile, NULL);
13481 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13482 if (!cmd)
13483 cmd = ast_play_and_wait(chan, "vm-speakup");
13484 break;
13485 #endif
13486 } else {
13487
13488 msg_exists = 1;
13489 cmd = 0;
13490 }
13491 break;
13492 case '4':
13493 if (outsidecaller) {
13494
13495 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13496 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13497 res = ast_play_and_wait(chan, "vm-marked-urgent");
13498 strcpy(flag, "Urgent");
13499 } else if (flag) {
13500 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13501 res = ast_play_and_wait(chan, "vm-urgent-removed");
13502 strcpy(flag, "");
13503 } else {
13504 ast_play_and_wait(chan, "vm-sorry");
13505 }
13506 cmd = 0;
13507 } else {
13508 cmd = ast_play_and_wait(chan, "vm-sorry");
13509 }
13510 break;
13511 case '5':
13512 case '6':
13513 case '7':
13514 case '8':
13515 case '9':
13516 case '*':
13517 case '#':
13518 cmd = ast_play_and_wait(chan, "vm-sorry");
13519 break;
13520 #if 0
13521
13522
13523 case '*':
13524
13525 cmd = ast_play_and_wait(chan, "vm-deleted");
13526 cmd = ast_filedelete(tempfile, NULL);
13527 if (outsidecaller) {
13528 res = vm_exec(chan, NULL);
13529 return res;
13530 }
13531 else
13532 return 1;
13533 #endif
13534 case '0':
13535 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13536 cmd = ast_play_and_wait(chan, "vm-sorry");
13537 break;
13538 }
13539 if (msg_exists || recorded) {
13540 cmd = ast_play_and_wait(chan, "vm-saveoper");
13541 if (!cmd)
13542 cmd = ast_waitfordigit(chan, 3000);
13543 if (cmd == '1') {
13544 ast_filerename(tempfile, recordfile, NULL);
13545 ast_play_and_wait(chan, "vm-msgsaved");
13546 cmd = '0';
13547 } else if (cmd == '4') {
13548 if (flag) {
13549 ast_play_and_wait(chan, "vm-marked-urgent");
13550 strcpy(flag, "Urgent");
13551 }
13552 ast_play_and_wait(chan, "vm-msgsaved");
13553 cmd = '0';
13554 } else {
13555 ast_play_and_wait(chan, "vm-deleted");
13556 DELETE(tempfile, -1, tempfile, vmu);
13557 cmd = '0';
13558 }
13559 }
13560 return cmd;
13561 default:
13562
13563
13564
13565 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13566 return cmd;
13567 if (msg_exists) {
13568 cmd = ast_play_and_wait(chan, "vm-review");
13569 if (!cmd && outsidecaller) {
13570 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13571 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13572 } else if (flag) {
13573 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13574 }
13575 }
13576 } else {
13577 cmd = ast_play_and_wait(chan, "vm-torerecord");
13578 if (!cmd)
13579 cmd = ast_waitfordigit(chan, 600);
13580 }
13581
13582 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13583 cmd = ast_play_and_wait(chan, "vm-reachoper");
13584 if (!cmd)
13585 cmd = ast_waitfordigit(chan, 600);
13586 }
13587 #if 0
13588 if (!cmd)
13589 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13590 #endif
13591 if (!cmd)
13592 cmd = ast_waitfordigit(chan, 6000);
13593 if (!cmd) {
13594 attempts++;
13595 }
13596 if (attempts > max_attempts) {
13597 cmd = 't';
13598 }
13599 }
13600 }
13601 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13602
13603 ast_filedelete(tempfile, NULL);
13604 }
13605
13606 if (cmd != 't' && outsidecaller)
13607 ast_play_and_wait(chan, "vm-goodbye");
13608
13609 return cmd;
13610 }
13611
13612
13613
13614
13615
13616 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13617 .load = load_module,
13618 .unload = unload_module,
13619 .reload = reload,
13620 .nonoptreq = "res_adsi,res_smdi",
13621 );