00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 #include "asterisk.h"
00071
00072 #ifdef IMAP_STORAGE
00073 #include <ctype.h>
00074 #include <signal.h>
00075 #include <pwd.h>
00076 #ifdef USE_SYSTEM_IMAP
00077 #include <imap/c-client.h>
00078 #include <imap/imap4r1.h>
00079 #include <imap/linkage.h>
00080 #elif defined (USE_SYSTEM_CCLIENT)
00081 #include <c-client/c-client.h>
00082 #include <c-client/imap4r1.h>
00083 #include <c-client/linkage.h>
00084 #else
00085 #include "c-client.h"
00086 #include "imap4r1.h"
00087 #include "linkage.h"
00088 #endif
00089 #endif
00090
00091 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 334453 $")
00092
00093 #include "asterisk/paths.h"
00094 #include <sys/time.h>
00095 #include <sys/stat.h>
00096 #include <sys/mman.h>
00097 #include <time.h>
00098 #include <dirent.h>
00099 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00100 #include <sys/wait.h>
00101 #endif
00102
00103 #include "asterisk/logger.h"
00104 #include "asterisk/lock.h"
00105 #include "asterisk/file.h"
00106 #include "asterisk/channel.h"
00107 #include "asterisk/pbx.h"
00108 #include "asterisk/config.h"
00109 #include "asterisk/say.h"
00110 #include "asterisk/module.h"
00111 #include "asterisk/adsi.h"
00112 #include "asterisk/app.h"
00113 #include "asterisk/manager.h"
00114 #include "asterisk/dsp.h"
00115 #include "asterisk/localtime.h"
00116 #include "asterisk/cli.h"
00117 #include "asterisk/utils.h"
00118 #include "asterisk/stringfields.h"
00119 #include "asterisk/smdi.h"
00120 #include "asterisk/astobj2.h"
00121 #include "asterisk/event.h"
00122 #include "asterisk/taskprocessor.h"
00123 #include "asterisk/test.h"
00124
00125 #ifdef ODBC_STORAGE
00126 #include "asterisk/res_odbc.h"
00127 #endif
00128
00129 #ifdef IMAP_STORAGE
00130 #include "asterisk/threadstorage.h"
00131 #endif
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
00367
00368
00369
00370
00371 #ifdef IMAP_STORAGE
00372 static char imapserver[48];
00373 static char imapport[8];
00374 static char imapflags[128];
00375 static char imapfolder[64];
00376 static char imapparentfolder[64] = "\0";
00377 static char greetingfolder[64];
00378 static char authuser[32];
00379 static char authpassword[42];
00380 static int imapversion = 1;
00381
00382 static int expungeonhangup = 1;
00383 static int imapgreetings = 0;
00384 static char delimiter = '\0';
00385
00386 struct vm_state;
00387 struct ast_vm_user;
00388
00389 AST_THREADSTORAGE(ts_vmstate);
00390
00391
00392 static int init_mailstream(struct vm_state *vms, int box);
00393 static void write_file(char *filename, char *buffer, unsigned long len);
00394 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00395 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00396 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00397 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00398 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00399 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00400 static void vmstate_insert(struct vm_state *vms);
00401 static void vmstate_delete(struct vm_state *vms);
00402 static void set_update(MAILSTREAM * stream);
00403 static void init_vm_state(struct vm_state *vms);
00404 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00405 static void get_mailbox_delimiter(MAILSTREAM *stream);
00406 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00407 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00408 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);
00409 static void update_messages_by_imapuser(const char *user, unsigned long number);
00410 static int vm_delete(char *file);
00411
00412 static int imap_remove_file (char *dir, int msgnum);
00413 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00414 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00415 static void check_quota(struct vm_state *vms, char *mailbox);
00416 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00417 struct vmstate {
00418 struct vm_state *vms;
00419 AST_LIST_ENTRY(vmstate) list;
00420 };
00421
00422 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00423
00424 #endif
00425
00426 #define SMDI_MWI_WAIT_TIMEOUT 1000
00427
00428 #define COMMAND_TIMEOUT 5000
00429
00430 #define VOICEMAIL_DIR_MODE 0777
00431 #define VOICEMAIL_FILE_MODE 0666
00432 #define CHUNKSIZE 65536
00433
00434 #define VOICEMAIL_CONFIG "voicemail.conf"
00435 #define ASTERISK_USERNAME "asterisk"
00436
00437
00438
00439
00440 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00441 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00442 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00443 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00444 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00445 #define VALID_DTMF "1234567890*#"
00446
00447
00448
00449 #define SENDMAIL "/usr/sbin/sendmail -t"
00450
00451 #define INTRO "vm-intro"
00452
00453 #define MAXMSG 100
00454 #define MAXMSGLIMIT 9999
00455
00456 #define MINPASSWORD 0
00457
00458 #define BASELINELEN 72
00459 #define BASEMAXINLINE 256
00460 #ifdef IMAP_STORAGE
00461 #define ENDL "\r\n"
00462 #else
00463 #define ENDL "\n"
00464 #endif
00465
00466 #define MAX_DATETIME_FORMAT 512
00467 #define MAX_NUM_CID_CONTEXTS 10
00468
00469 #define VM_REVIEW (1 << 0)
00470 #define VM_OPERATOR (1 << 1)
00471 #define VM_SAYCID (1 << 2)
00472 #define VM_SVMAIL (1 << 3)
00473 #define VM_ENVELOPE (1 << 4)
00474 #define VM_SAYDURATION (1 << 5)
00475 #define VM_SKIPAFTERCMD (1 << 6)
00476 #define VM_FORCENAME (1 << 7)
00477 #define VM_FORCEGREET (1 << 8)
00478 #define VM_PBXSKIP (1 << 9)
00479 #define VM_DIRECFORWARD (1 << 10)
00480 #define VM_ATTACH (1 << 11)
00481 #define VM_DELETE (1 << 12)
00482 #define VM_ALLOCED (1 << 13)
00483 #define VM_SEARCH (1 << 14)
00484 #define VM_TEMPGREETWARN (1 << 15)
00485 #define VM_MOVEHEARD (1 << 16)
00486 #define VM_MESSAGEWRAP (1 << 17)
00487 #define VM_FWDURGAUTO (1 << 18)
00488 #define ERROR_LOCK_PATH -100
00489 #define OPERATOR_EXIT 300
00490
00491
00492 enum vm_box {
00493 NEW_FOLDER,
00494 OLD_FOLDER,
00495 WORK_FOLDER,
00496 FAMILY_FOLDER,
00497 FRIENDS_FOLDER,
00498 GREETINGS_FOLDER
00499 };
00500
00501 enum vm_option_flags {
00502 OPT_SILENT = (1 << 0),
00503 OPT_BUSY_GREETING = (1 << 1),
00504 OPT_UNAVAIL_GREETING = (1 << 2),
00505 OPT_RECORDGAIN = (1 << 3),
00506 OPT_PREPEND_MAILBOX = (1 << 4),
00507 OPT_AUTOPLAY = (1 << 6),
00508 OPT_DTMFEXIT = (1 << 7),
00509 OPT_MESSAGE_Urgent = (1 << 8),
00510 OPT_MESSAGE_PRIORITY = (1 << 9)
00511 };
00512
00513 enum vm_option_args {
00514 OPT_ARG_RECORDGAIN = 0,
00515 OPT_ARG_PLAYFOLDER = 1,
00516 OPT_ARG_DTMFEXIT = 2,
00517
00518 OPT_ARG_ARRAY_SIZE = 3,
00519 };
00520
00521 enum vm_passwordlocation {
00522 OPT_PWLOC_VOICEMAILCONF = 0,
00523 OPT_PWLOC_SPOOLDIR = 1,
00524 OPT_PWLOC_USERSCONF = 2,
00525 };
00526
00527 AST_APP_OPTIONS(vm_app_options, {
00528 AST_APP_OPTION('s', OPT_SILENT),
00529 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00530 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00531 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00532 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00533 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00534 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00535 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00536 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00537 });
00538
00539 static int load_config(int reload);
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
00624 struct baseio {
00625 int iocp;
00626 int iolen;
00627 int linelength;
00628 int ateof;
00629 unsigned char iobuf[BASEMAXINLINE];
00630 };
00631
00632
00633
00634 struct ast_vm_user {
00635 char context[AST_MAX_CONTEXT];
00636 char mailbox[AST_MAX_EXTENSION];
00637 char password[80];
00638 char fullname[80];
00639 char email[80];
00640 char *emailsubject;
00641 char *emailbody;
00642 char pager[80];
00643 char serveremail[80];
00644 char mailcmd[160];
00645 char language[MAX_LANGUAGE];
00646 char zonetag[80];
00647 char locale[20];
00648 char callback[80];
00649 char dialout[80];
00650 char uniqueid[80];
00651 char exit[80];
00652 char attachfmt[20];
00653 unsigned int flags;
00654 int saydurationm;
00655 int minsecs;
00656 int maxmsg;
00657 int maxdeletedmsg;
00658 int maxsecs;
00659 int passwordlocation;
00660 #ifdef IMAP_STORAGE
00661 char imapuser[80];
00662 char imappassword[80];
00663 char imapfolder[64];
00664 char imapvmshareid[80];
00665 int imapversion;
00666 #endif
00667 double volgain;
00668 AST_LIST_ENTRY(ast_vm_user) list;
00669 };
00670
00671
00672 struct vm_zone {
00673 AST_LIST_ENTRY(vm_zone) list;
00674 char name[80];
00675 char timezone[80];
00676 char msg_format[512];
00677 };
00678
00679 #define VMSTATE_MAX_MSG_ARRAY 256
00680
00681
00682 struct vm_state {
00683 char curbox[80];
00684 char username[80];
00685 char context[80];
00686 char curdir[PATH_MAX];
00687 char vmbox[PATH_MAX];
00688 char fn[PATH_MAX];
00689 char intro[PATH_MAX];
00690 int *deleted;
00691 int *heard;
00692 int dh_arraysize;
00693 int curmsg;
00694 int lastmsg;
00695 int newmessages;
00696 int oldmessages;
00697 int urgentmessages;
00698 int starting;
00699 int repeats;
00700 #ifdef IMAP_STORAGE
00701 ast_mutex_t lock;
00702 int updated;
00703 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00704 MAILSTREAM *mailstream;
00705 int vmArrayIndex;
00706 char imapuser[80];
00707 char imapfolder[64];
00708 int imapversion;
00709 int interactive;
00710 char introfn[PATH_MAX];
00711 unsigned int quota_limit;
00712 unsigned int quota_usage;
00713 struct vm_state *persist_vms;
00714 #endif
00715 };
00716
00717 #ifdef ODBC_STORAGE
00718 static char odbc_database[80];
00719 static char odbc_table[80];
00720 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00721 #define DISPOSE(a,b) remove_file(a,b)
00722 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00723 #define EXISTS(a,b,c,d) (message_exists(a,b))
00724 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00725 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00726 #define DELETE(a,b,c,d) (delete_file(a,b))
00727 #else
00728 #ifdef IMAP_STORAGE
00729 #define DISPOSE(a,b) (imap_remove_file(a,b))
00730 #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))
00731 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00732 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00733 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00734 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00735 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00736 #else
00737 #define RETRIEVE(a,b,c,d)
00738 #define DISPOSE(a,b)
00739 #define STORE(a,b,c,d,e,f,g,h,i,j)
00740 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00741 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00742 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00743 #define DELETE(a,b,c,d) (vm_delete(c))
00744 #endif
00745 #endif
00746
00747 static char VM_SPOOL_DIR[PATH_MAX];
00748
00749 static char ext_pass_cmd[128];
00750 static char ext_pass_check_cmd[128];
00751
00752 static int my_umask;
00753
00754 #define PWDCHANGE_INTERNAL (1 << 1)
00755 #define PWDCHANGE_EXTERNAL (1 << 2)
00756 static int pwdchange = PWDCHANGE_INTERNAL;
00757
00758 #ifdef ODBC_STORAGE
00759 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00760 #else
00761 # ifdef IMAP_STORAGE
00762 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00763 # else
00764 # define tdesc "Comedian Mail (Voicemail System)"
00765 # endif
00766 #endif
00767
00768 static char userscontext[AST_MAX_EXTENSION] = "default";
00769
00770 static char *addesc = "Comedian Mail";
00771
00772
00773 static char *app = "VoiceMail";
00774
00775
00776 static char *app2 = "VoiceMailMain";
00777
00778 static char *app3 = "MailboxExists";
00779 static char *app4 = "VMAuthenticate";
00780
00781 static char *sayname_app = "VMSayName";
00782
00783 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00784 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00785 static char zonetag[80];
00786 static char locale[20];
00787 static int maxsilence;
00788 static int maxmsg;
00789 static int maxdeletedmsg;
00790 static int silencethreshold = 128;
00791 static char serveremail[80];
00792 static char mailcmd[160];
00793 static char externnotify[160];
00794 static struct ast_smdi_interface *smdi_iface = NULL;
00795 static char vmfmts[80];
00796 static double volgain;
00797 static int vmminsecs;
00798 static int vmmaxsecs;
00799 static int maxgreet;
00800 static int skipms;
00801 static int maxlogins;
00802 static int minpassword;
00803 static int passwordlocation;
00804
00805
00806
00807 static unsigned int poll_mailboxes;
00808
00809
00810 static unsigned int poll_freq;
00811
00812 #define DEFAULT_POLL_FREQ 30
00813
00814 AST_MUTEX_DEFINE_STATIC(poll_lock);
00815 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00816 static pthread_t poll_thread = AST_PTHREADT_NULL;
00817 static unsigned char poll_thread_run;
00818
00819
00820 static struct ast_event_sub *mwi_sub_sub;
00821
00822 static struct ast_event_sub *mwi_unsub_sub;
00823
00824
00825
00826
00827
00828
00829
00830
00831 struct mwi_sub {
00832 AST_RWLIST_ENTRY(mwi_sub) entry;
00833 int old_urgent;
00834 int old_new;
00835 int old_old;
00836 uint32_t uniqueid;
00837 char mailbox[1];
00838 };
00839
00840 struct mwi_sub_task {
00841 const char *mailbox;
00842 const char *context;
00843 uint32_t uniqueid;
00844 };
00845
00846 static struct ast_taskprocessor *mwi_subscription_tps;
00847
00848 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00849
00850
00851 static char listen_control_forward_key[12];
00852 static char listen_control_reverse_key[12];
00853 static char listen_control_pause_key[12];
00854 static char listen_control_restart_key[12];
00855 static char listen_control_stop_key[12];
00856
00857
00858 static char vm_password[80] = "vm-password";
00859 static char vm_newpassword[80] = "vm-newpassword";
00860 static char vm_passchanged[80] = "vm-passchanged";
00861 static char vm_reenterpassword[80] = "vm-reenterpassword";
00862 static char vm_mismatch[80] = "vm-mismatch";
00863 static char vm_invalid_password[80] = "vm-invalid-password";
00864 static char vm_pls_try_again[80] = "vm-pls-try-again";
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876 static char vm_prepend_timeout[80] = "vm-then-pound";
00877
00878 static struct ast_flags globalflags = {0};
00879
00880 static int saydurationminfo;
00881
00882 static char dialcontext[AST_MAX_CONTEXT] = "";
00883 static char callcontext[AST_MAX_CONTEXT] = "";
00884 static char exitcontext[AST_MAX_CONTEXT] = "";
00885
00886 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00887
00888
00889 static char *emailbody = NULL;
00890 static char *emailsubject = NULL;
00891 static char *pagerbody = NULL;
00892 static char *pagersubject = NULL;
00893 static char fromstring[100];
00894 static char pagerfromstring[100];
00895 static char charset[32] = "ISO-8859-1";
00896
00897 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00898 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00899 static int adsiver = 1;
00900 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00901 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00902
00903
00904 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00905 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);
00906 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00907 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00908 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00909 signed char record_gain, struct vm_state *vms, char *flag);
00910 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00911 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00912 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);
00913 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);
00914 static void apply_options(struct ast_vm_user *vmu, const char *options);
00915 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);
00916 static int is_valid_dtmf(const char *key);
00917 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00918 static int write_password_to_file(const char *secretfn, const char *password);
00919 static const char *substitute_escapes(const char *value);
00920 static void free_user(struct ast_vm_user *vmu);
00921
00922 struct ao2_container *inprocess_container;
00923
00924 struct inprocess {
00925 int count;
00926 char *context;
00927 char mailbox[0];
00928 };
00929
00930 static int inprocess_hash_fn(const void *obj, const int flags)
00931 {
00932 const struct inprocess *i = obj;
00933 return atoi(i->mailbox);
00934 }
00935
00936 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00937 {
00938 struct inprocess *i = obj, *j = arg;
00939 if (strcmp(i->mailbox, j->mailbox)) {
00940 return 0;
00941 }
00942 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00943 }
00944
00945 static int inprocess_count(const char *context, const char *mailbox, int delta)
00946 {
00947 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00948 arg->context = arg->mailbox + strlen(mailbox) + 1;
00949 strcpy(arg->mailbox, mailbox);
00950 strcpy(arg->context, context);
00951 ao2_lock(inprocess_container);
00952 if ((i = ao2_find(inprocess_container, arg, 0))) {
00953 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00954 ao2_unlock(inprocess_container);
00955 ao2_ref(i, -1);
00956 return ret;
00957 }
00958 if (delta < 0) {
00959 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00960 }
00961 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00962 ao2_unlock(inprocess_container);
00963 return 0;
00964 }
00965 i->context = i->mailbox + strlen(mailbox) + 1;
00966 strcpy(i->mailbox, mailbox);
00967 strcpy(i->context, context);
00968 i->count = delta;
00969 ao2_link(inprocess_container, i);
00970 ao2_unlock(inprocess_container);
00971 ao2_ref(i, -1);
00972 return 0;
00973 }
00974
00975 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00976 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00977 #endif
00978
00979
00980
00981
00982
00983
00984
00985 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00986 {
00987 char *bufptr = buf;
00988 for (; *input; input++) {
00989 if (*input < 32) {
00990 continue;
00991 }
00992 *bufptr++ = *input;
00993 if (bufptr == buf + buflen - 1) {
00994 break;
00995 }
00996 }
00997 *bufptr = '\0';
00998 return buf;
00999 }
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 static void populate_defaults(struct ast_vm_user *vmu)
01016 {
01017 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01018 vmu->passwordlocation = passwordlocation;
01019 if (saydurationminfo) {
01020 vmu->saydurationm = saydurationminfo;
01021 }
01022 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01023 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01024 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01025 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01026 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01027 if (vmminsecs) {
01028 vmu->minsecs = vmminsecs;
01029 }
01030 if (vmmaxsecs) {
01031 vmu->maxsecs = vmmaxsecs;
01032 }
01033 if (maxmsg) {
01034 vmu->maxmsg = maxmsg;
01035 }
01036 if (maxdeletedmsg) {
01037 vmu->maxdeletedmsg = maxdeletedmsg;
01038 }
01039 vmu->volgain = volgain;
01040 ast_free(vmu->emailsubject);
01041 vmu->emailsubject = NULL;
01042 ast_free(vmu->emailbody);
01043 vmu->emailbody = NULL;
01044 #ifdef IMAP_STORAGE
01045 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01046 #endif
01047 }
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01058 {
01059 int x;
01060 if (!strcasecmp(var, "attach")) {
01061 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01062 } else if (!strcasecmp(var, "attachfmt")) {
01063 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01064 } else if (!strcasecmp(var, "serveremail")) {
01065 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01066 } else if (!strcasecmp(var, "emailbody")) {
01067 vmu->emailbody = ast_strdup(substitute_escapes(value));
01068 } else if (!strcasecmp(var, "emailsubject")) {
01069 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01070 } else if (!strcasecmp(var, "language")) {
01071 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01072 } else if (!strcasecmp(var, "tz")) {
01073 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01074 } else if (!strcasecmp(var, "locale")) {
01075 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01076 #ifdef IMAP_STORAGE
01077 } else if (!strcasecmp(var, "imapuser")) {
01078 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01079 vmu->imapversion = imapversion;
01080 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01081 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01082 vmu->imapversion = imapversion;
01083 } else if (!strcasecmp(var, "imapfolder")) {
01084 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01085 } else if (!strcasecmp(var, "imapvmshareid")) {
01086 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01087 vmu->imapversion = imapversion;
01088 #endif
01089 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01090 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01091 } else if (!strcasecmp(var, "saycid")){
01092 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01093 } else if (!strcasecmp(var, "sendvoicemail")){
01094 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01095 } else if (!strcasecmp(var, "review")){
01096 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01097 } else if (!strcasecmp(var, "tempgreetwarn")){
01098 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01099 } else if (!strcasecmp(var, "messagewrap")){
01100 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01101 } else if (!strcasecmp(var, "operator")) {
01102 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01103 } else if (!strcasecmp(var, "envelope")){
01104 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01105 } else if (!strcasecmp(var, "moveheard")){
01106 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01107 } else if (!strcasecmp(var, "sayduration")){
01108 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01109 } else if (!strcasecmp(var, "saydurationm")){
01110 if (sscanf(value, "%30d", &x) == 1) {
01111 vmu->saydurationm = x;
01112 } else {
01113 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01114 }
01115 } else if (!strcasecmp(var, "forcename")){
01116 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01117 } else if (!strcasecmp(var, "forcegreetings")){
01118 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01119 } else if (!strcasecmp(var, "callback")) {
01120 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01121 } else if (!strcasecmp(var, "dialout")) {
01122 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01123 } else if (!strcasecmp(var, "exitcontext")) {
01124 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01125 } else if (!strcasecmp(var, "minsecs")) {
01126 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01127 vmu->minsecs = x;
01128 } else {
01129 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01130 vmu->minsecs = vmminsecs;
01131 }
01132 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01133 vmu->maxsecs = atoi(value);
01134 if (vmu->maxsecs <= 0) {
01135 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01136 vmu->maxsecs = vmmaxsecs;
01137 } else {
01138 vmu->maxsecs = atoi(value);
01139 }
01140 if (!strcasecmp(var, "maxmessage"))
01141 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01142 } else if (!strcasecmp(var, "maxmsg")) {
01143 vmu->maxmsg = atoi(value);
01144
01145 if (vmu->maxmsg < 0) {
01146 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01147 vmu->maxmsg = MAXMSG;
01148 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01149 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01150 vmu->maxmsg = MAXMSGLIMIT;
01151 }
01152 } else if (!strcasecmp(var, "nextaftercmd")) {
01153 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01154 } else if (!strcasecmp(var, "backupdeleted")) {
01155 if (sscanf(value, "%30d", &x) == 1)
01156 vmu->maxdeletedmsg = x;
01157 else if (ast_true(value))
01158 vmu->maxdeletedmsg = MAXMSG;
01159 else
01160 vmu->maxdeletedmsg = 0;
01161
01162 if (vmu->maxdeletedmsg < 0) {
01163 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01164 vmu->maxdeletedmsg = MAXMSG;
01165 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01166 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01167 vmu->maxdeletedmsg = MAXMSGLIMIT;
01168 }
01169 } else if (!strcasecmp(var, "volgain")) {
01170 sscanf(value, "%30lf", &vmu->volgain);
01171 } else if (!strcasecmp(var, "passwordlocation")) {
01172 if (!strcasecmp(value, "spooldir")) {
01173 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01174 } else {
01175 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01176 }
01177 } else if (!strcasecmp(var, "options")) {
01178 apply_options(vmu, value);
01179 }
01180 }
01181
01182 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01183 {
01184 int fds[2], pid = 0;
01185
01186 memset(buf, 0, len);
01187
01188 if (pipe(fds)) {
01189 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01190 } else {
01191
01192 pid = ast_safe_fork(0);
01193
01194 if (pid < 0) {
01195
01196 close(fds[0]);
01197 close(fds[1]);
01198 snprintf(buf, len, "FAILURE: Fork failed");
01199 } else if (pid) {
01200
01201 close(fds[1]);
01202 if (read(fds[0], buf, len) < 0) {
01203 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01204 }
01205 close(fds[0]);
01206 } else {
01207
01208 AST_DECLARE_APP_ARGS(arg,
01209 AST_APP_ARG(v)[20];
01210 );
01211 char *mycmd = ast_strdupa(command);
01212
01213 close(fds[0]);
01214 dup2(fds[1], STDOUT_FILENO);
01215 close(fds[1]);
01216 ast_close_fds_above_n(STDOUT_FILENO);
01217
01218 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01219
01220 execv(arg.v[0], arg.v);
01221 printf("FAILURE: %s", strerror(errno));
01222 _exit(0);
01223 }
01224 }
01225 return buf;
01226 }
01227
01228
01229
01230
01231
01232
01233
01234
01235 static int check_password(struct ast_vm_user *vmu, char *password)
01236 {
01237
01238 if (strlen(password) < minpassword)
01239 return 1;
01240
01241 if (!ast_strlen_zero(password) && password[0] == '*')
01242 return 1;
01243 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01244 char cmd[255], buf[255];
01245
01246 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01247
01248 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01249 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01250 ast_debug(5, "Result: %s\n", buf);
01251 if (!strncasecmp(buf, "VALID", 5)) {
01252 ast_debug(3, "Passed password check: '%s'\n", buf);
01253 return 0;
01254 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01255 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01256 return 0;
01257 } else {
01258 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01259 return 1;
01260 }
01261 }
01262 }
01263 return 0;
01264 }
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01277 {
01278 int res = -1;
01279 if (!strcmp(vmu->password, password)) {
01280
01281 return 0;
01282 }
01283
01284 if (strlen(password) > 10) {
01285 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01286 }
01287 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01288 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01289 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01290 res = 0;
01291 }
01292 return res;
01293 }
01294
01295
01296
01297
01298 static void apply_options(struct ast_vm_user *vmu, const char *options)
01299 {
01300 char *stringp;
01301 char *s;
01302 char *var, *value;
01303 stringp = ast_strdupa(options);
01304 while ((s = strsep(&stringp, "|"))) {
01305 value = s;
01306 if ((var = strsep(&value, "=")) && value) {
01307 apply_option(vmu, var, value);
01308 }
01309 }
01310 }
01311
01312
01313
01314
01315
01316
01317 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01318 {
01319 for (; var; var = var->next) {
01320 if (!strcasecmp(var->name, "vmsecret")) {
01321 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01322 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01323 if (ast_strlen_zero(retval->password)) {
01324 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01325 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01326 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01327 } else {
01328 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01329 }
01330 }
01331 } else if (!strcasecmp(var->name, "uniqueid")) {
01332 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01333 } else if (!strcasecmp(var->name, "pager")) {
01334 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01335 } else if (!strcasecmp(var->name, "email")) {
01336 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01337 } else if (!strcasecmp(var->name, "fullname")) {
01338 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01339 } else if (!strcasecmp(var->name, "context")) {
01340 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01341 } else if (!strcasecmp(var->name, "emailsubject")) {
01342 ast_free(retval->emailsubject);
01343 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01344 } else if (!strcasecmp(var->name, "emailbody")) {
01345 ast_free(retval->emailbody);
01346 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01347 #ifdef IMAP_STORAGE
01348 } else if (!strcasecmp(var->name, "imapuser")) {
01349 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01350 retval->imapversion = imapversion;
01351 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01352 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01353 retval->imapversion = imapversion;
01354 } else if (!strcasecmp(var->name, "imapfolder")) {
01355 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01356 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01357 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01358 retval->imapversion = imapversion;
01359 #endif
01360 } else
01361 apply_option(retval, var->name, var->value);
01362 }
01363 }
01364
01365
01366
01367
01368
01369
01370
01371
01372 static int is_valid_dtmf(const char *key)
01373 {
01374 int i;
01375 char *local_key = ast_strdupa(key);
01376
01377 for (i = 0; i < strlen(key); ++i) {
01378 if (!strchr(VALID_DTMF, *local_key)) {
01379 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01380 return 0;
01381 }
01382 local_key++;
01383 }
01384 return 1;
01385 }
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01398 {
01399 struct ast_variable *var;
01400 struct ast_vm_user *retval;
01401
01402 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01403 if (!ivm)
01404 ast_set_flag(retval, VM_ALLOCED);
01405 else
01406 memset(retval, 0, sizeof(*retval));
01407 if (mailbox)
01408 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01409 populate_defaults(retval);
01410 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01411 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01412 else
01413 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01414 if (var) {
01415 apply_options_full(retval, var);
01416 ast_variables_destroy(var);
01417 } else {
01418 if (!ivm)
01419 free_user(retval);
01420 retval = NULL;
01421 }
01422 }
01423 return retval;
01424 }
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01435 {
01436
01437 struct ast_vm_user *vmu = NULL, *cur;
01438 AST_LIST_LOCK(&users);
01439
01440 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01441 context = "default";
01442
01443 AST_LIST_TRAVERSE(&users, cur, list) {
01444 #ifdef IMAP_STORAGE
01445 if (cur->imapversion != imapversion) {
01446 continue;
01447 }
01448 #endif
01449 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01450 break;
01451 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01452 break;
01453 }
01454 if (cur) {
01455
01456 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01457 *vmu = *cur;
01458 if (!ivm) {
01459 vmu->emailbody = ast_strdup(cur->emailbody);
01460 vmu->emailsubject = ast_strdup(cur->emailsubject);
01461 }
01462 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01463 AST_LIST_NEXT(vmu, list) = NULL;
01464 }
01465 } else
01466 vmu = find_user_realtime(ivm, context, mailbox);
01467 AST_LIST_UNLOCK(&users);
01468 return vmu;
01469 }
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01482 {
01483
01484 struct ast_vm_user *cur;
01485 int res = -1;
01486 AST_LIST_LOCK(&users);
01487 AST_LIST_TRAVERSE(&users, cur, list) {
01488 if ((!context || !strcasecmp(context, cur->context)) &&
01489 (!strcasecmp(mailbox, cur->mailbox)))
01490 break;
01491 }
01492 if (cur) {
01493 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01494 res = 0;
01495 }
01496 AST_LIST_UNLOCK(&users);
01497 return res;
01498 }
01499
01500
01501
01502
01503
01504
01505
01506
01507 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01508 {
01509 struct ast_config *cfg = NULL;
01510 struct ast_variable *var = NULL;
01511 struct ast_category *cat = NULL;
01512 char *category = NULL, *value = NULL, *new = NULL;
01513 const char *tmp = NULL;
01514 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01515 char secretfn[PATH_MAX] = "";
01516 int found = 0;
01517
01518 if (!change_password_realtime(vmu, newpassword))
01519 return;
01520
01521
01522 switch (vmu->passwordlocation) {
01523 case OPT_PWLOC_SPOOLDIR:
01524 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01525 if (write_password_to_file(secretfn, newpassword) == 0) {
01526 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01527 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01528 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01529 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01530 break;
01531 } else {
01532 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01533 }
01534
01535 case OPT_PWLOC_VOICEMAILCONF:
01536 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01537 while ((category = ast_category_browse(cfg, category))) {
01538 if (!strcasecmp(category, vmu->context)) {
01539 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01540 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01541 break;
01542 }
01543 value = strstr(tmp, ",");
01544 if (!value) {
01545 new = alloca(strlen(newpassword)+1);
01546 sprintf(new, "%s", newpassword);
01547 } else {
01548 new = alloca((strlen(value) + strlen(newpassword) + 1));
01549 sprintf(new, "%s%s", newpassword, value);
01550 }
01551 if (!(cat = ast_category_get(cfg, category))) {
01552 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01553 break;
01554 }
01555 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01556 found = 1;
01557 }
01558 }
01559
01560 if (found) {
01561 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01562 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01563 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01564 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01565 break;
01566 }
01567 }
01568
01569 case OPT_PWLOC_USERSCONF:
01570
01571
01572 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01573 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01574 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01575 ast_debug(4, "users.conf: %s\n", category);
01576 if (!strcasecmp(category, vmu->mailbox)) {
01577 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01578 ast_debug(3, "looks like we need to make vmsecret!\n");
01579 var = ast_variable_new("vmsecret", newpassword, "");
01580 } else {
01581 var = NULL;
01582 }
01583 new = alloca(strlen(newpassword) + 1);
01584 sprintf(new, "%s", newpassword);
01585 if (!(cat = ast_category_get(cfg, category))) {
01586 ast_debug(4, "failed to get category!\n");
01587 ast_free(var);
01588 break;
01589 }
01590 if (!var) {
01591 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01592 } else {
01593 ast_variable_append(cat, var);
01594 }
01595 found = 1;
01596 break;
01597 }
01598 }
01599
01600 if (found) {
01601 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01602 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01603 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01604 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01605 }
01606 }
01607 }
01608 }
01609
01610 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01611 {
01612 char buf[255];
01613 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01614 ast_debug(1, "External password: %s\n",buf);
01615 if (!ast_safe_system(buf)) {
01616 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01617 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01618
01619 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01620 }
01621 }
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01637 {
01638 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01639 }
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653 static int make_file(char *dest, const int len, const char *dir, const int num)
01654 {
01655 return snprintf(dest, len, "%s/msg%04d", dir, num);
01656 }
01657
01658
01659 static FILE *vm_mkftemp(char *template)
01660 {
01661 FILE *p = NULL;
01662 int pfd = mkstemp(template);
01663 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01664 if (pfd > -1) {
01665 p = fdopen(pfd, "w+");
01666 if (!p) {
01667 close(pfd);
01668 pfd = -1;
01669 }
01670 }
01671 return p;
01672 }
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01683 {
01684 mode_t mode = VOICEMAIL_DIR_MODE;
01685 int res;
01686
01687 make_dir(dest, len, context, ext, folder);
01688 if ((res = ast_mkdir(dest, mode))) {
01689 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01690 return -1;
01691 }
01692 return 0;
01693 }
01694
01695 static const char * const mailbox_folders[] = {
01696 #ifdef IMAP_STORAGE
01697 imapfolder,
01698 #else
01699 "INBOX",
01700 #endif
01701 "Old",
01702 "Work",
01703 "Family",
01704 "Friends",
01705 "Cust1",
01706 "Cust2",
01707 "Cust3",
01708 "Cust4",
01709 "Cust5",
01710 "Deleted",
01711 "Urgent",
01712 };
01713
01714 static const char *mbox(struct ast_vm_user *vmu, int id)
01715 {
01716 #ifdef IMAP_STORAGE
01717 if (vmu && id == 0) {
01718 return vmu->imapfolder;
01719 }
01720 #endif
01721 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01722 }
01723
01724 static int get_folder_by_name(const char *name)
01725 {
01726 size_t i;
01727
01728 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01729 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01730 return i;
01731 }
01732 }
01733
01734 return -1;
01735 }
01736
01737 static void free_user(struct ast_vm_user *vmu)
01738 {
01739 if (ast_test_flag(vmu, VM_ALLOCED)) {
01740
01741 ast_free(vmu->emailbody);
01742 vmu->emailbody = NULL;
01743
01744 ast_free(vmu->emailsubject);
01745 vmu->emailsubject = NULL;
01746
01747 ast_free(vmu);
01748 }
01749 }
01750
01751 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01752
01753 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01754 if (!vms->dh_arraysize) {
01755
01756 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01757 return -1;
01758 }
01759 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01760 return -1;
01761 }
01762 vms->dh_arraysize = arraysize;
01763 } else if (vms->dh_arraysize < arraysize) {
01764 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01765 return -1;
01766 }
01767 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01768 return -1;
01769 }
01770 memset(vms->deleted, 0, arraysize * sizeof(int));
01771 memset(vms->heard, 0, arraysize * sizeof(int));
01772 vms->dh_arraysize = arraysize;
01773 }
01774
01775 return 0;
01776 }
01777
01778
01779
01780 #ifdef IMAP_STORAGE
01781 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01782 {
01783 char arg[10];
01784 struct vm_state *vms;
01785 unsigned long messageNum;
01786
01787
01788 if (msgnum < 0 && !imapgreetings) {
01789 ast_filedelete(file, NULL);
01790 return;
01791 }
01792
01793 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01794 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);
01795 return;
01796 }
01797
01798
01799
01800 messageNum = vms->msgArray[msgnum];
01801 if (messageNum == 0) {
01802 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01803 return;
01804 }
01805 if (option_debug > 2)
01806 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01807
01808 snprintf (arg, sizeof(arg), "%lu", messageNum);
01809 ast_mutex_lock(&vms->lock);
01810 mail_setflag (vms->mailstream, arg, "\\DELETED");
01811 mail_expunge(vms->mailstream);
01812 ast_mutex_unlock(&vms->lock);
01813 }
01814
01815 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01816 {
01817 struct vm_state *vms_p;
01818 char *file, *filename;
01819 char *attachment;
01820 int ret = 0, i;
01821 BODY *body;
01822
01823
01824
01825
01826 if (msgnum > -1 || !imapgreetings) {
01827 return 0;
01828 } else {
01829 file = strrchr(ast_strdupa(dir), '/');
01830 if (file)
01831 *file++ = '\0';
01832 else {
01833 ast_debug (1, "Failed to procure file name from directory passed.\n");
01834 return -1;
01835 }
01836 }
01837
01838
01839 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01840 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01841
01842
01843
01844
01845 if (!(vms_p = create_vm_state_from_user(vmu))) {
01846 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01847 return -1;
01848 }
01849 }
01850
01851
01852 *vms_p->introfn = '\0';
01853
01854 ast_mutex_lock(&vms_p->lock);
01855 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01856 if (!vms_p->mailstream) {
01857 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01858 ast_mutex_unlock(&vms_p->lock);
01859 return -1;
01860 }
01861
01862
01863 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01864 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01865
01866 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01867 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01868 } else {
01869 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01870 ast_mutex_unlock(&vms_p->lock);
01871 return -1;
01872 }
01873 filename = strsep(&attachment, ".");
01874 if (!strcmp(filename, file)) {
01875 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01876 vms_p->msgArray[vms_p->curmsg] = i + 1;
01877 save_body(body, vms_p, "2", attachment, 0);
01878 ast_mutex_unlock(&vms_p->lock);
01879 return 0;
01880 }
01881 }
01882 ast_mutex_unlock(&vms_p->lock);
01883
01884 return -1;
01885 }
01886
01887 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01888 {
01889 BODY *body;
01890 char *header_content;
01891 char *attachedfilefmt;
01892 char buf[80];
01893 struct vm_state *vms;
01894 char text_file[PATH_MAX];
01895 FILE *text_file_ptr;
01896 int res = 0;
01897 struct ast_vm_user *vmu;
01898
01899 if (!(vmu = find_user(NULL, context, mailbox))) {
01900 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01901 return -1;
01902 }
01903
01904 if (msgnum < 0) {
01905 if (imapgreetings) {
01906 res = imap_retrieve_greeting(dir, msgnum, vmu);
01907 goto exit;
01908 } else {
01909 res = 0;
01910 goto exit;
01911 }
01912 }
01913
01914
01915
01916
01917 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01918
01919
01920
01921
01922
01923
01924
01925 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01926 res = -1;
01927 goto exit;
01928 }
01929
01930 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01931 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01932
01933
01934 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01935 res = 0;
01936 goto exit;
01937 }
01938
01939 if (option_debug > 2)
01940 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01941 if (vms->msgArray[msgnum] == 0) {
01942 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01943 res = -1;
01944 goto exit;
01945 }
01946
01947
01948 ast_mutex_lock(&vms->lock);
01949 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01950 ast_mutex_unlock(&vms->lock);
01951
01952 if (ast_strlen_zero(header_content)) {
01953 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01954 res = -1;
01955 goto exit;
01956 }
01957
01958 ast_mutex_lock(&vms->lock);
01959 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01960 ast_mutex_unlock(&vms->lock);
01961
01962
01963 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01964 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01965 } else {
01966 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01967 res = -1;
01968 goto exit;
01969 }
01970
01971
01972
01973 strsep(&attachedfilefmt, ".");
01974 if (!attachedfilefmt) {
01975 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01976 res = -1;
01977 goto exit;
01978 }
01979
01980 save_body(body, vms, "2", attachedfilefmt, 0);
01981 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01982 *vms->introfn = '\0';
01983 }
01984
01985
01986 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01987
01988 if (!(text_file_ptr = fopen(text_file, "w"))) {
01989 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01990 }
01991
01992 fprintf(text_file_ptr, "%s\n", "[message]");
01993
01994 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01995 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01996 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01997 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01998 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01999 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02000 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02001 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02002 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02003 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02004 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02005 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02006 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02007 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02008 fclose(text_file_ptr);
02009
02010 exit:
02011 free_user(vmu);
02012 return res;
02013 }
02014
02015 static int folder_int(const char *folder)
02016 {
02017
02018 if (!folder) {
02019 return 0;
02020 }
02021 if (!strcasecmp(folder, imapfolder)) {
02022 return 0;
02023 } else if (!strcasecmp(folder, "Old")) {
02024 return 1;
02025 } else if (!strcasecmp(folder, "Work")) {
02026 return 2;
02027 } else if (!strcasecmp(folder, "Family")) {
02028 return 3;
02029 } else if (!strcasecmp(folder, "Friends")) {
02030 return 4;
02031 } else if (!strcasecmp(folder, "Cust1")) {
02032 return 5;
02033 } else if (!strcasecmp(folder, "Cust2")) {
02034 return 6;
02035 } else if (!strcasecmp(folder, "Cust3")) {
02036 return 7;
02037 } else if (!strcasecmp(folder, "Cust4")) {
02038 return 8;
02039 } else if (!strcasecmp(folder, "Cust5")) {
02040 return 9;
02041 } else if (!strcasecmp(folder, "Urgent")) {
02042 return 11;
02043 } else {
02044 return 0;
02045 }
02046 }
02047
02048 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02049 {
02050 SEARCHPGM *pgm;
02051 SEARCHHEADER *hdr;
02052
02053 struct ast_vm_user *vmu, vmus;
02054 struct vm_state *vms_p;
02055 int ret = 0;
02056 int fold = folder_int(folder);
02057 int urgent = 0;
02058
02059
02060 if (fold == 11) {
02061 fold = NEW_FOLDER;
02062 urgent = 1;
02063 }
02064
02065 if (ast_strlen_zero(mailbox))
02066 return 0;
02067
02068
02069 vmu = find_user(&vmus, context, mailbox);
02070 if (!vmu) {
02071 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02072 return -1;
02073 } else {
02074
02075 if (vmu->imapuser[0] == '\0') {
02076 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02077 return -1;
02078 }
02079 }
02080
02081
02082 if (vmu->imapuser[0] == '\0') {
02083 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02084 free_user(vmu);
02085 return -1;
02086 }
02087
02088
02089 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02090 if (!vms_p) {
02091 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02092 }
02093 if (vms_p) {
02094 ast_debug(3, "Returning before search - user is logged in\n");
02095 if (fold == 0) {
02096 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02097 }
02098 if (fold == 1) {
02099 return vms_p->oldmessages;
02100 }
02101 }
02102
02103
02104 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02105 if (!vms_p) {
02106 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02107 }
02108
02109 if (!vms_p) {
02110 vms_p = create_vm_state_from_user(vmu);
02111 }
02112 ret = init_mailstream(vms_p, fold);
02113 if (!vms_p->mailstream) {
02114 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02115 return -1;
02116 }
02117 if (ret == 0) {
02118 ast_mutex_lock(&vms_p->lock);
02119 pgm = mail_newsearchpgm ();
02120 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02121 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02122 pgm->header = hdr;
02123 if (fold != OLD_FOLDER) {
02124 pgm->unseen = 1;
02125 pgm->seen = 0;
02126 }
02127
02128
02129
02130 else {
02131 pgm->unseen = 0;
02132 pgm->seen = 1;
02133 }
02134
02135 if (fold == NEW_FOLDER) {
02136 if (urgent) {
02137 pgm->flagged = 1;
02138 pgm->unflagged = 0;
02139 } else {
02140 pgm->flagged = 0;
02141 pgm->unflagged = 1;
02142 }
02143 }
02144 pgm->undeleted = 1;
02145 pgm->deleted = 0;
02146
02147 vms_p->vmArrayIndex = 0;
02148 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02149 if (fold == 0 && urgent == 0)
02150 vms_p->newmessages = vms_p->vmArrayIndex;
02151 if (fold == 1)
02152 vms_p->oldmessages = vms_p->vmArrayIndex;
02153 if (fold == 0 && urgent == 1)
02154 vms_p->urgentmessages = vms_p->vmArrayIndex;
02155
02156 mail_free_searchpgm(&pgm);
02157 ast_mutex_unlock(&vms_p->lock);
02158 vms_p->updated = 0;
02159 return vms_p->vmArrayIndex;
02160 } else {
02161 ast_mutex_lock(&vms_p->lock);
02162 mail_ping(vms_p->mailstream);
02163 ast_mutex_unlock(&vms_p->lock);
02164 }
02165 return 0;
02166 }
02167
02168 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02169 {
02170
02171 check_quota(vms, vmu->imapfolder);
02172 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02173 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02174 ast_play_and_wait(chan, "vm-mailboxfull");
02175 return -1;
02176 }
02177
02178
02179 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));
02180 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02181 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02182 ast_play_and_wait(chan, "vm-mailboxfull");
02183 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02184 return -1;
02185 }
02186
02187 return 0;
02188 }
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198
02199 static int messagecount(const char *context, const char *mailbox, const char *folder)
02200 {
02201 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02202 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02203 } else {
02204 return __messagecount(context, mailbox, folder);
02205 }
02206 }
02207
02208 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)
02209 {
02210 char *myserveremail = serveremail;
02211 char fn[PATH_MAX];
02212 char introfn[PATH_MAX];
02213 char mailbox[256];
02214 char *stringp;
02215 FILE *p = NULL;
02216 char tmp[80] = "/tmp/astmail-XXXXXX";
02217 long len;
02218 void *buf;
02219 int tempcopy = 0;
02220 STRING str;
02221 int ret;
02222 char *imap_flags = NIL;
02223 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02224 int box = NEW_FOLDER;
02225
02226
02227 if (msgnum < 0) {
02228 if(!imapgreetings) {
02229 return 0;
02230 } else {
02231 box = GREETINGS_FOLDER;
02232 }
02233 }
02234
02235 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02236 return -1;
02237 }
02238
02239
02240 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02241 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02242 imap_flags = "\\FLAGGED";
02243 }
02244
02245
02246 fmt = ast_strdupa(fmt);
02247 stringp = fmt;
02248 strsep(&stringp, "|");
02249
02250 if (!ast_strlen_zero(vmu->serveremail))
02251 myserveremail = vmu->serveremail;
02252
02253 if (msgnum > -1)
02254 make_file(fn, sizeof(fn), dir, msgnum);
02255 else
02256 ast_copy_string (fn, dir, sizeof(fn));
02257
02258 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02259 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02260 *introfn = '\0';
02261 }
02262
02263 if (ast_strlen_zero(vmu->email)) {
02264
02265
02266
02267
02268
02269 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02270 tempcopy = 1;
02271 }
02272
02273 if (!strcmp(fmt, "wav49"))
02274 fmt = "WAV";
02275 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02276
02277
02278
02279 if (!(p = vm_mkftemp(tmp))) {
02280 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02281 if (tempcopy)
02282 *(vmu->email) = '\0';
02283 return -1;
02284 }
02285
02286 if (msgnum < 0 && imapgreetings) {
02287 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02288 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02289 return -1;
02290 }
02291 imap_delete_old_greeting(fn, vms);
02292 }
02293
02294 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02295 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02296 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02297 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02298
02299 len = ftell(p);
02300 rewind(p);
02301 if (!(buf = ast_malloc(len + 1))) {
02302 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02303 fclose(p);
02304 if (tempcopy)
02305 *(vmu->email) = '\0';
02306 return -1;
02307 }
02308 if (fread(buf, len, 1, p) < len) {
02309 if (ferror(p)) {
02310 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02311 return -1;
02312 }
02313 }
02314 ((char *) buf)[len] = '\0';
02315 INIT(&str, mail_string, buf, len);
02316 ret = init_mailstream(vms, box);
02317 if (ret == 0) {
02318 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02319 ast_mutex_lock(&vms->lock);
02320 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02321 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02322 ast_mutex_unlock(&vms->lock);
02323 fclose(p);
02324 unlink(tmp);
02325 ast_free(buf);
02326 } else {
02327 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02328 fclose(p);
02329 unlink(tmp);
02330 ast_free(buf);
02331 return -1;
02332 }
02333 ast_debug(3, "%s stored\n", fn);
02334
02335 if (tempcopy)
02336 *(vmu->email) = '\0';
02337 inprocess_count(vmu->mailbox, vmu->context, -1);
02338 return 0;
02339
02340 }
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352
02353
02354
02355 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02356 {
02357 char tmp[PATH_MAX] = "";
02358 char *mailboxnc;
02359 char *context;
02360 char *mb;
02361 char *cur;
02362 if (newmsgs)
02363 *newmsgs = 0;
02364 if (oldmsgs)
02365 *oldmsgs = 0;
02366 if (urgentmsgs)
02367 *urgentmsgs = 0;
02368
02369 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02370
02371 if (ast_strlen_zero(mailbox_context))
02372 return 0;
02373
02374 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02375 context = strchr(tmp, '@');
02376 if (strchr(mailbox_context, ',')) {
02377 int tmpnew, tmpold, tmpurgent;
02378 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02379 mb = tmp;
02380 while ((cur = strsep(&mb, ", "))) {
02381 if (!ast_strlen_zero(cur)) {
02382 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02383 return -1;
02384 else {
02385 if (newmsgs)
02386 *newmsgs += tmpnew;
02387 if (oldmsgs)
02388 *oldmsgs += tmpold;
02389 if (urgentmsgs)
02390 *urgentmsgs += tmpurgent;
02391 }
02392 }
02393 }
02394 return 0;
02395 }
02396 if (context) {
02397 *context = '\0';
02398 mailboxnc = tmp;
02399 context++;
02400 } else {
02401 context = "default";
02402 mailboxnc = (char *) mailbox_context;
02403 }
02404
02405 if (newmsgs) {
02406 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02407 if (!vmu) {
02408 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02409 return -1;
02410 }
02411 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02412 return -1;
02413 }
02414 }
02415 if (oldmsgs) {
02416 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02417 return -1;
02418 }
02419 }
02420 if (urgentmsgs) {
02421 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02422 return -1;
02423 }
02424 }
02425 return 0;
02426 }
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438 static int has_voicemail(const char *mailbox, const char *folder)
02439 {
02440 char tmp[256], *tmp2, *box, *context;
02441 ast_copy_string(tmp, mailbox, sizeof(tmp));
02442 tmp2 = tmp;
02443 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02444 while ((box = strsep(&tmp2, ",&"))) {
02445 if (!ast_strlen_zero(box)) {
02446 if (has_voicemail(box, folder)) {
02447 return 1;
02448 }
02449 }
02450 }
02451 }
02452 if ((context = strchr(tmp, '@'))) {
02453 *context++ = '\0';
02454 } else {
02455 context = "default";
02456 }
02457 return __messagecount(context, tmp, folder) ? 1 : 0;
02458 }
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475 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)
02476 {
02477 struct vm_state *sendvms = NULL, *destvms = NULL;
02478 char messagestring[10];
02479 if (msgnum >= recip->maxmsg) {
02480 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02481 return -1;
02482 }
02483 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02484 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02485 return -1;
02486 }
02487 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02488 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02489 return -1;
02490 }
02491 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02492 ast_mutex_lock(&sendvms->lock);
02493 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02494 ast_mutex_unlock(&sendvms->lock);
02495 return 0;
02496 }
02497 ast_mutex_unlock(&sendvms->lock);
02498 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02499 return -1;
02500 }
02501
02502 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02503 {
02504 char tmp[256], *t = tmp;
02505 size_t left = sizeof(tmp);
02506
02507 if (box == OLD_FOLDER) {
02508 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02509 } else {
02510 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02511 }
02512
02513 if (box == NEW_FOLDER) {
02514 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02515 } else {
02516 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02517 }
02518
02519
02520 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02521
02522
02523 if (!ast_strlen_zero(authuser))
02524 ast_build_string(&t, &left, "/authuser=%s", authuser);
02525
02526
02527 if (!ast_strlen_zero(imapflags))
02528 ast_build_string(&t, &left, "/%s", imapflags);
02529
02530
02531 #if 1
02532 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02533 #else
02534 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02535 #endif
02536 if (box == NEW_FOLDER || box == OLD_FOLDER)
02537 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02538 else if (box == GREETINGS_FOLDER)
02539 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02540 else {
02541 if (!ast_strlen_zero(imapparentfolder)) {
02542
02543 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02544 } else {
02545 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02546 }
02547 }
02548 }
02549
02550 static int init_mailstream(struct vm_state *vms, int box)
02551 {
02552 MAILSTREAM *stream = NIL;
02553 long debug;
02554 char tmp[256];
02555
02556 if (!vms) {
02557 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02558 return -1;
02559 }
02560 if (option_debug > 2)
02561 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02562 if (vms->mailstream == NIL || !vms->mailstream) {
02563 if (option_debug)
02564 ast_log(LOG_DEBUG, "mailstream not set.\n");
02565 } else {
02566 stream = vms->mailstream;
02567 }
02568
02569 debug = NIL;
02570
02571 if (delimiter == '\0') {
02572 char *cp;
02573 #ifdef USE_SYSTEM_IMAP
02574 #include <imap/linkage.c>
02575 #elif defined(USE_SYSTEM_CCLIENT)
02576 #include <c-client/linkage.c>
02577 #else
02578 #include "linkage.c"
02579 #endif
02580
02581 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02582 ast_mutex_lock(&vms->lock);
02583 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02584 ast_mutex_unlock(&vms->lock);
02585 if (stream == NIL) {
02586 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02587 return -1;
02588 }
02589 get_mailbox_delimiter(stream);
02590
02591 for (cp = vms->imapfolder; *cp; cp++)
02592 if (*cp == '/')
02593 *cp = delimiter;
02594 }
02595
02596 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02597 if (option_debug > 2)
02598 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02599 ast_mutex_lock(&vms->lock);
02600 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02601 ast_mutex_unlock(&vms->lock);
02602 if (vms->mailstream == NIL) {
02603 return -1;
02604 } else {
02605 return 0;
02606 }
02607 }
02608
02609 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02610 {
02611 SEARCHPGM *pgm;
02612 SEARCHHEADER *hdr;
02613 int ret, urgent = 0;
02614
02615
02616 if (box == 11) {
02617 box = NEW_FOLDER;
02618 urgent = 1;
02619 }
02620
02621 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02622 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02623 vms->imapversion = vmu->imapversion;
02624 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02625
02626 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02627 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02628 return -1;
02629 }
02630
02631 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02632
02633
02634 if (box == 0) {
02635 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02636 check_quota(vms, (char *) mbox(vmu, box));
02637 }
02638
02639 ast_mutex_lock(&vms->lock);
02640 pgm = mail_newsearchpgm();
02641
02642
02643 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02644 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02645 pgm->header = hdr;
02646 pgm->deleted = 0;
02647 pgm->undeleted = 1;
02648
02649
02650 if (box == NEW_FOLDER && urgent == 1) {
02651 pgm->unseen = 1;
02652 pgm->seen = 0;
02653 pgm->flagged = 1;
02654 pgm->unflagged = 0;
02655 } else if (box == NEW_FOLDER && urgent == 0) {
02656 pgm->unseen = 1;
02657 pgm->seen = 0;
02658 pgm->flagged = 0;
02659 pgm->unflagged = 1;
02660 } else if (box == OLD_FOLDER) {
02661 pgm->seen = 1;
02662 pgm->unseen = 0;
02663 }
02664
02665 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02666
02667 vms->vmArrayIndex = 0;
02668 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02669 vms->lastmsg = vms->vmArrayIndex - 1;
02670 mail_free_searchpgm(&pgm);
02671
02672
02673
02674
02675 if (box == 0 && !vms->dh_arraysize) {
02676 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02677 }
02678 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02679 ast_mutex_unlock(&vms->lock);
02680 return -1;
02681 }
02682
02683 ast_mutex_unlock(&vms->lock);
02684 return 0;
02685 }
02686
02687 static void write_file(char *filename, char *buffer, unsigned long len)
02688 {
02689 FILE *output;
02690
02691 output = fopen (filename, "w");
02692 if (fwrite(buffer, len, 1, output) != 1) {
02693 if (ferror(output)) {
02694 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02695 }
02696 }
02697 fclose (output);
02698 }
02699
02700 static void update_messages_by_imapuser(const char *user, unsigned long number)
02701 {
02702 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02703
02704 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02705 return;
02706 }
02707
02708 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02709 vms->msgArray[vms->vmArrayIndex++] = number;
02710 }
02711
02712 void mm_searched(MAILSTREAM *stream, unsigned long number)
02713 {
02714 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02715
02716 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02717 return;
02718
02719 update_messages_by_imapuser(user, number);
02720 }
02721
02722 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02723 {
02724 struct ast_variable *var;
02725 struct ast_vm_user *vmu;
02726
02727 vmu = ast_calloc(1, sizeof *vmu);
02728 if (!vmu)
02729 return NULL;
02730 ast_set_flag(vmu, VM_ALLOCED);
02731 populate_defaults(vmu);
02732
02733 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02734 if (var) {
02735 apply_options_full(vmu, var);
02736 ast_variables_destroy(var);
02737 return vmu;
02738 } else {
02739 ast_free(vmu);
02740 return NULL;
02741 }
02742 }
02743
02744
02745
02746 void mm_exists(MAILSTREAM * stream, unsigned long number)
02747 {
02748
02749 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02750 if (number == 0) return;
02751 set_update(stream);
02752 }
02753
02754
02755 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02756 {
02757
02758 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02759 if (number == 0) return;
02760 set_update(stream);
02761 }
02762
02763
02764 void mm_flags(MAILSTREAM * stream, unsigned long number)
02765 {
02766
02767 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02768 if (number == 0) return;
02769 set_update(stream);
02770 }
02771
02772
02773 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02774 {
02775 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02776 mm_log (string, errflg);
02777 }
02778
02779
02780 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02781 {
02782 if (delimiter == '\0') {
02783 delimiter = delim;
02784 }
02785
02786 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02787 if (attributes & LATT_NOINFERIORS)
02788 ast_debug(5, "no inferiors\n");
02789 if (attributes & LATT_NOSELECT)
02790 ast_debug(5, "no select\n");
02791 if (attributes & LATT_MARKED)
02792 ast_debug(5, "marked\n");
02793 if (attributes & LATT_UNMARKED)
02794 ast_debug(5, "unmarked\n");
02795 }
02796
02797
02798 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02799 {
02800 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02801 if (attributes & LATT_NOINFERIORS)
02802 ast_debug(5, "no inferiors\n");
02803 if (attributes & LATT_NOSELECT)
02804 ast_debug(5, "no select\n");
02805 if (attributes & LATT_MARKED)
02806 ast_debug(5, "marked\n");
02807 if (attributes & LATT_UNMARKED)
02808 ast_debug(5, "unmarked\n");
02809 }
02810
02811
02812 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02813 {
02814 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02815 if (status->flags & SA_MESSAGES)
02816 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02817 if (status->flags & SA_RECENT)
02818 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02819 if (status->flags & SA_UNSEEN)
02820 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02821 if (status->flags & SA_UIDVALIDITY)
02822 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02823 if (status->flags & SA_UIDNEXT)
02824 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02825 ast_log(AST_LOG_NOTICE, "\n");
02826 }
02827
02828
02829 void mm_log(char *string, long errflg)
02830 {
02831 switch ((short) errflg) {
02832 case NIL:
02833 ast_debug(1, "IMAP Info: %s\n", string);
02834 break;
02835 case PARSE:
02836 case WARN:
02837 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02838 break;
02839 case ERROR:
02840 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02841 break;
02842 }
02843 }
02844
02845
02846 void mm_dlog(char *string)
02847 {
02848 ast_log(AST_LOG_NOTICE, "%s\n", string);
02849 }
02850
02851
02852 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02853 {
02854 struct ast_vm_user *vmu;
02855
02856 ast_debug(4, "Entering callback mm_login\n");
02857
02858 ast_copy_string(user, mb->user, MAILTMPLEN);
02859
02860
02861 if (!ast_strlen_zero(authpassword)) {
02862 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02863 } else {
02864 AST_LIST_TRAVERSE(&users, vmu, list) {
02865 if (!strcasecmp(mb->user, vmu->imapuser)) {
02866 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02867 break;
02868 }
02869 }
02870 if (!vmu) {
02871 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02872 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02873 free_user(vmu);
02874 }
02875 }
02876 }
02877 }
02878
02879
02880 void mm_critical(MAILSTREAM * stream)
02881 {
02882 }
02883
02884
02885 void mm_nocritical(MAILSTREAM * stream)
02886 {
02887 }
02888
02889
02890 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02891 {
02892 kill (getpid (), SIGSTOP);
02893 return NIL;
02894 }
02895
02896
02897 void mm_fatal(char *string)
02898 {
02899 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02900 }
02901
02902
02903 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02904 {
02905 struct vm_state *vms;
02906 char *mailbox = stream->mailbox, *user;
02907 char buf[1024] = "";
02908 unsigned long usage = 0, limit = 0;
02909
02910 while (pquota) {
02911 usage = pquota->usage;
02912 limit = pquota->limit;
02913 pquota = pquota->next;
02914 }
02915
02916 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)))) {
02917 ast_log(AST_LOG_ERROR, "No state found.\n");
02918 return;
02919 }
02920
02921 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02922
02923 vms->quota_usage = usage;
02924 vms->quota_limit = limit;
02925 }
02926
02927 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02928 {
02929 char *start, *eol_pnt;
02930 int taglen;
02931
02932 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02933 return NULL;
02934
02935 taglen = strlen(tag) + 1;
02936 if (taglen < 1)
02937 return NULL;
02938
02939 if (!(start = strstr(header, tag)))
02940 return NULL;
02941
02942
02943 memset(buf, 0, len);
02944
02945 ast_copy_string(buf, start+taglen, len);
02946 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02947 *eol_pnt = '\0';
02948 return buf;
02949 }
02950
02951 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02952 {
02953 char *start, *quote, *eol_pnt;
02954
02955 if (ast_strlen_zero(mailbox))
02956 return NULL;
02957
02958 if (!(start = strstr(mailbox, "/user=")))
02959 return NULL;
02960
02961 ast_copy_string(buf, start+6, len);
02962
02963 if (!(quote = strchr(buf, '\"'))) {
02964 if (!(eol_pnt = strchr(buf, '/')))
02965 eol_pnt = strchr(buf,'}');
02966 *eol_pnt = '\0';
02967 return buf;
02968 } else {
02969 eol_pnt = strchr(buf+1,'\"');
02970 *eol_pnt = '\0';
02971 return buf+1;
02972 }
02973 }
02974
02975 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02976 {
02977 struct vm_state *vms_p;
02978
02979 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02980 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02981 return vms_p;
02982 }
02983 if (option_debug > 4)
02984 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02985 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02986 return NULL;
02987 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02988 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02989 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02990 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02991 vms_p->mailstream = NIL;
02992 vms_p->imapversion = vmu->imapversion;
02993 if (option_debug > 4)
02994 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02995 vms_p->updated = 1;
02996
02997 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02998 init_vm_state(vms_p);
02999 vmstate_insert(vms_p);
03000 return vms_p;
03001 }
03002
03003 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03004 {
03005 struct vmstate *vlist = NULL;
03006
03007 if (interactive) {
03008 struct vm_state *vms;
03009 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03010 vms = pthread_getspecific(ts_vmstate.key);
03011 return vms;
03012 }
03013
03014 AST_LIST_LOCK(&vmstates);
03015 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03016 if (!vlist->vms) {
03017 ast_debug(3, "error: vms is NULL for %s\n", user);
03018 continue;
03019 }
03020 if (vlist->vms->imapversion != imapversion) {
03021 continue;
03022 }
03023 if (!vlist->vms->imapuser) {
03024 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03025 continue;
03026 }
03027
03028 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03029 AST_LIST_UNLOCK(&vmstates);
03030 return vlist->vms;
03031 }
03032 }
03033 AST_LIST_UNLOCK(&vmstates);
03034
03035 ast_debug(3, "%s not found in vmstates\n", user);
03036
03037 return NULL;
03038 }
03039
03040 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03041 {
03042
03043 struct vmstate *vlist = NULL;
03044 const char *local_context = S_OR(context, "default");
03045
03046 if (interactive) {
03047 struct vm_state *vms;
03048 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03049 vms = pthread_getspecific(ts_vmstate.key);
03050 return vms;
03051 }
03052
03053 AST_LIST_LOCK(&vmstates);
03054 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03055 if (!vlist->vms) {
03056 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03057 continue;
03058 }
03059 if (vlist->vms->imapversion != imapversion) {
03060 continue;
03061 }
03062 if (!vlist->vms->username || !vlist->vms->context) {
03063 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03064 continue;
03065 }
03066
03067 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);
03068
03069 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03070 ast_debug(3, "Found it!\n");
03071 AST_LIST_UNLOCK(&vmstates);
03072 return vlist->vms;
03073 }
03074 }
03075 AST_LIST_UNLOCK(&vmstates);
03076
03077 ast_debug(3, "%s not found in vmstates\n", mailbox);
03078
03079 return NULL;
03080 }
03081
03082 static void vmstate_insert(struct vm_state *vms)
03083 {
03084 struct vmstate *v;
03085 struct vm_state *altvms;
03086
03087
03088
03089
03090 if (vms->interactive == 1) {
03091 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03092 if (altvms) {
03093 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03094 vms->newmessages = altvms->newmessages;
03095 vms->oldmessages = altvms->oldmessages;
03096 vms->vmArrayIndex = altvms->vmArrayIndex;
03097 vms->lastmsg = altvms->lastmsg;
03098 vms->curmsg = altvms->curmsg;
03099
03100 vms->persist_vms = altvms;
03101
03102 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03103 vms->mailstream = altvms->mailstream;
03104 #else
03105 vms->mailstream = NIL;
03106 #endif
03107 }
03108 return;
03109 }
03110
03111 if (!(v = ast_calloc(1, sizeof(*v))))
03112 return;
03113
03114 v->vms = vms;
03115
03116 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03117
03118 AST_LIST_LOCK(&vmstates);
03119 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03120 AST_LIST_UNLOCK(&vmstates);
03121 }
03122
03123 static void vmstate_delete(struct vm_state *vms)
03124 {
03125 struct vmstate *vc = NULL;
03126 struct vm_state *altvms = NULL;
03127
03128
03129
03130 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03131 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03132 altvms->newmessages = vms->newmessages;
03133 altvms->oldmessages = vms->oldmessages;
03134 altvms->updated = 1;
03135 vms->mailstream = mail_close(vms->mailstream);
03136
03137
03138 return;
03139 }
03140
03141 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03142
03143 AST_LIST_LOCK(&vmstates);
03144 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03145 if (vc->vms == vms) {
03146 AST_LIST_REMOVE_CURRENT(list);
03147 break;
03148 }
03149 }
03150 AST_LIST_TRAVERSE_SAFE_END
03151 AST_LIST_UNLOCK(&vmstates);
03152
03153 if (vc) {
03154 ast_mutex_destroy(&vc->vms->lock);
03155 ast_free(vc);
03156 }
03157 else
03158 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03159 }
03160
03161 static void set_update(MAILSTREAM * stream)
03162 {
03163 struct vm_state *vms;
03164 char *mailbox = stream->mailbox, *user;
03165 char buf[1024] = "";
03166
03167 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03168 if (user && option_debug > 2)
03169 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03170 return;
03171 }
03172
03173 ast_debug(3, "User %s mailbox set for update.\n", user);
03174
03175 vms->updated = 1;
03176 }
03177
03178 static void init_vm_state(struct vm_state *vms)
03179 {
03180 int x;
03181 vms->vmArrayIndex = 0;
03182 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03183 vms->msgArray[x] = 0;
03184 }
03185 ast_mutex_init(&vms->lock);
03186 }
03187
03188 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03189 {
03190 char *body_content;
03191 char *body_decoded;
03192 char *fn = is_intro ? vms->introfn : vms->fn;
03193 unsigned long len;
03194 unsigned long newlen;
03195 char filename[256];
03196
03197 if (!body || body == NIL)
03198 return -1;
03199
03200 ast_mutex_lock(&vms->lock);
03201 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03202 ast_mutex_unlock(&vms->lock);
03203 if (body_content != NIL) {
03204 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03205
03206 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03207
03208 if (!newlen) {
03209 return -1;
03210 }
03211 write_file(filename, (char *) body_decoded, newlen);
03212 } else {
03213 ast_debug(5, "Body of message is NULL.\n");
03214 return -1;
03215 }
03216 return 0;
03217 }
03218
03219
03220
03221
03222
03223
03224
03225
03226 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03227 char tmp[50];
03228 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03229 mail_list(stream, tmp, "*");
03230 }
03231
03232
03233
03234
03235
03236
03237
03238
03239 static void check_quota(struct vm_state *vms, char *mailbox) {
03240 ast_mutex_lock(&vms->lock);
03241 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03242 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03243 if (vms && vms->mailstream != NULL) {
03244 imap_getquotaroot(vms->mailstream, mailbox);
03245 } else {
03246 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03247 }
03248 ast_mutex_unlock(&vms->lock);
03249 }
03250
03251 #endif
03252
03253
03254
03255
03256
03257 static int vm_lock_path(const char *path)
03258 {
03259 switch (ast_lock_path(path)) {
03260 case AST_LOCK_TIMEOUT:
03261 return -1;
03262 default:
03263 return 0;
03264 }
03265 }
03266
03267
03268 #ifdef ODBC_STORAGE
03269 struct generic_prepare_struct {
03270 char *sql;
03271 int argc;
03272 char **argv;
03273 };
03274
03275 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03276 {
03277 struct generic_prepare_struct *gps = data;
03278 int res, i;
03279 SQLHSTMT stmt;
03280
03281 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03282 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03283 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03284 return NULL;
03285 }
03286 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03287 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03288 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03289 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03290 return NULL;
03291 }
03292 for (i = 0; i < gps->argc; i++)
03293 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03294
03295 return stmt;
03296 }
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312 static int retrieve_file(char *dir, int msgnum)
03313 {
03314 int x = 0;
03315 int res;
03316 int fd = -1;
03317 size_t fdlen = 0;
03318 void *fdm = MAP_FAILED;
03319 SQLSMALLINT colcount = 0;
03320 SQLHSTMT stmt;
03321 char sql[PATH_MAX];
03322 char fmt[80]="";
03323 char *c;
03324 char coltitle[256];
03325 SQLSMALLINT collen;
03326 SQLSMALLINT datatype;
03327 SQLSMALLINT decimaldigits;
03328 SQLSMALLINT nullable;
03329 SQLULEN colsize;
03330 SQLLEN colsize2;
03331 FILE *f = NULL;
03332 char rowdata[80];
03333 char fn[PATH_MAX];
03334 char full_fn[PATH_MAX];
03335 char msgnums[80];
03336 char *argv[] = { dir, msgnums };
03337 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03338
03339 struct odbc_obj *obj;
03340 obj = ast_odbc_request_obj(odbc_database, 0);
03341 if (obj) {
03342 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03343 c = strchr(fmt, '|');
03344 if (c)
03345 *c = '\0';
03346 if (!strcasecmp(fmt, "wav49"))
03347 strcpy(fmt, "WAV");
03348 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03349 if (msgnum > -1)
03350 make_file(fn, sizeof(fn), dir, msgnum);
03351 else
03352 ast_copy_string(fn, dir, sizeof(fn));
03353
03354
03355 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03356
03357 if (!(f = fopen(full_fn, "w+"))) {
03358 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03359 goto yuck;
03360 }
03361
03362 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03363 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03364 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03365 if (!stmt) {
03366 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03367 ast_odbc_release_obj(obj);
03368 goto yuck;
03369 }
03370 res = SQLFetch(stmt);
03371 if (res == SQL_NO_DATA) {
03372 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03373 ast_odbc_release_obj(obj);
03374 goto yuck;
03375 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03376 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03377 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03378 ast_odbc_release_obj(obj);
03379 goto yuck;
03380 }
03381 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03382 if (fd < 0) {
03383 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03384 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03385 ast_odbc_release_obj(obj);
03386 goto yuck;
03387 }
03388 res = SQLNumResultCols(stmt, &colcount);
03389 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03390 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03391 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03392 ast_odbc_release_obj(obj);
03393 goto yuck;
03394 }
03395 if (f)
03396 fprintf(f, "[message]\n");
03397 for (x = 0; x < colcount; x++) {
03398 rowdata[0] = '\0';
03399 colsize = 0;
03400 collen = sizeof(coltitle);
03401 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03402 &datatype, &colsize, &decimaldigits, &nullable);
03403 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03404 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03405 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03406 ast_odbc_release_obj(obj);
03407 goto yuck;
03408 }
03409 if (!strcasecmp(coltitle, "recording")) {
03410 off_t offset;
03411 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03412 fdlen = colsize2;
03413 if (fd > -1) {
03414 char tmp[1]="";
03415 lseek(fd, fdlen - 1, SEEK_SET);
03416 if (write(fd, tmp, 1) != 1) {
03417 close(fd);
03418 fd = -1;
03419 continue;
03420 }
03421
03422 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03423 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03424 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03425 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03426 ast_odbc_release_obj(obj);
03427 goto yuck;
03428 } else {
03429 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03430 munmap(fdm, CHUNKSIZE);
03431 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03432 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03433 unlink(full_fn);
03434 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03435 ast_odbc_release_obj(obj);
03436 goto yuck;
03437 }
03438 }
03439 }
03440 if (truncate(full_fn, fdlen) < 0) {
03441 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03442 }
03443 }
03444 } else {
03445 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03446 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03447 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03448 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03449 ast_odbc_release_obj(obj);
03450 goto yuck;
03451 }
03452 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03453 fprintf(f, "%s=%s\n", coltitle, rowdata);
03454 }
03455 }
03456 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03457 ast_odbc_release_obj(obj);
03458 } else
03459 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03460 yuck:
03461 if (f)
03462 fclose(f);
03463 if (fd > -1)
03464 close(fd);
03465 return x - 1;
03466 }
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03480 {
03481 int x = 0;
03482 int res;
03483 SQLHSTMT stmt;
03484 char sql[PATH_MAX];
03485 char rowdata[20];
03486 char *argv[] = { dir };
03487 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03488
03489 struct odbc_obj *obj;
03490 obj = ast_odbc_request_obj(odbc_database, 0);
03491 if (obj) {
03492 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03493
03494 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03495 if (!stmt) {
03496 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03497 ast_odbc_release_obj(obj);
03498 goto yuck;
03499 }
03500 res = SQLFetch(stmt);
03501 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03502 if (res == SQL_NO_DATA) {
03503 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03504 } else {
03505 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03506 }
03507
03508 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03509 ast_odbc_release_obj(obj);
03510 goto yuck;
03511 }
03512 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03513 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03514 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03515 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03516 ast_odbc_release_obj(obj);
03517 goto yuck;
03518 }
03519 if (sscanf(rowdata, "%30d", &x) != 1)
03520 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03521 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03522 ast_odbc_release_obj(obj);
03523 return x;
03524 } else
03525 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03526 yuck:
03527 return x - 1;
03528 }
03529
03530
03531
03532
03533
03534
03535
03536
03537
03538
03539 static int message_exists(char *dir, int msgnum)
03540 {
03541 int x = 0;
03542 int res;
03543 SQLHSTMT stmt;
03544 char sql[PATH_MAX];
03545 char rowdata[20];
03546 char msgnums[20];
03547 char *argv[] = { dir, msgnums };
03548 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03549
03550 struct odbc_obj *obj;
03551 obj = ast_odbc_request_obj(odbc_database, 0);
03552 if (obj) {
03553 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03554 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03555 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03556 if (!stmt) {
03557 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03558 ast_odbc_release_obj(obj);
03559 goto yuck;
03560 }
03561 res = SQLFetch(stmt);
03562 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03563 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03564 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03565 ast_odbc_release_obj(obj);
03566 goto yuck;
03567 }
03568 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03569 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03570 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03571 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03572 ast_odbc_release_obj(obj);
03573 goto yuck;
03574 }
03575 if (sscanf(rowdata, "%30d", &x) != 1)
03576 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03577 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03578 ast_odbc_release_obj(obj);
03579 } else
03580 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03581 yuck:
03582 return x;
03583 }
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594 static int count_messages(struct ast_vm_user *vmu, char *dir)
03595 {
03596 int x = 0;
03597 int res;
03598 SQLHSTMT stmt;
03599 char sql[PATH_MAX];
03600 char rowdata[20];
03601 char *argv[] = { dir };
03602 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03603
03604 struct odbc_obj *obj;
03605 obj = ast_odbc_request_obj(odbc_database, 0);
03606 if (obj) {
03607 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03608 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03609 if (!stmt) {
03610 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03611 ast_odbc_release_obj(obj);
03612 goto yuck;
03613 }
03614 res = SQLFetch(stmt);
03615 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03616 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03617 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03618 ast_odbc_release_obj(obj);
03619 goto yuck;
03620 }
03621 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03622 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03623 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03624 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03625 ast_odbc_release_obj(obj);
03626 goto yuck;
03627 }
03628 if (sscanf(rowdata, "%30d", &x) != 1)
03629 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03630 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03631 ast_odbc_release_obj(obj);
03632 return x;
03633 } else
03634 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03635 yuck:
03636 return x - 1;
03637
03638 }
03639
03640
03641
03642
03643
03644
03645
03646
03647
03648
03649
03650 static void delete_file(const char *sdir, int smsg)
03651 {
03652 SQLHSTMT stmt;
03653 char sql[PATH_MAX];
03654 char msgnums[20];
03655 char *argv[] = { NULL, msgnums };
03656 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03657 struct odbc_obj *obj;
03658
03659 argv[0] = ast_strdupa(sdir);
03660
03661 obj = ast_odbc_request_obj(odbc_database, 0);
03662 if (obj) {
03663 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03664 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03665 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03666 if (!stmt)
03667 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03668 else
03669 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03670 ast_odbc_release_obj(obj);
03671 } else
03672 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03673 return;
03674 }
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03688 {
03689 SQLHSTMT stmt;
03690 char sql[512];
03691 char msgnums[20];
03692 char msgnumd[20];
03693 struct odbc_obj *obj;
03694 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03695 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03696
03697 delete_file(ddir, dmsg);
03698 obj = ast_odbc_request_obj(odbc_database, 0);
03699 if (obj) {
03700 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03701 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03702 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);
03703 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03704 if (!stmt)
03705 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03706 else
03707 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03708 ast_odbc_release_obj(obj);
03709 } else
03710 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03711 return;
03712 }
03713
03714 struct insert_data {
03715 char *sql;
03716 const char *dir;
03717 const char *msgnums;
03718 void *data;
03719 SQLLEN datalen;
03720 SQLLEN indlen;
03721 const char *context;
03722 const char *macrocontext;
03723 const char *callerid;
03724 const char *origtime;
03725 const char *duration;
03726 const char *mailboxuser;
03727 const char *mailboxcontext;
03728 const char *category;
03729 const char *flag;
03730 };
03731
03732 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03733 {
03734 struct insert_data *data = vdata;
03735 int res;
03736 SQLHSTMT stmt;
03737
03738 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03739 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03740 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03741 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03742 return NULL;
03743 }
03744
03745 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03746 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03747 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03748 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03749 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03750 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03751 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03752 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03753 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03754 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03755 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03756 if (!ast_strlen_zero(data->category)) {
03757 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03758 }
03759 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03760 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03761 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03762 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03763 return NULL;
03764 }
03765
03766 return stmt;
03767 }
03768
03769
03770
03771
03772
03773
03774
03775
03776
03777
03778
03779
03780
03781
03782 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03783 {
03784 int res = 0;
03785 int fd = -1;
03786 void *fdm = MAP_FAILED;
03787 size_t fdlen = -1;
03788 SQLHSTMT stmt;
03789 char sql[PATH_MAX];
03790 char msgnums[20];
03791 char fn[PATH_MAX];
03792 char full_fn[PATH_MAX];
03793 char fmt[80]="";
03794 char *c;
03795 struct ast_config *cfg = NULL;
03796 struct odbc_obj *obj;
03797 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03798 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03799 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03800
03801 delete_file(dir, msgnum);
03802 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03803 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03804 return -1;
03805 }
03806
03807 do {
03808 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03809 c = strchr(fmt, '|');
03810 if (c)
03811 *c = '\0';
03812 if (!strcasecmp(fmt, "wav49"))
03813 strcpy(fmt, "WAV");
03814 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03815 if (msgnum > -1)
03816 make_file(fn, sizeof(fn), dir, msgnum);
03817 else
03818 ast_copy_string(fn, dir, sizeof(fn));
03819 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03820 cfg = ast_config_load(full_fn, config_flags);
03821 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03822 fd = open(full_fn, O_RDWR);
03823 if (fd < 0) {
03824 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03825 res = -1;
03826 break;
03827 }
03828 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03829 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03830 idata.context = "";
03831 }
03832 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03833 idata.macrocontext = "";
03834 }
03835 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03836 idata.callerid = "";
03837 }
03838 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03839 idata.origtime = "";
03840 }
03841 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03842 idata.duration = "";
03843 }
03844 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03845 idata.category = "";
03846 }
03847 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03848 idata.flag = "";
03849 }
03850 }
03851 fdlen = lseek(fd, 0, SEEK_END);
03852 lseek(fd, 0, SEEK_SET);
03853 printf("Length is %zd\n", fdlen);
03854 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03855 if (fdm == MAP_FAILED) {
03856 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03857 res = -1;
03858 break;
03859 }
03860 idata.data = fdm;
03861 idata.datalen = idata.indlen = fdlen;
03862
03863 if (!ast_strlen_zero(idata.category))
03864 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03865 else
03866 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03867
03868 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03869 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03870 } else {
03871 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03872 res = -1;
03873 }
03874 } while (0);
03875 if (obj) {
03876 ast_odbc_release_obj(obj);
03877 }
03878 if (cfg)
03879 ast_config_destroy(cfg);
03880 if (fdm != MAP_FAILED)
03881 munmap(fdm, fdlen);
03882 if (fd > -1)
03883 close(fd);
03884 return res;
03885 }
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897
03898
03899
03900 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03901 {
03902 SQLHSTMT stmt;
03903 char sql[PATH_MAX];
03904 char msgnums[20];
03905 char msgnumd[20];
03906 struct odbc_obj *obj;
03907 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03908 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03909
03910 delete_file(ddir, dmsg);
03911 obj = ast_odbc_request_obj(odbc_database, 0);
03912 if (obj) {
03913 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03914 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03915 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03916 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03917 if (!stmt)
03918 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03919 else
03920 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03921 ast_odbc_release_obj(obj);
03922 } else
03923 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03924 return;
03925 }
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938 static int remove_file(char *dir, int msgnum)
03939 {
03940 char fn[PATH_MAX];
03941 char full_fn[PATH_MAX];
03942 char msgnums[80];
03943
03944 if (msgnum > -1) {
03945 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03946 make_file(fn, sizeof(fn), dir, msgnum);
03947 } else
03948 ast_copy_string(fn, dir, sizeof(fn));
03949 ast_filedelete(fn, NULL);
03950 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03951 unlink(full_fn);
03952 return 0;
03953 }
03954 #else
03955 #ifndef IMAP_STORAGE
03956
03957
03958
03959
03960
03961
03962
03963
03964
03965 static int count_messages(struct ast_vm_user *vmu, char *dir)
03966 {
03967
03968 int vmcount = 0;
03969 DIR *vmdir = NULL;
03970 struct dirent *vment = NULL;
03971
03972 if (vm_lock_path(dir))
03973 return ERROR_LOCK_PATH;
03974
03975 if ((vmdir = opendir(dir))) {
03976 while ((vment = readdir(vmdir))) {
03977 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03978 vmcount++;
03979 }
03980 }
03981 closedir(vmdir);
03982 }
03983 ast_unlock_path(dir);
03984
03985 return vmcount;
03986 }
03987
03988
03989
03990
03991
03992
03993
03994
03995 static void rename_file(char *sfn, char *dfn)
03996 {
03997 char stxt[PATH_MAX];
03998 char dtxt[PATH_MAX];
03999 ast_filerename(sfn, dfn, NULL);
04000 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04001 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04002 if (ast_check_realtime("voicemail_data")) {
04003 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04004 }
04005 rename(stxt, dtxt);
04006 }
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04020 {
04021 int x;
04022 unsigned char map[MAXMSGLIMIT] = "";
04023 DIR *msgdir;
04024 struct dirent *msgdirent;
04025 int msgdirint;
04026 char extension[4];
04027 int stopcount = 0;
04028
04029
04030
04031
04032
04033 if (!(msgdir = opendir(dir))) {
04034 return -1;
04035 }
04036
04037 while ((msgdirent = readdir(msgdir))) {
04038 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04039 map[msgdirint] = 1;
04040 stopcount++;
04041 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04042 }
04043 }
04044 closedir(msgdir);
04045
04046 for (x = 0; x < vmu->maxmsg; x++) {
04047 if (map[x] == 1) {
04048 stopcount--;
04049 } else if (map[x] == 0 && !stopcount) {
04050 break;
04051 }
04052 }
04053
04054 return x - 1;
04055 }
04056
04057 #endif
04058 #endif
04059 #ifndef IMAP_STORAGE
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070 static int copy(char *infile, char *outfile)
04071 {
04072 int ifd;
04073 int ofd;
04074 int res;
04075 int len;
04076 char buf[4096];
04077
04078 #ifdef HARDLINK_WHEN_POSSIBLE
04079
04080 if (link(infile, outfile)) {
04081 #endif
04082 if ((ifd = open(infile, O_RDONLY)) < 0) {
04083 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04084 return -1;
04085 }
04086 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04087 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04088 close(ifd);
04089 return -1;
04090 }
04091 do {
04092 len = read(ifd, buf, sizeof(buf));
04093 if (len < 0) {
04094 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04095 close(ifd);
04096 close(ofd);
04097 unlink(outfile);
04098 }
04099 if (len) {
04100 res = write(ofd, buf, len);
04101 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04102 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04103 close(ifd);
04104 close(ofd);
04105 unlink(outfile);
04106 }
04107 }
04108 } while (len);
04109 close(ifd);
04110 close(ofd);
04111 return 0;
04112 #ifdef HARDLINK_WHEN_POSSIBLE
04113 } else {
04114
04115 return 0;
04116 }
04117 #endif
04118 }
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129 static void copy_plain_file(char *frompath, char *topath)
04130 {
04131 char frompath2[PATH_MAX], topath2[PATH_MAX];
04132 struct ast_variable *tmp,*var = NULL;
04133 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04134 ast_filecopy(frompath, topath, NULL);
04135 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04136 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04137 if (ast_check_realtime("voicemail_data")) {
04138 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04139
04140 for (tmp = var; tmp; tmp = tmp->next) {
04141 if (!strcasecmp(tmp->name, "origmailbox")) {
04142 origmailbox = tmp->value;
04143 } else if (!strcasecmp(tmp->name, "context")) {
04144 context = tmp->value;
04145 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04146 macrocontext = tmp->value;
04147 } else if (!strcasecmp(tmp->name, "exten")) {
04148 exten = tmp->value;
04149 } else if (!strcasecmp(tmp->name, "priority")) {
04150 priority = tmp->value;
04151 } else if (!strcasecmp(tmp->name, "callerchan")) {
04152 callerchan = tmp->value;
04153 } else if (!strcasecmp(tmp->name, "callerid")) {
04154 callerid = tmp->value;
04155 } else if (!strcasecmp(tmp->name, "origdate")) {
04156 origdate = tmp->value;
04157 } else if (!strcasecmp(tmp->name, "origtime")) {
04158 origtime = tmp->value;
04159 } else if (!strcasecmp(tmp->name, "category")) {
04160 category = tmp->value;
04161 } else if (!strcasecmp(tmp->name, "duration")) {
04162 duration = tmp->value;
04163 }
04164 }
04165 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);
04166 }
04167 copy(frompath2, topath2);
04168 ast_variables_destroy(var);
04169 }
04170 #endif
04171
04172
04173
04174
04175
04176
04177
04178
04179
04180 static int vm_delete(char *file)
04181 {
04182 char *txt;
04183 int txtsize = 0;
04184
04185 txtsize = (strlen(file) + 5)*sizeof(char);
04186 txt = alloca(txtsize);
04187
04188
04189
04190 if (ast_check_realtime("voicemail_data")) {
04191 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04192 }
04193 snprintf(txt, txtsize, "%s.txt", file);
04194 unlink(txt);
04195 return ast_filedelete(file, NULL);
04196 }
04197
04198
04199
04200
04201 static int inbuf(struct baseio *bio, FILE *fi)
04202 {
04203 int l;
04204
04205 if (bio->ateof)
04206 return 0;
04207
04208 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04209 if (ferror(fi))
04210 return -1;
04211
04212 bio->ateof = 1;
04213 return 0;
04214 }
04215
04216 bio->iolen = l;
04217 bio->iocp = 0;
04218
04219 return 1;
04220 }
04221
04222
04223
04224
04225 static int inchar(struct baseio *bio, FILE *fi)
04226 {
04227 if (bio->iocp>=bio->iolen) {
04228 if (!inbuf(bio, fi))
04229 return EOF;
04230 }
04231
04232 return bio->iobuf[bio->iocp++];
04233 }
04234
04235
04236
04237
04238 static int ochar(struct baseio *bio, int c, FILE *so)
04239 {
04240 if (bio->linelength >= BASELINELEN) {
04241 if (fputs(ENDL, so) == EOF) {
04242 return -1;
04243 }
04244
04245 bio->linelength = 0;
04246 }
04247
04248 if (putc(((unsigned char) c), so) == EOF) {
04249 return -1;
04250 }
04251
04252 bio->linelength++;
04253
04254 return 1;
04255 }
04256
04257
04258
04259
04260
04261
04262
04263
04264
04265
04266 static int base_encode(char *filename, FILE *so)
04267 {
04268 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04269 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04270 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04271 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04272 int i, hiteof = 0;
04273 FILE *fi;
04274 struct baseio bio;
04275
04276 memset(&bio, 0, sizeof(bio));
04277 bio.iocp = BASEMAXINLINE;
04278
04279 if (!(fi = fopen(filename, "rb"))) {
04280 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04281 return -1;
04282 }
04283
04284 while (!hiteof){
04285 unsigned char igroup[3], ogroup[4];
04286 int c, n;
04287
04288 memset(igroup, 0, sizeof(igroup));
04289
04290 for (n = 0; n < 3; n++) {
04291 if ((c = inchar(&bio, fi)) == EOF) {
04292 hiteof = 1;
04293 break;
04294 }
04295
04296 igroup[n] = (unsigned char) c;
04297 }
04298
04299 if (n > 0) {
04300 ogroup[0]= dtable[igroup[0] >> 2];
04301 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04302 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04303 ogroup[3]= dtable[igroup[2] & 0x3F];
04304
04305 if (n < 3) {
04306 ogroup[3] = '=';
04307
04308 if (n < 2)
04309 ogroup[2] = '=';
04310 }
04311
04312 for (i = 0; i < 4; i++)
04313 ochar(&bio, ogroup[i], so);
04314 }
04315 }
04316
04317 fclose(fi);
04318
04319 if (fputs(ENDL, so) == EOF) {
04320 return 0;
04321 }
04322
04323 return 1;
04324 }
04325
04326 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)
04327 {
04328 char callerid[256];
04329 char num[12];
04330 char fromdir[256], fromfile[256];
04331 struct ast_config *msg_cfg;
04332 const char *origcallerid, *origtime;
04333 char origcidname[80], origcidnum[80], origdate[80];
04334 int inttime;
04335 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04336
04337
04338 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04339 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04340 snprintf(num, sizeof(num), "%d", msgnum);
04341 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04342 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04343 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04344 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04345 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04346 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04347 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04348 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04349 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04350 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04351
04352
04353 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04354 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04355 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04356 strcat(fromfile, ".txt");
04357 }
04358 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04359 if (option_debug > 0) {
04360 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04361 }
04362 return;
04363 }
04364
04365 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04366 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04367 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04368 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04369 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04370 }
04371
04372 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04373 struct timeval tv = { inttime, };
04374 struct ast_tm tm;
04375 ast_localtime(&tv, &tm, NULL);
04376 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04377 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04378 }
04379 ast_config_destroy(msg_cfg);
04380 }
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04391 {
04392 const char *ptr;
04393
04394
04395 ast_str_set(buf, maxlen, "\"");
04396 for (ptr = from; *ptr; ptr++) {
04397 if (*ptr == '"' || *ptr == '\\') {
04398 ast_str_append(buf, maxlen, "\\%c", *ptr);
04399 } else {
04400 ast_str_append(buf, maxlen, "%c", *ptr);
04401 }
04402 }
04403 ast_str_append(buf, maxlen, "\"");
04404
04405 return ast_str_buffer(*buf);
04406 }
04407
04408
04409
04410
04411
04412 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04413 {
04414 const struct vm_zone *z = NULL;
04415 struct timeval t = ast_tvnow();
04416
04417
04418 if (!ast_strlen_zero(vmu->zonetag)) {
04419
04420 AST_LIST_LOCK(&zones);
04421 AST_LIST_TRAVERSE(&zones, z, list) {
04422 if (!strcmp(z->name, vmu->zonetag))
04423 break;
04424 }
04425 AST_LIST_UNLOCK(&zones);
04426 }
04427 ast_localtime(&t, tm, z ? z->timezone : NULL);
04428 return tm;
04429 }
04430
04431
04432
04433
04434
04435 static int check_mime(const char *str)
04436 {
04437 for (; *str; str++) {
04438 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04439 return 1;
04440 }
04441 }
04442 return 0;
04443 }
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04463 {
04464 struct ast_str *tmp = ast_str_alloca(80);
04465 int first_section = 1;
04466
04467 ast_str_reset(*end);
04468 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04469 for (; *start; start++) {
04470 int need_encoding = 0;
04471 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04472 need_encoding = 1;
04473 }
04474 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04475 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04476 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04477 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04478
04479 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04480 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04481 first_section = 0;
04482 }
04483 if (need_encoding && *start == ' ') {
04484 ast_str_append(&tmp, -1, "_");
04485 } else if (need_encoding) {
04486 ast_str_append(&tmp, -1, "=%hhX", *start);
04487 } else {
04488 ast_str_append(&tmp, -1, "%c", *start);
04489 }
04490 }
04491 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04492 return ast_str_buffer(*end);
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
04518 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)
04519 {
04520 char date[256];
04521 char host[MAXHOSTNAMELEN] = "";
04522 char who[256];
04523 char bound[256];
04524 char dur[256];
04525 struct ast_tm tm;
04526 char enc_cidnum[256] = "", enc_cidname[256] = "";
04527 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04528 char *greeting_attachment;
04529 char filename[256];
04530
04531 if (!str1 || !str2) {
04532 ast_free(str1);
04533 ast_free(str2);
04534 return;
04535 }
04536
04537 if (cidnum) {
04538 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04539 }
04540 if (cidname) {
04541 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04542 }
04543 gethostname(host, sizeof(host) - 1);
04544
04545 if (strchr(srcemail, '@')) {
04546 ast_copy_string(who, srcemail, sizeof(who));
04547 } else {
04548 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04549 }
04550
04551 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04552 if (greeting_attachment) {
04553 *greeting_attachment++ = '\0';
04554 }
04555
04556 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04557 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04558 fprintf(p, "Date: %s" ENDL, date);
04559
04560
04561 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04562
04563 if (!ast_strlen_zero(fromstring)) {
04564 struct ast_channel *ast;
04565 if ((ast = ast_dummy_channel_alloc())) {
04566 char *ptr;
04567 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04568 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04569
04570 if (check_mime(ast_str_buffer(str1))) {
04571 int first_line = 1;
04572 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04573 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04574 *ptr = '\0';
04575 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04576 first_line = 0;
04577
04578 ast_str_set(&str2, 0, "%s", ptr + 1);
04579 }
04580 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04581 } else {
04582 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04583 }
04584 ast = ast_channel_release(ast);
04585 } else {
04586 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04587 }
04588 } else {
04589 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04590 }
04591
04592 if (check_mime(vmu->fullname)) {
04593 int first_line = 1;
04594 char *ptr;
04595 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04596 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04597 *ptr = '\0';
04598 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04599 first_line = 0;
04600
04601 ast_str_set(&str2, 0, "%s", ptr + 1);
04602 }
04603 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04604 } else {
04605 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04606 }
04607
04608 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04609 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04610 struct ast_channel *ast;
04611 if ((ast = ast_dummy_channel_alloc())) {
04612 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04613 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04614 if (check_mime(ast_str_buffer(str1))) {
04615 int first_line = 1;
04616 char *ptr;
04617 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04618 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04619 *ptr = '\0';
04620 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04621 first_line = 0;
04622
04623 ast_str_set(&str2, 0, "%s", ptr + 1);
04624 }
04625 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04626 } else {
04627 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04628 }
04629 ast = ast_channel_release(ast);
04630 } else {
04631 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04632 }
04633 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04634 if (ast_strlen_zero(flag)) {
04635 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04636 } else {
04637 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04638 }
04639 } else {
04640 if (ast_strlen_zero(flag)) {
04641 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04642 } else {
04643 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04644 }
04645 }
04646
04647 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04648 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04649 if (imap) {
04650
04651 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04652
04653 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04654 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04655 #ifdef IMAP_STORAGE
04656 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04657 #else
04658 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04659 #endif
04660
04661 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04662 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04663 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04664 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04665 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04666 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04667 if (!ast_strlen_zero(category)) {
04668 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04669 } else {
04670 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04671 }
04672 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04673 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04674 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04675 }
04676 if (!ast_strlen_zero(cidnum)) {
04677 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04678 }
04679 if (!ast_strlen_zero(cidname)) {
04680 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04681 }
04682 fprintf(p, "MIME-Version: 1.0" ENDL);
04683 if (attach_user_voicemail) {
04684
04685 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04686 (int) getpid(), (unsigned int) ast_random());
04687
04688 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04689 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04690 fprintf(p, "--%s" ENDL, bound);
04691 }
04692 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04693 if (emailbody || vmu->emailbody) {
04694 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04695 struct ast_channel *ast;
04696 if ((ast = ast_dummy_channel_alloc())) {
04697 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04698 ast_str_substitute_variables(&str1, 0, ast, e_body);
04699 #ifdef IMAP_STORAGE
04700 {
04701
04702 char *line = ast_str_buffer(str1), *next;
04703 do {
04704
04705 if ((next = strchr(line, '\n'))) {
04706 *next++ = '\0';
04707 }
04708 fprintf(p, "%s" ENDL, line);
04709 line = next;
04710 } while (!ast_strlen_zero(line));
04711 }
04712 #else
04713 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04714 #endif
04715 ast = ast_channel_release(ast);
04716 } else {
04717 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04718 }
04719 } else if (msgnum > -1) {
04720 if (strcmp(vmu->mailbox, mailbox)) {
04721
04722 struct ast_config *msg_cfg;
04723 const char *v;
04724 int inttime;
04725 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04726 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04727
04728 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04729 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04730 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04731 strcat(fromfile, ".txt");
04732 }
04733 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04734 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04735 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04736 }
04737
04738
04739
04740 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04741 struct timeval tv = { inttime, };
04742 struct ast_tm tm;
04743 ast_localtime(&tv, &tm, NULL);
04744 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04745 }
04746 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04747 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04748 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04749 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04750 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04751 date, origcallerid, origdate);
04752 ast_config_destroy(msg_cfg);
04753 } else {
04754 goto plain_message;
04755 }
04756 } else {
04757 plain_message:
04758 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04759 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04760 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04761 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04762 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04763 }
04764 } else {
04765 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04766 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04767 }
04768
04769 if (imap || attach_user_voicemail) {
04770 if (!ast_strlen_zero(attach2)) {
04771 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04772 ast_debug(5, "creating second attachment filename %s\n", filename);
04773 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04774 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04775 ast_debug(5, "creating attachment filename %s\n", filename);
04776 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04777 } else {
04778 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04779 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04780 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04781 }
04782 }
04783 ast_free(str1);
04784 ast_free(str2);
04785 }
04786
04787 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)
04788 {
04789 char tmpdir[256], newtmp[256];
04790 char fname[256];
04791 char tmpcmd[256];
04792 int tmpfd = -1;
04793 int soxstatus = 0;
04794
04795
04796 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04797
04798 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04799 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04800 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04801 tmpfd = mkstemp(newtmp);
04802 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04803 ast_debug(3, "newtmp: %s\n", newtmp);
04804 if (tmpfd > -1) {
04805 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04806 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04807 attach = newtmp;
04808 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04809 } else {
04810 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04811 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04812 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04813 }
04814 }
04815 }
04816 fprintf(p, "--%s" ENDL, bound);
04817 if (msgnum > -1)
04818 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04819 else
04820 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04821 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04822 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04823 if (msgnum > -1)
04824 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04825 else
04826 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04827 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04828 base_encode(fname, p);
04829 if (last)
04830 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04831 if (tmpfd > -1) {
04832 if (soxstatus == 0) {
04833 unlink(fname);
04834 }
04835 close(tmpfd);
04836 unlink(newtmp);
04837 }
04838 return 0;
04839 }
04840
04841 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)
04842 {
04843 FILE *p = NULL;
04844 char tmp[80] = "/tmp/astmail-XXXXXX";
04845 char tmp2[256];
04846 char *stringp;
04847
04848 if (vmu && ast_strlen_zero(vmu->email)) {
04849 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04850 return(0);
04851 }
04852
04853
04854 format = ast_strdupa(format);
04855 stringp = format;
04856 strsep(&stringp, "|");
04857
04858 if (!strcmp(format, "wav49"))
04859 format = "WAV";
04860 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));
04861
04862
04863 if ((p = vm_mkftemp(tmp)) == NULL) {
04864 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04865 return -1;
04866 } else {
04867 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04868 fclose(p);
04869 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04870 ast_safe_system(tmp2);
04871 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04872 }
04873 return 0;
04874 }
04875
04876 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)
04877 {
04878 char enc_cidnum[256], enc_cidname[256];
04879 char date[256];
04880 char host[MAXHOSTNAMELEN] = "";
04881 char who[256];
04882 char dur[PATH_MAX];
04883 char tmp[80] = "/tmp/astmail-XXXXXX";
04884 char tmp2[PATH_MAX];
04885 struct ast_tm tm;
04886 FILE *p;
04887 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04888
04889 if (!str1 || !str2) {
04890 ast_free(str1);
04891 ast_free(str2);
04892 return -1;
04893 }
04894
04895 if (cidnum) {
04896 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04897 }
04898 if (cidname) {
04899 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04900 }
04901
04902 if ((p = vm_mkftemp(tmp)) == NULL) {
04903 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04904 ast_free(str1);
04905 ast_free(str2);
04906 return -1;
04907 }
04908 gethostname(host, sizeof(host)-1);
04909 if (strchr(srcemail, '@')) {
04910 ast_copy_string(who, srcemail, sizeof(who));
04911 } else {
04912 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04913 }
04914 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04915 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04916 fprintf(p, "Date: %s\n", date);
04917
04918
04919 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04920
04921 if (!ast_strlen_zero(pagerfromstring)) {
04922 struct ast_channel *ast;
04923 if ((ast = ast_dummy_channel_alloc())) {
04924 char *ptr;
04925 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04926 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04927
04928 if (check_mime(ast_str_buffer(str1))) {
04929 int first_line = 1;
04930 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04931 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04932 *ptr = '\0';
04933 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04934 first_line = 0;
04935
04936 ast_str_set(&str2, 0, "%s", ptr + 1);
04937 }
04938 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04939 } else {
04940 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04941 }
04942 ast = ast_channel_release(ast);
04943 } else {
04944 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04945 }
04946 } else {
04947 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04948 }
04949
04950 if (check_mime(vmu->fullname)) {
04951 int first_line = 1;
04952 char *ptr;
04953 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04954 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04955 *ptr = '\0';
04956 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04957 first_line = 0;
04958
04959 ast_str_set(&str2, 0, "%s", ptr + 1);
04960 }
04961 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04962 } else {
04963 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04964 }
04965
04966 if (!ast_strlen_zero(pagersubject)) {
04967 struct ast_channel *ast;
04968 if ((ast = ast_dummy_channel_alloc())) {
04969 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04970 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04971 if (check_mime(ast_str_buffer(str1))) {
04972 int first_line = 1;
04973 char *ptr;
04974 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04975 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04976 *ptr = '\0';
04977 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04978 first_line = 0;
04979
04980 ast_str_set(&str2, 0, "%s", ptr + 1);
04981 }
04982 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04983 } else {
04984 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04985 }
04986 ast = ast_channel_release(ast);
04987 } else {
04988 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04989 }
04990 } else {
04991 if (ast_strlen_zero(flag)) {
04992 fprintf(p, "Subject: New VM\n\n");
04993 } else {
04994 fprintf(p, "Subject: New %s VM\n\n", flag);
04995 }
04996 }
04997
04998 if (pagerbody) {
04999 struct ast_channel *ast;
05000 if ((ast = ast_dummy_channel_alloc())) {
05001 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05002 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05003 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05004 ast = ast_channel_release(ast);
05005 } else {
05006 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05007 }
05008 } else {
05009 fprintf(p, "New %s long %s msg in box %s\n"
05010 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05011 }
05012
05013 fclose(p);
05014 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05015 ast_safe_system(tmp2);
05016 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05017 ast_free(str1);
05018 ast_free(str2);
05019 return 0;
05020 }
05021
05022
05023
05024
05025
05026
05027
05028
05029
05030
05031 static int get_date(char *s, int len)
05032 {
05033 struct ast_tm tm;
05034 struct timeval t = ast_tvnow();
05035
05036 ast_localtime(&t, &tm, "UTC");
05037
05038 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05039 }
05040
05041 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05042 {
05043 int res;
05044 char fn[PATH_MAX];
05045 char dest[PATH_MAX];
05046
05047 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05048
05049 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05050 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05051 return -1;
05052 }
05053
05054 RETRIEVE(fn, -1, ext, context);
05055 if (ast_fileexists(fn, NULL, NULL) > 0) {
05056 res = ast_stream_and_wait(chan, fn, ecodes);
05057 if (res) {
05058 DISPOSE(fn, -1);
05059 return res;
05060 }
05061 } else {
05062
05063 DISPOSE(fn, -1);
05064 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05065 if (res)
05066 return res;
05067 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05068 if (res)
05069 return res;
05070 }
05071 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05072 return res;
05073 }
05074
05075 static void free_zone(struct vm_zone *z)
05076 {
05077 ast_free(z);
05078 }
05079
05080 #ifdef ODBC_STORAGE
05081 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05082 {
05083 int x = -1;
05084 int res;
05085 SQLHSTMT stmt = NULL;
05086 char sql[PATH_MAX];
05087 char rowdata[20];
05088 char tmp[PATH_MAX] = "";
05089 struct odbc_obj *obj = NULL;
05090 char *context;
05091 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05092
05093 if (newmsgs)
05094 *newmsgs = 0;
05095 if (oldmsgs)
05096 *oldmsgs = 0;
05097 if (urgentmsgs)
05098 *urgentmsgs = 0;
05099
05100
05101 if (ast_strlen_zero(mailbox))
05102 return 0;
05103
05104 ast_copy_string(tmp, mailbox, sizeof(tmp));
05105
05106 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05107 int u, n, o;
05108 char *next, *remaining = tmp;
05109 while ((next = strsep(&remaining, " ,"))) {
05110 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05111 return -1;
05112 }
05113 if (urgentmsgs) {
05114 *urgentmsgs += u;
05115 }
05116 if (newmsgs) {
05117 *newmsgs += n;
05118 }
05119 if (oldmsgs) {
05120 *oldmsgs += o;
05121 }
05122 }
05123 return 0;
05124 }
05125
05126 context = strchr(tmp, '@');
05127 if (context) {
05128 *context = '\0';
05129 context++;
05130 } else
05131 context = "default";
05132
05133 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05134 do {
05135 if (newmsgs) {
05136 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05137 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05138 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05139 break;
05140 }
05141 res = SQLFetch(stmt);
05142 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05143 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05144 break;
05145 }
05146 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05147 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05148 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05149 break;
05150 }
05151 *newmsgs = atoi(rowdata);
05152 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05153 }
05154
05155 if (oldmsgs) {
05156 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05157 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05158 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05159 break;
05160 }
05161 res = SQLFetch(stmt);
05162 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05163 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05164 break;
05165 }
05166 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05167 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05168 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05169 break;
05170 }
05171 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05172 *oldmsgs = atoi(rowdata);
05173 }
05174
05175 if (urgentmsgs) {
05176 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05177 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05178 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05179 break;
05180 }
05181 res = SQLFetch(stmt);
05182 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05183 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05184 break;
05185 }
05186 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05187 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05188 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05189 break;
05190 }
05191 *urgentmsgs = atoi(rowdata);
05192 }
05193
05194 x = 0;
05195 } while (0);
05196 } else {
05197 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05198 }
05199
05200 if (stmt) {
05201 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05202 }
05203 if (obj) {
05204 ast_odbc_release_obj(obj);
05205 }
05206 return x;
05207 }
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218 static int messagecount(const char *context, const char *mailbox, const char *folder)
05219 {
05220 struct odbc_obj *obj = NULL;
05221 int nummsgs = 0;
05222 int res;
05223 SQLHSTMT stmt = NULL;
05224 char sql[PATH_MAX];
05225 char rowdata[20];
05226 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05227 if (!folder)
05228 folder = "INBOX";
05229
05230 if (ast_strlen_zero(mailbox))
05231 return 0;
05232
05233 obj = ast_odbc_request_obj(odbc_database, 0);
05234 if (obj) {
05235 if (!strcmp(folder, "INBOX")) {
05236 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);
05237 } else {
05238 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05239 }
05240 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05241 if (!stmt) {
05242 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05243 goto yuck;
05244 }
05245 res = SQLFetch(stmt);
05246 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05247 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05248 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05249 goto yuck;
05250 }
05251 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05252 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05253 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05254 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05255 goto yuck;
05256 }
05257 nummsgs = atoi(rowdata);
05258 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05259 } else
05260 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05261
05262 yuck:
05263 if (obj)
05264 ast_odbc_release_obj(obj);
05265 return nummsgs;
05266 }
05267
05268
05269
05270
05271
05272
05273
05274
05275
05276 static int has_voicemail(const char *mailbox, const char *folder)
05277 {
05278 char tmp[256], *tmp2 = tmp, *box, *context;
05279 ast_copy_string(tmp, mailbox, sizeof(tmp));
05280 while ((context = box = strsep(&tmp2, ",&"))) {
05281 strsep(&context, "@");
05282 if (ast_strlen_zero(context))
05283 context = "default";
05284 if (messagecount(context, box, folder))
05285 return 1;
05286 }
05287 return 0;
05288 }
05289 #endif
05290 #ifndef IMAP_STORAGE
05291
05292
05293
05294
05295
05296
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307 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)
05308 {
05309 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05310 const char *frombox = mbox(vmu, imbox);
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 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
05318 } else {
05319 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05320 }
05321
05322 if (!dir)
05323 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05324 else
05325 ast_copy_string(fromdir, dir, sizeof(fromdir));
05326
05327 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05328 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05329
05330 if (vm_lock_path(todir))
05331 return ERROR_LOCK_PATH;
05332
05333 recipmsgnum = last_message_index(recip, todir) + 1;
05334 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05335 make_file(topath, sizeof(topath), todir, recipmsgnum);
05336 #ifndef ODBC_STORAGE
05337 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05338 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05339 } else {
05340 #endif
05341
05342
05343
05344 copy_plain_file(frompath, topath);
05345 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05346 vm_delete(topath);
05347 #ifndef ODBC_STORAGE
05348 }
05349 #endif
05350 } else {
05351 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05352 res = -1;
05353 }
05354 ast_unlock_path(todir);
05355 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05356 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05357 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05358 flag);
05359
05360 return res;
05361 }
05362 #endif
05363 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05364
05365 static int messagecount(const char *context, const char *mailbox, const char *folder)
05366 {
05367 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05368 }
05369
05370 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05371 {
05372 DIR *dir;
05373 struct dirent *de;
05374 char fn[256];
05375 int ret = 0;
05376
05377
05378 if (ast_strlen_zero(mailbox))
05379 return 0;
05380
05381 if (ast_strlen_zero(folder))
05382 folder = "INBOX";
05383 if (ast_strlen_zero(context))
05384 context = "default";
05385
05386 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05387
05388 if (!(dir = opendir(fn)))
05389 return 0;
05390
05391 while ((de = readdir(dir))) {
05392 if (!strncasecmp(de->d_name, "msg", 3)) {
05393 if (shortcircuit) {
05394 ret = 1;
05395 break;
05396 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05397 ret++;
05398 }
05399 }
05400 }
05401
05402 closedir(dir);
05403
05404 return ret;
05405 }
05406
05407
05408
05409
05410
05411
05412
05413
05414
05415
05416 static int has_voicemail(const char *mailbox, const char *folder)
05417 {
05418 char tmp[256], *tmp2 = tmp, *box, *context;
05419 ast_copy_string(tmp, mailbox, sizeof(tmp));
05420 if (ast_strlen_zero(folder)) {
05421 folder = "INBOX";
05422 }
05423 while ((box = strsep(&tmp2, ",&"))) {
05424 if ((context = strchr(box, '@')))
05425 *context++ = '\0';
05426 else
05427 context = "default";
05428 if (__has_voicemail(context, box, folder, 1))
05429 return 1;
05430
05431 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05432 return 1;
05433 }
05434 }
05435 return 0;
05436 }
05437
05438
05439 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05440 {
05441 char tmp[256];
05442 char *context;
05443
05444
05445 if (ast_strlen_zero(mailbox))
05446 return 0;
05447
05448 if (newmsgs)
05449 *newmsgs = 0;
05450 if (oldmsgs)
05451 *oldmsgs = 0;
05452 if (urgentmsgs)
05453 *urgentmsgs = 0;
05454
05455 if (strchr(mailbox, ',')) {
05456 int tmpnew, tmpold, tmpurgent;
05457 char *mb, *cur;
05458
05459 ast_copy_string(tmp, mailbox, sizeof(tmp));
05460 mb = tmp;
05461 while ((cur = strsep(&mb, ", "))) {
05462 if (!ast_strlen_zero(cur)) {
05463 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05464 return -1;
05465 else {
05466 if (newmsgs)
05467 *newmsgs += tmpnew;
05468 if (oldmsgs)
05469 *oldmsgs += tmpold;
05470 if (urgentmsgs)
05471 *urgentmsgs += tmpurgent;
05472 }
05473 }
05474 }
05475 return 0;
05476 }
05477
05478 ast_copy_string(tmp, mailbox, sizeof(tmp));
05479
05480 if ((context = strchr(tmp, '@')))
05481 *context++ = '\0';
05482 else
05483 context = "default";
05484
05485 if (newmsgs)
05486 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05487 if (oldmsgs)
05488 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05489 if (urgentmsgs)
05490 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05491
05492 return 0;
05493 }
05494
05495 #endif
05496
05497
05498 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05499 {
05500 int urgentmsgs = 0;
05501 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05502 if (newmsgs) {
05503 *newmsgs += urgentmsgs;
05504 }
05505 return res;
05506 }
05507
05508 static void run_externnotify(char *context, char *extension, const char *flag)
05509 {
05510 char arguments[255];
05511 char ext_context[256] = "";
05512 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05513 struct ast_smdi_mwi_message *mwi_msg;
05514
05515 if (!ast_strlen_zero(context))
05516 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05517 else
05518 ast_copy_string(ext_context, extension, sizeof(ext_context));
05519
05520 if (smdi_iface) {
05521 if (ast_app_has_voicemail(ext_context, NULL))
05522 ast_smdi_mwi_set(smdi_iface, extension);
05523 else
05524 ast_smdi_mwi_unset(smdi_iface, extension);
05525
05526 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05527 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05528 if (!strncmp(mwi_msg->cause, "INV", 3))
05529 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05530 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05531 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05532 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05533 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05534 } else {
05535 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05536 }
05537 }
05538
05539 if (!ast_strlen_zero(externnotify)) {
05540 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05541 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05542 } else {
05543 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05544 ast_debug(1, "Executing %s\n", arguments);
05545 ast_safe_system(arguments);
05546 }
05547 }
05548 }
05549
05550
05551
05552
05553
05554
05555 struct leave_vm_options {
05556 unsigned int flags;
05557 signed char record_gain;
05558 char *exitcontext;
05559 };
05560
05561
05562
05563
05564
05565
05566
05567
05568
05569
05570
05571 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05572 {
05573 #ifdef IMAP_STORAGE
05574 int newmsgs, oldmsgs;
05575 #else
05576 char urgdir[PATH_MAX];
05577 #endif
05578 char txtfile[PATH_MAX];
05579 char tmptxtfile[PATH_MAX];
05580 struct vm_state *vms = NULL;
05581 char callerid[256];
05582 FILE *txt;
05583 char date[256];
05584 int txtdes;
05585 int res = 0;
05586 int msgnum;
05587 int duration = 0;
05588 int ausemacro = 0;
05589 int ousemacro = 0;
05590 int ouseexten = 0;
05591 char tmpdur[16];
05592 char priority[16];
05593 char origtime[16];
05594 char dir[PATH_MAX];
05595 char tmpdir[PATH_MAX];
05596 char fn[PATH_MAX];
05597 char prefile[PATH_MAX] = "";
05598 char tempfile[PATH_MAX] = "";
05599 char ext_context[256] = "";
05600 char fmt[80];
05601 char *context;
05602 char ecodes[17] = "#";
05603 struct ast_str *tmp = ast_str_create(16);
05604 char *tmpptr;
05605 struct ast_vm_user *vmu;
05606 struct ast_vm_user svm;
05607 const char *category = NULL;
05608 const char *code;
05609 const char *alldtmf = "0123456789ABCD*#";
05610 char flag[80];
05611
05612 if (!tmp) {
05613 return -1;
05614 }
05615
05616 ast_str_set(&tmp, 0, "%s", ext);
05617 ext = ast_str_buffer(tmp);
05618 if ((context = strchr(ext, '@'))) {
05619 *context++ = '\0';
05620 tmpptr = strchr(context, '&');
05621 } else {
05622 tmpptr = strchr(ext, '&');
05623 }
05624
05625 if (tmpptr)
05626 *tmpptr++ = '\0';
05627
05628 ast_channel_lock(chan);
05629 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05630 category = ast_strdupa(category);
05631 }
05632 ast_channel_unlock(chan);
05633
05634 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05635 ast_copy_string(flag, "Urgent", sizeof(flag));
05636 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05637 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05638 } else {
05639 flag[0] = '\0';
05640 }
05641
05642 ast_debug(3, "Before find_user\n");
05643 if (!(vmu = find_user(&svm, context, ext))) {
05644 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05645 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05646 ast_free(tmp);
05647 return res;
05648 }
05649
05650 if (strcmp(vmu->context, "default"))
05651 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05652 else
05653 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05654
05655
05656
05657
05658
05659
05660 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05661 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05662 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05663 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05664 }
05665
05666
05667
05668
05669 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05670 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05671 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05672 ast_free(tmp);
05673 return -1;
05674 }
05675 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05676 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05677 ast_copy_string(prefile, tempfile, sizeof(prefile));
05678
05679 DISPOSE(tempfile, -1);
05680
05681 #ifndef IMAP_STORAGE
05682 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05683 #else
05684 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05685 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05686 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05687 }
05688 #endif
05689
05690
05691 if (ast_test_flag(vmu, VM_OPERATOR)) {
05692 if (!ast_strlen_zero(vmu->exit)) {
05693 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05694 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05695 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05696 ouseexten = 1;
05697 }
05698 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05699 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05700 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05701 ouseexten = 1;
05702 } else if (!ast_strlen_zero(chan->macrocontext)
05703 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05704 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05705 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05706 ousemacro = 1;
05707 }
05708 }
05709
05710 if (!ast_strlen_zero(vmu->exit)) {
05711 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05712 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05713 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05714 }
05715 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05716 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05717 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05718 } else if (!ast_strlen_zero(chan->macrocontext)
05719 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05720 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05721 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05722 ausemacro = 1;
05723 }
05724
05725 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05726 for (code = alldtmf; *code; code++) {
05727 char e[2] = "";
05728 e[0] = *code;
05729 if (strchr(ecodes, e[0]) == NULL
05730 && ast_canmatch_extension(chan, chan->context, e, 1,
05731 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05732 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05733 }
05734 }
05735 }
05736
05737
05738 if (!ast_strlen_zero(prefile)) {
05739 #ifdef ODBC_STORAGE
05740 int success =
05741 #endif
05742 RETRIEVE(prefile, -1, ext, context);
05743 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05744 if (ast_streamfile(chan, prefile, chan->language) > -1)
05745 res = ast_waitstream(chan, ecodes);
05746 #ifdef ODBC_STORAGE
05747 if (success == -1) {
05748
05749 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05750 store_file(prefile, vmu->mailbox, vmu->context, -1);
05751 }
05752 #endif
05753 } else {
05754 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05755 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05756 }
05757 DISPOSE(prefile, -1);
05758 if (res < 0) {
05759 ast_debug(1, "Hang up during prefile playback\n");
05760 free_user(vmu);
05761 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05762 ast_free(tmp);
05763 return -1;
05764 }
05765 }
05766 if (res == '#') {
05767
05768 ast_set_flag(options, OPT_SILENT);
05769 res = 0;
05770 }
05771
05772 if (vmu->maxmsg == 0) {
05773 if (option_debug > 2)
05774 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05775 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05776 goto leave_vm_out;
05777 }
05778 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05779 res = ast_stream_and_wait(chan, INTRO, ecodes);
05780 if (res == '#') {
05781 ast_set_flag(options, OPT_SILENT);
05782 res = 0;
05783 }
05784 }
05785 if (res > 0)
05786 ast_stopstream(chan);
05787
05788
05789 if (res == '*') {
05790 chan->exten[0] = 'a';
05791 chan->exten[1] = '\0';
05792 if (!ast_strlen_zero(vmu->exit)) {
05793 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05794 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05795 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05796 }
05797 chan->priority = 0;
05798 free_user(vmu);
05799 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05800 ast_free(tmp);
05801 return 0;
05802 }
05803
05804
05805 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05806 transfer:
05807 if (ouseexten || ousemacro) {
05808 chan->exten[0] = 'o';
05809 chan->exten[1] = '\0';
05810 if (!ast_strlen_zero(vmu->exit)) {
05811 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05812 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05813 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05814 }
05815 ast_play_and_wait(chan, "transfer");
05816 chan->priority = 0;
05817 free_user(vmu);
05818 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05819 }
05820 ast_free(tmp);
05821 return OPERATOR_EXIT;
05822 }
05823
05824
05825 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05826 if (!ast_strlen_zero(options->exitcontext))
05827 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05828 free_user(vmu);
05829 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05830 ast_free(tmp);
05831 return res;
05832 }
05833
05834 if (res < 0) {
05835 free_user(vmu);
05836 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05837 ast_free(tmp);
05838 return -1;
05839 }
05840
05841 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05842 if (!ast_strlen_zero(fmt)) {
05843 msgnum = 0;
05844
05845 #ifdef IMAP_STORAGE
05846
05847
05848 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05849 if (res < 0) {
05850 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05851 ast_free(tmp);
05852 return -1;
05853 }
05854 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05855
05856
05857
05858
05859 if (!(vms = create_vm_state_from_user(vmu))) {
05860 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05861 ast_free(tmp);
05862 return -1;
05863 }
05864 }
05865 vms->newmessages++;
05866
05867
05868 msgnum = newmsgs + oldmsgs;
05869 ast_debug(3, "Messagecount set to %d\n", msgnum);
05870 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05871
05872 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05873
05874 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05875 goto leave_vm_out;
05876 }
05877 #else
05878 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05879 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05880 if (!res)
05881 res = ast_waitstream(chan, "");
05882 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05883 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05884 inprocess_count(vmu->mailbox, vmu->context, -1);
05885 goto leave_vm_out;
05886 }
05887
05888 #endif
05889 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05890 txtdes = mkstemp(tmptxtfile);
05891 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05892 if (txtdes < 0) {
05893 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05894 if (!res)
05895 res = ast_waitstream(chan, "");
05896 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05897 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05898 inprocess_count(vmu->mailbox, vmu->context, -1);
05899 goto leave_vm_out;
05900 }
05901
05902
05903 if (res >= 0) {
05904
05905 res = ast_stream_and_wait(chan, "beep", "");
05906 }
05907
05908
05909 if (ast_check_realtime("voicemail_data")) {
05910 snprintf(priority, sizeof(priority), "%d", chan->priority);
05911 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05912 get_date(date, sizeof(date));
05913 ast_callerid_merge(callerid, sizeof(callerid),
05914 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05915 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05916 "Unknown");
05917 ast_store_realtime("voicemail_data",
05918 "origmailbox", ext,
05919 "context", chan->context,
05920 "macrocontext", chan->macrocontext,
05921 "exten", chan->exten,
05922 "priority", priority,
05923 "callerchan", chan->name,
05924 "callerid", callerid,
05925 "origdate", date,
05926 "origtime", origtime,
05927 "category", S_OR(category, ""),
05928 "filename", tmptxtfile,
05929 SENTINEL);
05930 }
05931
05932
05933 txt = fdopen(txtdes, "w+");
05934 if (txt) {
05935 get_date(date, sizeof(date));
05936 ast_callerid_merge(callerid, sizeof(callerid),
05937 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05938 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05939 "Unknown");
05940 fprintf(txt,
05941 ";\n"
05942 "; Message Information file\n"
05943 ";\n"
05944 "[message]\n"
05945 "origmailbox=%s\n"
05946 "context=%s\n"
05947 "macrocontext=%s\n"
05948 "exten=%s\n"
05949 "rdnis=%s\n"
05950 "priority=%d\n"
05951 "callerchan=%s\n"
05952 "callerid=%s\n"
05953 "origdate=%s\n"
05954 "origtime=%ld\n"
05955 "category=%s\n",
05956 ext,
05957 chan->context,
05958 chan->macrocontext,
05959 chan->exten,
05960 S_COR(chan->redirecting.from.number.valid,
05961 chan->redirecting.from.number.str, "unknown"),
05962 chan->priority,
05963 chan->name,
05964 callerid,
05965 date, (long) time(NULL),
05966 category ? category : "");
05967 } else {
05968 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05969 inprocess_count(vmu->mailbox, vmu->context, -1);
05970 if (ast_check_realtime("voicemail_data")) {
05971 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05972 }
05973 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05974 goto leave_vm_out;
05975 }
05976 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05977
05978 if (txt) {
05979 fprintf(txt, "flag=%s\n", flag);
05980 if (duration < vmu->minsecs) {
05981 fclose(txt);
05982 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmu->minsecs);
05983 ast_filedelete(tmptxtfile, NULL);
05984 unlink(tmptxtfile);
05985 if (ast_check_realtime("voicemail_data")) {
05986 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05987 }
05988 inprocess_count(vmu->mailbox, vmu->context, -1);
05989 } else {
05990 fprintf(txt, "duration=%d\n", duration);
05991 fclose(txt);
05992 if (vm_lock_path(dir)) {
05993 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05994
05995 ast_filedelete(tmptxtfile, NULL);
05996 unlink(tmptxtfile);
05997 inprocess_count(vmu->mailbox, vmu->context, -1);
05998 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05999 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06000 unlink(tmptxtfile);
06001 ast_unlock_path(dir);
06002 inprocess_count(vmu->mailbox, vmu->context, -1);
06003 if (ast_check_realtime("voicemail_data")) {
06004 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06005 }
06006 } else {
06007 #ifndef IMAP_STORAGE
06008 msgnum = last_message_index(vmu, dir) + 1;
06009 #endif
06010 make_file(fn, sizeof(fn), dir, msgnum);
06011
06012
06013 #ifndef IMAP_STORAGE
06014 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06015 #else
06016 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06017 #endif
06018
06019 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06020 ast_filerename(tmptxtfile, fn, NULL);
06021 rename(tmptxtfile, txtfile);
06022 inprocess_count(vmu->mailbox, vmu->context, -1);
06023
06024
06025
06026 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06027 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06028
06029 ast_unlock_path(dir);
06030 if (ast_check_realtime("voicemail_data")) {
06031 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06032 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06033 }
06034
06035
06036
06037 if (ast_fileexists(fn, NULL, NULL) > 0) {
06038 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06039 }
06040
06041
06042 while (tmpptr) {
06043 struct ast_vm_user recipu, *recip;
06044 char *exten, *cntx;
06045
06046 exten = strsep(&tmpptr, "&");
06047 cntx = strchr(exten, '@');
06048 if (cntx) {
06049 *cntx = '\0';
06050 cntx++;
06051 }
06052 if ((recip = find_user(&recipu, cntx, exten))) {
06053 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06054 free_user(recip);
06055 }
06056 }
06057 #ifndef IMAP_STORAGE
06058 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06059
06060 char sfn[PATH_MAX];
06061 char dfn[PATH_MAX];
06062 int x;
06063
06064 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06065 x = last_message_index(vmu, urgdir) + 1;
06066 make_file(sfn, sizeof(sfn), dir, msgnum);
06067 make_file(dfn, sizeof(dfn), urgdir, x);
06068 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06069 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06070
06071 ast_copy_string(fn, dfn, sizeof(fn));
06072 msgnum = x;
06073 }
06074 #endif
06075
06076 if (ast_fileexists(fn, NULL, NULL)) {
06077 #ifdef IMAP_STORAGE
06078 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06079 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06080 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06081 flag);
06082 #else
06083 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06084 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06085 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06086 flag);
06087 #endif
06088 }
06089
06090
06091 if (ast_fileexists(fn, NULL, NULL)) {
06092 DISPOSE(dir, msgnum);
06093 }
06094 }
06095 }
06096 } else {
06097 inprocess_count(vmu->mailbox, vmu->context, -1);
06098 }
06099 if (res == '0') {
06100 goto transfer;
06101 } else if (res > 0 && res != 't')
06102 res = 0;
06103
06104 if (duration < vmu->minsecs)
06105
06106 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06107 else
06108 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06109 } else
06110 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06111 leave_vm_out:
06112 free_user(vmu);
06113
06114 #ifdef IMAP_STORAGE
06115
06116 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06117 if (expungeonhangup == 1) {
06118 ast_mutex_lock(&vms->lock);
06119 #ifdef HAVE_IMAP_TK2006
06120 if (LEVELUIDPLUS (vms->mailstream)) {
06121 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06122 } else
06123 #endif
06124 mail_expunge(vms->mailstream);
06125 ast_mutex_unlock(&vms->lock);
06126 }
06127 #endif
06128
06129 ast_free(tmp);
06130 return res;
06131 }
06132
06133 #if !defined(IMAP_STORAGE)
06134 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06135 {
06136
06137
06138 int x, dest;
06139 char sfn[PATH_MAX];
06140 char dfn[PATH_MAX];
06141
06142 if (vm_lock_path(dir))
06143 return ERROR_LOCK_PATH;
06144
06145 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06146 make_file(sfn, sizeof(sfn), dir, x);
06147 if (EXISTS(dir, x, sfn, NULL)) {
06148
06149 if (x != dest) {
06150 make_file(dfn, sizeof(dfn), dir, dest);
06151 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06152 }
06153
06154 dest++;
06155 }
06156 }
06157 ast_unlock_path(dir);
06158
06159 return dest;
06160 }
06161 #endif
06162
06163 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06164 {
06165 int d;
06166 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06167 return d;
06168 }
06169
06170 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06171 {
06172 #ifdef IMAP_STORAGE
06173
06174
06175 char sequence[10];
06176 char mailbox[256];
06177 int res;
06178
06179
06180 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06181
06182 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06183 ast_mutex_lock(&vms->lock);
06184
06185 if (box == OLD_FOLDER) {
06186 mail_setflag(vms->mailstream, sequence, "\\Seen");
06187 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06188 } else if (box == NEW_FOLDER) {
06189 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06190 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06191 }
06192 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06193 ast_mutex_unlock(&vms->lock);
06194 return 0;
06195 }
06196
06197 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06198 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06199 if (mail_create(vms->mailstream, mailbox) == NIL)
06200 ast_debug(5, "Folder exists.\n");
06201 else
06202 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06203 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06204 ast_mutex_unlock(&vms->lock);
06205 return res;
06206 #else
06207 char *dir = vms->curdir;
06208 char *username = vms->username;
06209 char *context = vmu->context;
06210 char sfn[PATH_MAX];
06211 char dfn[PATH_MAX];
06212 char ddir[PATH_MAX];
06213 const char *dbox = mbox(vmu, box);
06214 int x, i;
06215 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06216
06217 if (vm_lock_path(ddir))
06218 return ERROR_LOCK_PATH;
06219
06220 x = last_message_index(vmu, ddir) + 1;
06221
06222 if (box == 10 && x >= vmu->maxdeletedmsg) {
06223 x--;
06224 for (i = 1; i <= x; i++) {
06225
06226 make_file(sfn, sizeof(sfn), ddir, i);
06227 make_file(dfn, sizeof(dfn), ddir, i - 1);
06228 if (EXISTS(ddir, i, sfn, NULL)) {
06229 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06230 } else
06231 break;
06232 }
06233 } else {
06234 if (x >= vmu->maxmsg) {
06235 ast_unlock_path(ddir);
06236 return -1;
06237 }
06238 }
06239 make_file(sfn, sizeof(sfn), dir, msg);
06240 make_file(dfn, sizeof(dfn), ddir, x);
06241 if (strcmp(sfn, dfn)) {
06242 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06243 }
06244 ast_unlock_path(ddir);
06245 #endif
06246 return 0;
06247 }
06248
06249 static int adsi_logo(unsigned char *buf)
06250 {
06251 int bytes = 0;
06252 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06253 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06254 return bytes;
06255 }
06256
06257 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06258 {
06259 unsigned char buf[256];
06260 int bytes = 0;
06261 int x;
06262 char num[5];
06263
06264 *useadsi = 0;
06265 bytes += ast_adsi_data_mode(buf + bytes);
06266 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06267
06268 bytes = 0;
06269 bytes += adsi_logo(buf);
06270 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06271 #ifdef DISPLAY
06272 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06273 #endif
06274 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06275 bytes += ast_adsi_data_mode(buf + bytes);
06276 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06277
06278 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06279 bytes = 0;
06280 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06281 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06282 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06283 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06284 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06285 return 0;
06286 }
06287
06288 #ifdef DISPLAY
06289
06290 bytes = 0;
06291 bytes += ast_adsi_logo(buf);
06292 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06293 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06294 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06295 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06296 #endif
06297 bytes = 0;
06298 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06299 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06300 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06301 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06302 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06303 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06304 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06305
06306 #ifdef DISPLAY
06307
06308 bytes = 0;
06309 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06310 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06311
06312 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06313 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06314 #endif
06315
06316 bytes = 0;
06317
06318 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06319 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06320 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06321 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06322 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06323 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06324 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06325
06326 #ifdef DISPLAY
06327
06328 bytes = 0;
06329 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06330 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06331 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06332 #endif
06333
06334 bytes = 0;
06335 for (x = 0; x < 5; x++) {
06336 snprintf(num, sizeof(num), "%d", x);
06337 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06338 }
06339 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06340 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06341
06342 #ifdef DISPLAY
06343
06344 bytes = 0;
06345 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06346 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06347 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06348 #endif
06349
06350 if (ast_adsi_end_download(chan)) {
06351 bytes = 0;
06352 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06353 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06354 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06355 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06356 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06357 return 0;
06358 }
06359 bytes = 0;
06360 bytes += ast_adsi_download_disconnect(buf + bytes);
06361 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06362 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06363
06364 ast_debug(1, "Done downloading scripts...\n");
06365
06366 #ifdef DISPLAY
06367
06368 bytes = 0;
06369 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06370 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06371 #endif
06372 ast_debug(1, "Restarting session...\n");
06373
06374 bytes = 0;
06375
06376 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06377 *useadsi = 1;
06378 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06379 } else
06380 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06381
06382 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06383 return 0;
06384 }
06385
06386 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06387 {
06388 int x;
06389 if (!ast_adsi_available(chan))
06390 return;
06391 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06392 if (x < 0)
06393 return;
06394 if (!x) {
06395 if (adsi_load_vmail(chan, useadsi)) {
06396 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06397 return;
06398 }
06399 } else
06400 *useadsi = 1;
06401 }
06402
06403 static void adsi_login(struct ast_channel *chan)
06404 {
06405 unsigned char buf[256];
06406 int bytes = 0;
06407 unsigned char keys[8];
06408 int x;
06409 if (!ast_adsi_available(chan))
06410 return;
06411
06412 for (x = 0; x < 8; x++)
06413 keys[x] = 0;
06414
06415 keys[3] = ADSI_KEY_APPS + 3;
06416
06417 bytes += adsi_logo(buf + bytes);
06418 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06419 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06420 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06421 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06422 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06423 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06424 bytes += ast_adsi_set_keys(buf + bytes, keys);
06425 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06426 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06427 }
06428
06429 static void adsi_password(struct ast_channel *chan)
06430 {
06431 unsigned char buf[256];
06432 int bytes = 0;
06433 unsigned char keys[8];
06434 int x;
06435 if (!ast_adsi_available(chan))
06436 return;
06437
06438 for (x = 0; x < 8; x++)
06439 keys[x] = 0;
06440
06441 keys[3] = ADSI_KEY_APPS + 3;
06442
06443 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06444 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06445 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06446 bytes += ast_adsi_set_keys(buf + bytes, keys);
06447 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06448 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06449 }
06450
06451 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06452 {
06453 unsigned char buf[256];
06454 int bytes = 0;
06455 unsigned char keys[8];
06456 int x, y;
06457
06458 if (!ast_adsi_available(chan))
06459 return;
06460
06461 for (x = 0; x < 5; x++) {
06462 y = ADSI_KEY_APPS + 12 + start + x;
06463 if (y > ADSI_KEY_APPS + 12 + 4)
06464 y = 0;
06465 keys[x] = ADSI_KEY_SKT | y;
06466 }
06467 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06468 keys[6] = 0;
06469 keys[7] = 0;
06470
06471 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06472 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06473 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06474 bytes += ast_adsi_set_keys(buf + bytes, keys);
06475 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06476
06477 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06478 }
06479
06480 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06481 {
06482 int bytes = 0;
06483 unsigned char buf[256];
06484 char buf1[256], buf2[256];
06485 char fn2[PATH_MAX];
06486
06487 char cid[256] = "";
06488 char *val;
06489 char *name, *num;
06490 char datetime[21] = "";
06491 FILE *f;
06492
06493 unsigned char keys[8];
06494
06495 int x;
06496
06497 if (!ast_adsi_available(chan))
06498 return;
06499
06500
06501 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06502 f = fopen(fn2, "r");
06503 if (f) {
06504 while (!feof(f)) {
06505 if (!fgets((char *) buf, sizeof(buf), f)) {
06506 continue;
06507 }
06508 if (!feof(f)) {
06509 char *stringp = NULL;
06510 stringp = (char *) buf;
06511 strsep(&stringp, "=");
06512 val = strsep(&stringp, "=");
06513 if (!ast_strlen_zero(val)) {
06514 if (!strcmp((char *) buf, "callerid"))
06515 ast_copy_string(cid, val, sizeof(cid));
06516 if (!strcmp((char *) buf, "origdate"))
06517 ast_copy_string(datetime, val, sizeof(datetime));
06518 }
06519 }
06520 }
06521 fclose(f);
06522 }
06523
06524 for (x = 0; x < 5; x++)
06525 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06526 keys[6] = 0x0;
06527 keys[7] = 0x0;
06528
06529 if (!vms->curmsg) {
06530
06531 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06532 }
06533 if (vms->curmsg >= vms->lastmsg) {
06534
06535 if (vms->curmsg) {
06536
06537 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06538 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06539
06540 } else {
06541
06542 keys[3] = 1;
06543 }
06544 }
06545
06546 if (!ast_strlen_zero(cid)) {
06547 ast_callerid_parse(cid, &name, &num);
06548 if (!name)
06549 name = num;
06550 } else
06551 name = "Unknown Caller";
06552
06553
06554
06555 if (vms->deleted[vms->curmsg])
06556 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06557
06558
06559 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06560 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06561 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06562 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06563
06564 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06565 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06566 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06567 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06568 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06569 bytes += ast_adsi_set_keys(buf + bytes, keys);
06570 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06571
06572 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06573 }
06574
06575 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06576 {
06577 int bytes = 0;
06578 unsigned char buf[256];
06579 unsigned char keys[8];
06580
06581 int x;
06582
06583 if (!ast_adsi_available(chan))
06584 return;
06585
06586
06587 for (x = 0; x < 5; x++)
06588 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06589
06590 keys[6] = 0x0;
06591 keys[7] = 0x0;
06592
06593 if (!vms->curmsg) {
06594
06595 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06596 }
06597 if (vms->curmsg >= vms->lastmsg) {
06598
06599 if (vms->curmsg) {
06600
06601 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06602 } else {
06603
06604 keys[3] = 1;
06605 }
06606 }
06607
06608
06609 if (vms->deleted[vms->curmsg])
06610 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06611
06612
06613 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06614 bytes += ast_adsi_set_keys(buf + bytes, keys);
06615 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06616
06617 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06618 }
06619
06620 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06621 {
06622 unsigned char buf[256] = "";
06623 char buf1[256] = "", buf2[256] = "";
06624 int bytes = 0;
06625 unsigned char keys[8];
06626 int x;
06627
06628 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06629 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06630 if (!ast_adsi_available(chan))
06631 return;
06632 if (vms->newmessages) {
06633 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06634 if (vms->oldmessages) {
06635 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06636 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06637 } else {
06638 snprintf(buf2, sizeof(buf2), "%s.", newm);
06639 }
06640 } else if (vms->oldmessages) {
06641 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06642 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06643 } else {
06644 strcpy(buf1, "You have no messages.");
06645 buf2[0] = ' ';
06646 buf2[1] = '\0';
06647 }
06648 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06649 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06650 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06651
06652 for (x = 0; x < 6; x++)
06653 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06654 keys[6] = 0;
06655 keys[7] = 0;
06656
06657
06658 if (vms->lastmsg < 0)
06659 keys[0] = 1;
06660 bytes += ast_adsi_set_keys(buf + bytes, keys);
06661
06662 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06663
06664 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06665 }
06666
06667 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06668 {
06669 unsigned char buf[256] = "";
06670 char buf1[256] = "", buf2[256] = "";
06671 int bytes = 0;
06672 unsigned char keys[8];
06673 int x;
06674
06675 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06676
06677 if (!ast_adsi_available(chan))
06678 return;
06679
06680
06681 for (x = 0; x < 6; x++)
06682 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06683
06684 keys[6] = 0;
06685 keys[7] = 0;
06686
06687 if ((vms->lastmsg + 1) < 1)
06688 keys[0] = 0;
06689
06690 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06691 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06692
06693 if (vms->lastmsg + 1)
06694 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06695 else
06696 strcpy(buf2, "no messages.");
06697 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06698 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06699 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06700 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06701 bytes += ast_adsi_set_keys(buf + bytes, keys);
06702
06703 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06704
06705 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06706
06707 }
06708
06709
06710
06711
06712
06713
06714
06715
06716
06717
06718
06719
06720
06721
06722
06723 static void adsi_goodbye(struct ast_channel *chan)
06724 {
06725 unsigned char buf[256];
06726 int bytes = 0;
06727
06728 if (!ast_adsi_available(chan))
06729 return;
06730 bytes += adsi_logo(buf + bytes);
06731 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06732 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06733 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06734 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06735
06736 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06737 }
06738
06739
06740
06741
06742
06743 static int get_folder(struct ast_channel *chan, int start)
06744 {
06745 int x;
06746 int d;
06747 char fn[PATH_MAX];
06748 d = ast_play_and_wait(chan, "vm-press");
06749 if (d)
06750 return d;
06751 for (x = start; x < 5; x++) {
06752 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06753 return d;
06754 d = ast_play_and_wait(chan, "vm-for");
06755 if (d)
06756 return d;
06757 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06758
06759
06760
06761
06762 if (x == 0) {
06763 if (ast_fileexists(fn, NULL, NULL)) {
06764 d = vm_play_folder_name(chan, fn);
06765 } else {
06766 ast_verb(1, "failed to find %s\n", fn);
06767 d = vm_play_folder_name(chan, "vm-INBOX");
06768 }
06769 } else {
06770 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06771 d = vm_play_folder_name(chan, fn);
06772 }
06773
06774 if (d)
06775 return d;
06776 d = ast_waitfordigit(chan, 500);
06777 if (d)
06778 return d;
06779 }
06780
06781 d = ast_play_and_wait(chan, "vm-tocancel");
06782 if (d)
06783 return d;
06784 d = ast_waitfordigit(chan, 4000);
06785 return d;
06786 }
06787
06788
06789
06790
06791
06792
06793
06794
06795
06796
06797
06798
06799
06800 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06801 {
06802 int res = 0;
06803 int loops = 0;
06804
06805 res = ast_play_and_wait(chan, fn);
06806 while (((res < '0') || (res > '9')) &&
06807 (res != '#') && (res >= 0) &&
06808 loops < 4) {
06809 res = get_folder(chan, 0);
06810 loops++;
06811 }
06812 if (loops == 4) {
06813 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06814 return '#';
06815 }
06816 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06817 return res;
06818 }
06819
06820
06821
06822
06823
06824
06825
06826
06827
06828
06829
06830
06831
06832
06833
06834
06835
06836
06837
06838 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06839 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06840 {
06841 #ifdef IMAP_STORAGE
06842 int res;
06843 #endif
06844 int cmd = 0;
06845 int retries = 0, prepend_duration = 0, already_recorded = 0;
06846 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06847 char textfile[PATH_MAX];
06848 struct ast_config *msg_cfg;
06849 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06850 #ifndef IMAP_STORAGE
06851 signed char zero_gain = 0;
06852 #endif
06853 const char *duration_str;
06854
06855
06856 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06857 strcpy(textfile, msgfile);
06858 strcpy(backup, msgfile);
06859 strcpy(backup_textfile, msgfile);
06860 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06861 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06862 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06863
06864 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06865 *duration = atoi(duration_str);
06866 } else {
06867 *duration = 0;
06868 }
06869
06870 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06871 if (cmd)
06872 retries = 0;
06873 switch (cmd) {
06874 case '1':
06875
06876 #ifdef IMAP_STORAGE
06877
06878 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06879 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06880 res = ast_play_and_wait(chan, INTRO);
06881 res = ast_play_and_wait(chan, "beep");
06882 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, record_gain, vms, flag);
06883 cmd = 't';
06884 #else
06885
06886
06887
06888 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06889 strcpy(textfile, msgfile);
06890 strncat(textfile, ".txt", sizeof(textfile) - 1);
06891 *duration = 0;
06892
06893
06894 if (!msg_cfg) {
06895 cmd = 0;
06896 break;
06897 }
06898
06899
06900 #ifndef IMAP_STORAGE
06901 if (already_recorded) {
06902 ast_filecopy(backup, msgfile, NULL);
06903 copy(backup_textfile, textfile);
06904 }
06905 else {
06906 ast_filecopy(msgfile, backup, NULL);
06907 copy(textfile, backup_textfile);
06908 }
06909 #endif
06910 already_recorded = 1;
06911
06912 if (record_gain)
06913 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06914
06915 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06916
06917 if (cmd == 'S') {
06918 ast_stream_and_wait(chan, vm_pls_try_again, "");
06919 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06920 ast_filerename(backup, msgfile, NULL);
06921 }
06922
06923 if (record_gain)
06924 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06925
06926
06927 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06928 *duration = atoi(duration_str);
06929
06930 if (prepend_duration) {
06931 struct ast_category *msg_cat;
06932
06933 char duration_buf[12];
06934
06935 *duration += prepend_duration;
06936 msg_cat = ast_category_get(msg_cfg, "message");
06937 snprintf(duration_buf, 11, "%ld", *duration);
06938 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06939 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06940 }
06941 }
06942
06943 #endif
06944 break;
06945 case '2':
06946
06947 #ifdef IMAP_STORAGE
06948 *vms->introfn = '\0';
06949 #endif
06950 cmd = 't';
06951 break;
06952 case '*':
06953 cmd = '*';
06954 break;
06955 default:
06956
06957 already_recorded = 0;
06958
06959 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06960
06961 if (!cmd) {
06962 cmd = ast_play_and_wait(chan, "vm-starmain");
06963
06964 }
06965 if (!cmd) {
06966 cmd = ast_waitfordigit(chan, 6000);
06967 }
06968 if (!cmd) {
06969 retries++;
06970 }
06971 if (retries > 3) {
06972 cmd = '*';
06973 }
06974 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
06975 }
06976 }
06977
06978 if (msg_cfg)
06979 ast_config_destroy(msg_cfg);
06980 if (prepend_duration)
06981 *duration = prepend_duration;
06982
06983 if (already_recorded && cmd == -1) {
06984
06985 ast_filerename(backup, msgfile, NULL);
06986 rename(backup_textfile, textfile);
06987 }
06988
06989 if (cmd == 't' || cmd == 'S')
06990 cmd = 0;
06991 return cmd;
06992 }
06993
06994 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06995 {
06996 struct ast_event *event;
06997 char *mailbox, *context;
06998
06999
07000 context = mailbox = ast_strdupa(box);
07001 strsep(&context, "@");
07002 if (ast_strlen_zero(context))
07003 context = "default";
07004
07005 if (!(event = ast_event_new(AST_EVENT_MWI,
07006 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07007 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07008 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07009 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07010 AST_EVENT_IE_END))) {
07011 return;
07012 }
07013
07014 ast_event_queue_and_cache(event);
07015 }
07016
07017
07018
07019
07020
07021
07022
07023
07024
07025
07026
07027
07028
07029
07030
07031 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)
07032 {
07033 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07034 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07035 const char *category;
07036 char *myserveremail = serveremail;
07037
07038 ast_channel_lock(chan);
07039 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07040 category = ast_strdupa(category);
07041 }
07042 ast_channel_unlock(chan);
07043
07044 #ifndef IMAP_STORAGE
07045 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07046 #else
07047 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07048 #endif
07049 make_file(fn, sizeof(fn), todir, msgnum);
07050 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07051
07052 if (!ast_strlen_zero(vmu->attachfmt)) {
07053 if (strstr(fmt, vmu->attachfmt))
07054 fmt = vmu->attachfmt;
07055 else
07056 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);
07057 }
07058
07059
07060 fmt = ast_strdupa(fmt);
07061 stringp = fmt;
07062 strsep(&stringp, "|");
07063
07064 if (!ast_strlen_zero(vmu->serveremail))
07065 myserveremail = vmu->serveremail;
07066
07067 if (!ast_strlen_zero(vmu->email)) {
07068 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07069
07070 if (attach_user_voicemail)
07071 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07072
07073
07074 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07075
07076 if (attach_user_voicemail)
07077 DISPOSE(todir, msgnum);
07078 }
07079
07080 if (!ast_strlen_zero(vmu->pager)) {
07081 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07082 }
07083
07084 if (ast_test_flag(vmu, VM_DELETE))
07085 DELETE(todir, msgnum, fn, vmu);
07086
07087
07088 if (ast_app_has_voicemail(ext_context, NULL))
07089 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07090
07091 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07092
07093 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);
07094 run_externnotify(vmu->context, vmu->mailbox, flag);
07095
07096 #ifdef IMAP_STORAGE
07097 vm_delete(fn);
07098 if (ast_test_flag(vmu, VM_DELETE)) {
07099 vm_imap_delete(NULL, vms->curmsg, vmu);
07100 vms->newmessages--;
07101 }
07102 #endif
07103
07104 return 0;
07105 }
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 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)
07135 {
07136 #ifdef IMAP_STORAGE
07137 int todircount = 0;
07138 struct vm_state *dstvms;
07139 #endif
07140 char username[70]="";
07141 char fn[PATH_MAX];
07142 char ecodes[16] = "#";
07143 int res = 0, cmd = 0;
07144 struct ast_vm_user *receiver = NULL, *vmtmp;
07145 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07146 char *stringp;
07147 const char *s;
07148 int saved_messages = 0;
07149 int valid_extensions = 0;
07150 char *dir;
07151 int curmsg;
07152 char urgent_str[7] = "";
07153 int prompt_played = 0;
07154 #ifndef IMAP_STORAGE
07155 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07156 #endif
07157 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07158 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07159 }
07160
07161 if (vms == NULL) return -1;
07162 dir = vms->curdir;
07163 curmsg = vms->curmsg;
07164
07165 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07166 while (!res && !valid_extensions) {
07167 int use_directory = 0;
07168 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07169 int done = 0;
07170 int retries = 0;
07171 cmd = 0;
07172 while ((cmd >= 0) && !done ){
07173 if (cmd)
07174 retries = 0;
07175 switch (cmd) {
07176 case '1':
07177 use_directory = 0;
07178 done = 1;
07179 break;
07180 case '2':
07181 use_directory = 1;
07182 done = 1;
07183 break;
07184 case '*':
07185 cmd = 't';
07186 done = 1;
07187 break;
07188 default:
07189
07190 cmd = ast_play_and_wait(chan, "vm-forward");
07191 if (!cmd) {
07192 cmd = ast_waitfordigit(chan, 3000);
07193 }
07194 if (!cmd) {
07195 retries++;
07196 }
07197 if (retries > 3) {
07198 cmd = 't';
07199 done = 1;
07200 }
07201 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07202 }
07203 }
07204 if (cmd < 0 || cmd == 't')
07205 break;
07206 }
07207
07208 if (use_directory) {
07209
07210
07211 char old_context[sizeof(chan->context)];
07212 char old_exten[sizeof(chan->exten)];
07213 int old_priority;
07214 struct ast_app* directory_app;
07215
07216 directory_app = pbx_findapp("Directory");
07217 if (directory_app) {
07218 char vmcontext[256];
07219
07220 memcpy(old_context, chan->context, sizeof(chan->context));
07221 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07222 old_priority = chan->priority;
07223
07224
07225 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07226 res = pbx_exec(chan, directory_app, vmcontext);
07227
07228 ast_copy_string(username, chan->exten, sizeof(username));
07229
07230
07231 memcpy(chan->context, old_context, sizeof(chan->context));
07232 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07233 chan->priority = old_priority;
07234 } else {
07235 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07236 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07237 }
07238 } else {
07239
07240 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07241 res = ast_streamfile(chan, "vm-extension", chan->language);
07242 prompt_played++;
07243 if (res || prompt_played > 4)
07244 break;
07245 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07246 break;
07247 }
07248
07249
07250 if (ast_strlen_zero(username))
07251 continue;
07252 stringp = username;
07253 s = strsep(&stringp, "*");
07254
07255 valid_extensions = 1;
07256 while (s) {
07257 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07258 int oldmsgs;
07259 int newmsgs;
07260 int capacity;
07261 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07262 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07263
07264 res = ast_play_and_wait(chan, "pbx-invalid");
07265 valid_extensions = 0;
07266 break;
07267 }
07268 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07269 if ((newmsgs + oldmsgs) >= capacity) {
07270 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07271 res = ast_play_and_wait(chan, "vm-mailboxfull");
07272 valid_extensions = 0;
07273 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07274 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07275 free_user(vmtmp);
07276 }
07277 inprocess_count(receiver->mailbox, receiver->context, -1);
07278 break;
07279 }
07280 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07281 } else {
07282
07283
07284
07285
07286
07287 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07288 free_user(receiver);
07289 }
07290 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07291
07292 res = ast_play_and_wait(chan, "pbx-invalid");
07293 valid_extensions = 0;
07294 break;
07295 }
07296
07297
07298 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07299 RETRIEVE(fn, -1, s, receiver->context);
07300 if (ast_fileexists(fn, NULL, NULL) > 0) {
07301 res = ast_stream_and_wait(chan, fn, ecodes);
07302 if (res) {
07303 DISPOSE(fn, -1);
07304 return res;
07305 }
07306 } else {
07307 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07308 }
07309 DISPOSE(fn, -1);
07310
07311 s = strsep(&stringp, "*");
07312 }
07313
07314 if (valid_extensions)
07315 break;
07316 }
07317
07318 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07319 return res;
07320 if (is_new_message == 1) {
07321 struct leave_vm_options leave_options;
07322 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07323 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07324
07325
07326 memset(&leave_options, 0, sizeof(leave_options));
07327 leave_options.record_gain = record_gain;
07328 cmd = leave_voicemail(chan, mailbox, &leave_options);
07329 } else {
07330
07331 long duration = 0;
07332 struct vm_state vmstmp;
07333 int copy_msg_result = 0;
07334 memcpy(&vmstmp, vms, sizeof(vmstmp));
07335
07336 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07337
07338 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07339 if (!cmd) {
07340 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07341 #ifdef IMAP_STORAGE
07342 int attach_user_voicemail;
07343 char *myserveremail = serveremail;
07344
07345
07346 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07347 if (!dstvms) {
07348 dstvms = create_vm_state_from_user(vmtmp);
07349 }
07350 if (dstvms) {
07351 init_mailstream(dstvms, 0);
07352 if (!dstvms->mailstream) {
07353 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07354 } else {
07355 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07356 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07357 }
07358 } else {
07359 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07360 }
07361 if (!ast_strlen_zero(vmtmp->serveremail))
07362 myserveremail = vmtmp->serveremail;
07363 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07364
07365 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07366 dstvms->curbox,
07367 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07368 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07369 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07370 NULL, urgent_str);
07371 #else
07372 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07373 #endif
07374 saved_messages++;
07375 AST_LIST_REMOVE_CURRENT(list);
07376 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07377 free_user(vmtmp);
07378 if (res)
07379 break;
07380 }
07381 AST_LIST_TRAVERSE_SAFE_END;
07382 if (saved_messages > 0 && !copy_msg_result) {
07383
07384
07385
07386
07387
07388
07389
07390
07391 #ifdef IMAP_STORAGE
07392
07393 if (ast_strlen_zero(vmstmp.introfn))
07394 #endif
07395 res = ast_play_and_wait(chan, "vm-msgsaved");
07396 }
07397 #ifndef IMAP_STORAGE
07398 else {
07399
07400 res = ast_play_and_wait(chan, "vm-mailboxfull");
07401 }
07402
07403 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07404 strcpy(textfile, msgfile);
07405 strcpy(backup, msgfile);
07406 strcpy(backup_textfile, msgfile);
07407 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07408 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07409 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07410 if (ast_fileexists(backup, NULL, NULL) > 0) {
07411 ast_filerename(backup, msgfile, NULL);
07412 rename(backup_textfile, textfile);
07413 }
07414 #endif
07415 }
07416 DISPOSE(dir, curmsg);
07417 #ifndef IMAP_STORAGE
07418 if (cmd) {
07419 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07420 strcpy(textfile, msgfile);
07421 strcpy(backup_textfile, msgfile);
07422 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07423 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07424 rename(backup_textfile, textfile);
07425 }
07426 #endif
07427 }
07428
07429
07430 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07431 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07432 free_user(vmtmp);
07433 }
07434 return res ? res : cmd;
07435 }
07436
07437 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07438 {
07439 int res;
07440 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07441 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07442 return res;
07443 }
07444
07445 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07446 {
07447 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07448 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);
07449 }
07450
07451 static int play_message_category(struct ast_channel *chan, const char *category)
07452 {
07453 int res = 0;
07454
07455 if (!ast_strlen_zero(category))
07456 res = ast_play_and_wait(chan, category);
07457
07458 if (res) {
07459 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07460 res = 0;
07461 }
07462
07463 return res;
07464 }
07465
07466 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07467 {
07468 int res = 0;
07469 struct vm_zone *the_zone = NULL;
07470 time_t t;
07471
07472 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07473 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07474 return 0;
07475 }
07476
07477
07478 if (!ast_strlen_zero(vmu->zonetag)) {
07479
07480 struct vm_zone *z;
07481 AST_LIST_LOCK(&zones);
07482 AST_LIST_TRAVERSE(&zones, z, list) {
07483 if (!strcmp(z->name, vmu->zonetag)) {
07484 the_zone = z;
07485 break;
07486 }
07487 }
07488 AST_LIST_UNLOCK(&zones);
07489 }
07490
07491
07492 #if 0
07493
07494 ast_localtime(&t, &time_now, NULL);
07495 tv_now = ast_tvnow();
07496 ast_localtime(&tv_now, &time_then, NULL);
07497
07498
07499 if (time_now.tm_year == time_then.tm_year)
07500 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07501 else
07502 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07503 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07504
07505
07506 #endif
07507 if (the_zone) {
07508 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07509 } else if (!strncasecmp(chan->language, "de", 2)) {
07510 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07511 } else if (!strncasecmp(chan->language, "gr", 2)) {
07512 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07513 } else if (!strncasecmp(chan->language, "it", 2)) {
07514 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);
07515 } else if (!strncasecmp(chan->language, "nl", 2)) {
07516 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07517 } else if (!strncasecmp(chan->language, "no", 2)) {
07518 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07519 } else if (!strncasecmp(chan->language, "pl", 2)) {
07520 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07521 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07522 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);
07523 } else if (!strncasecmp(chan->language, "se", 2)) {
07524 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07525 } else if (!strncasecmp(chan->language, "zh", 2)) {
07526 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07527 } else if (!strncasecmp(chan->language, "vi", 2)) {
07528 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);
07529 } else {
07530 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07531 }
07532 #if 0
07533 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07534 #endif
07535 return res;
07536 }
07537
07538
07539
07540 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07541 {
07542 int res = 0;
07543 int i;
07544 char *callerid, *name;
07545 char prefile[PATH_MAX] = "";
07546
07547
07548
07549
07550
07551
07552
07553
07554
07555 if ((cid == NULL)||(context == NULL))
07556 return res;
07557
07558
07559 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07560 ast_callerid_parse(cid, &name, &callerid);
07561 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07562
07563
07564 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07565 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07566 if ((strcmp(cidinternalcontexts[i], context) == 0))
07567 break;
07568 }
07569 if (i != MAX_NUM_CID_CONTEXTS){
07570 if (!res) {
07571 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07572 if (!ast_strlen_zero(prefile)) {
07573
07574 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07575 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07576 if (!callback)
07577 res = wait_file2(chan, vms, "vm-from");
07578 res = ast_stream_and_wait(chan, prefile, "");
07579 } else {
07580 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07581
07582 if (!callback)
07583 res = wait_file2(chan, vms, "vm-from-extension");
07584 res = ast_say_digit_str(chan, callerid, "", chan->language);
07585 }
07586 }
07587 }
07588 } else if (!res) {
07589 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07590
07591 if (!callback)
07592 res = wait_file2(chan, vms, "vm-from-phonenumber");
07593 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07594 }
07595 } else {
07596
07597 ast_debug(1, "VM-CID: From an unknown number\n");
07598
07599 res = wait_file2(chan, vms, "vm-unknown-caller");
07600 }
07601 return res;
07602 }
07603
07604 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07605 {
07606 int res = 0;
07607 int durationm;
07608 int durations;
07609
07610 if (duration == NULL)
07611 return res;
07612
07613
07614 durations = atoi(duration);
07615 durationm = (durations / 60);
07616
07617 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07618
07619 if ((!res) && (durationm >= minduration)) {
07620 res = wait_file2(chan, vms, "vm-duration");
07621
07622
07623 if (!strncasecmp(chan->language, "pl", 2)) {
07624 div_t num = div(durationm, 10);
07625
07626 if (durationm == 1) {
07627 res = ast_play_and_wait(chan, "digits/1z");
07628 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07629 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07630 if (num.rem == 2) {
07631 if (!num.quot) {
07632 res = ast_play_and_wait(chan, "digits/2-ie");
07633 } else {
07634 res = say_and_wait(chan, durationm - 2 , chan->language);
07635 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07636 }
07637 } else {
07638 res = say_and_wait(chan, durationm, chan->language);
07639 }
07640 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07641 } else {
07642 res = say_and_wait(chan, durationm, chan->language);
07643 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07644 }
07645
07646 } else {
07647 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07648 res = wait_file2(chan, vms, "vm-minutes");
07649 }
07650 }
07651 return res;
07652 }
07653
07654 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07655 {
07656 int res = 0;
07657 char filename[256], *cid;
07658 const char *origtime, *context, *category, *duration, *flag;
07659 struct ast_config *msg_cfg;
07660 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07661
07662 vms->starting = 0;
07663 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07664 adsi_message(chan, vms);
07665 if (!vms->curmsg) {
07666 res = wait_file2(chan, vms, "vm-first");
07667 } else if (vms->curmsg == vms->lastmsg) {
07668 res = wait_file2(chan, vms, "vm-last");
07669 }
07670
07671 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07672 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07673 msg_cfg = ast_config_load(filename, config_flags);
07674 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07675 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07676 return 0;
07677 }
07678 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07679
07680
07681 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07682 res = wait_file2(chan, vms, "vm-Urgent");
07683 }
07684
07685 if (!res) {
07686
07687
07688 if (!strncasecmp(chan->language, "pl", 2)) {
07689 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07690 int ten, one;
07691 char nextmsg[256];
07692 ten = (vms->curmsg + 1) / 10;
07693 one = (vms->curmsg + 1) % 10;
07694
07695 if (vms->curmsg < 20) {
07696 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07697 res = wait_file2(chan, vms, nextmsg);
07698 } else {
07699 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07700 res = wait_file2(chan, vms, nextmsg);
07701 if (one > 0) {
07702 if (!res) {
07703 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07704 res = wait_file2(chan, vms, nextmsg);
07705 }
07706 }
07707 }
07708 }
07709 if (!res)
07710 res = wait_file2(chan, vms, "vm-message");
07711
07712 } else if (!strncasecmp(chan->language, "he", 2)) {
07713 if (!vms->curmsg) {
07714 res = wait_file2(chan, vms, "vm-message");
07715 res = wait_file2(chan, vms, "vm-first");
07716 } else if (vms->curmsg == vms->lastmsg) {
07717 res = wait_file2(chan, vms, "vm-message");
07718 res = wait_file2(chan, vms, "vm-last");
07719 } else {
07720 res = wait_file2(chan, vms, "vm-message");
07721 res = wait_file2(chan, vms, "vm-number");
07722 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07723 }
07724
07725 } else if (!strncasecmp(chan->language, "vi", 2)) {
07726 if (!vms->curmsg) {
07727 res = wait_file2(chan, vms, "vm-message");
07728 res = wait_file2(chan, vms, "vm-first");
07729 } else if (vms->curmsg == vms->lastmsg) {
07730 res = wait_file2(chan, vms, "vm-message");
07731 res = wait_file2(chan, vms, "vm-last");
07732 } else {
07733 res = wait_file2(chan, vms, "vm-message");
07734 res = wait_file2(chan, vms, "vm-number");
07735 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07736 }
07737 } else {
07738 if (!strncasecmp(chan->language, "se", 2)) {
07739 res = wait_file2(chan, vms, "vm-meddelandet");
07740 } else {
07741 res = wait_file2(chan, vms, "vm-message");
07742 }
07743 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07744 if (!res) {
07745 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07746 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07747 }
07748 }
07749 }
07750 }
07751
07752 if (!msg_cfg) {
07753 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07754 return 0;
07755 }
07756
07757 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07758 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07759 DISPOSE(vms->curdir, vms->curmsg);
07760 ast_config_destroy(msg_cfg);
07761 return 0;
07762 }
07763
07764 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07765 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07766 category = ast_variable_retrieve(msg_cfg, "message", "category");
07767
07768 context = ast_variable_retrieve(msg_cfg, "message", "context");
07769 if (!strncasecmp("macro", context, 5))
07770 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07771 if (!res) {
07772 res = play_message_category(chan, category);
07773 }
07774 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07775 res = play_message_datetime(chan, vmu, origtime, filename);
07776 }
07777 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07778 res = play_message_callerid(chan, vms, cid, context, 0);
07779 }
07780 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07781 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07782 }
07783
07784 if (res == '1') {
07785 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07786 res = 0;
07787 }
07788 ast_config_destroy(msg_cfg);
07789
07790 if (!res) {
07791 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07792 vms->heard[vms->curmsg] = 1;
07793 #ifdef IMAP_STORAGE
07794
07795
07796
07797 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07798 wait_file(chan, vms, vms->introfn);
07799 }
07800 #endif
07801 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07802 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07803 res = 0;
07804 }
07805 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07806 }
07807 DISPOSE(vms->curdir, vms->curmsg);
07808 return res;
07809 }
07810
07811 #ifdef IMAP_STORAGE
07812 static int imap_remove_file(char *dir, int msgnum)
07813 {
07814 char fn[PATH_MAX];
07815 char full_fn[PATH_MAX];
07816 char intro[PATH_MAX] = {0,};
07817
07818 if (msgnum > -1) {
07819 make_file(fn, sizeof(fn), dir, msgnum);
07820 snprintf(intro, sizeof(intro), "%sintro", fn);
07821 } else
07822 ast_copy_string(fn, dir, sizeof(fn));
07823
07824 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07825 ast_filedelete(fn, NULL);
07826 if (!ast_strlen_zero(intro)) {
07827 ast_filedelete(intro, NULL);
07828 }
07829 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07830 unlink(full_fn);
07831 }
07832 return 0;
07833 }
07834
07835
07836
07837 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07838 {
07839 char *file, *filename;
07840 char *attachment;
07841 char arg[10];
07842 int i;
07843 BODY* body;
07844
07845 file = strrchr(ast_strdupa(dir), '/');
07846 if (file) {
07847 *file++ = '\0';
07848 } else {
07849 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07850 return -1;
07851 }
07852
07853 ast_mutex_lock(&vms->lock);
07854 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07855 mail_fetchstructure(vms->mailstream, i + 1, &body);
07856
07857 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07858 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07859 } else {
07860 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07861 ast_mutex_unlock(&vms->lock);
07862 return -1;
07863 }
07864 filename = strsep(&attachment, ".");
07865 if (!strcmp(filename, file)) {
07866 sprintf(arg, "%d", i + 1);
07867 mail_setflag(vms->mailstream, arg, "\\DELETED");
07868 }
07869 }
07870 mail_expunge(vms->mailstream);
07871 ast_mutex_unlock(&vms->lock);
07872 return 0;
07873 }
07874
07875 #elif !defined(IMAP_STORAGE)
07876 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07877 {
07878 int count_msg, last_msg;
07879
07880 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07881
07882
07883
07884
07885 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07886
07887
07888 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07889
07890
07891 count_msg = count_messages(vmu, vms->curdir);
07892 if (count_msg < 0) {
07893 return count_msg;
07894 } else {
07895 vms->lastmsg = count_msg - 1;
07896 }
07897
07898 if (vm_allocate_dh(vms, vmu, count_msg)) {
07899 return -1;
07900 }
07901
07902
07903
07904
07905
07906
07907
07908
07909 if (vm_lock_path(vms->curdir)) {
07910 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07911 return ERROR_LOCK_PATH;
07912 }
07913
07914
07915 last_msg = last_message_index(vmu, vms->curdir);
07916 ast_unlock_path(vms->curdir);
07917
07918 if (last_msg < -1) {
07919 return last_msg;
07920 } else if (vms->lastmsg != last_msg) {
07921 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);
07922 resequence_mailbox(vmu, vms->curdir, count_msg);
07923 }
07924
07925 return 0;
07926 }
07927 #endif
07928
07929 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07930 {
07931 int x = 0;
07932
07933 #ifndef IMAP_STORAGE
07934 int last_msg_idx;
07935 int res = 0, nummsg;
07936 char fn2[PATH_MAX];
07937 #endif
07938
07939 if (vms->lastmsg <= -1) {
07940 goto done;
07941 }
07942
07943 vms->curmsg = -1;
07944 #ifndef IMAP_STORAGE
07945
07946 if (vm_lock_path(vms->curdir)) {
07947 return ERROR_LOCK_PATH;
07948 }
07949
07950
07951 last_msg_idx = last_message_index(vmu, vms->curdir);
07952 if (last_msg_idx != vms->lastmsg) {
07953 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07954 }
07955
07956
07957 for (x = 0; x < last_msg_idx + 1; x++) {
07958 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07959
07960 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07961 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07962 break;
07963 }
07964 vms->curmsg++;
07965 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07966 if (strcmp(vms->fn, fn2)) {
07967 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07968 }
07969 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07970
07971 res = save_to_folder(vmu, vms, x, 1);
07972 if (res == ERROR_LOCK_PATH) {
07973
07974 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07975 vms->deleted[x] = 0;
07976 vms->heard[x] = 0;
07977 --x;
07978 }
07979 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07980
07981 res = save_to_folder(vmu, vms, x, 10);
07982 if (res == ERROR_LOCK_PATH) {
07983
07984 vms->deleted[x] = 0;
07985 vms->heard[x] = 0;
07986 --x;
07987 }
07988 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07989
07990
07991 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07992 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07993 DELETE(vms->curdir, x, vms->fn, vmu);
07994 }
07995 }
07996 }
07997
07998
07999 nummsg = x - 1;
08000 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08001 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08002 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08003 DELETE(vms->curdir, x, vms->fn, vmu);
08004 }
08005 }
08006 ast_unlock_path(vms->curdir);
08007 #else
08008 if (vms->deleted) {
08009
08010
08011 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
08012 if (vms->deleted[x]) {
08013 ast_debug(3, "IMAP delete of %d\n", x);
08014 DELETE(vms->curdir, x, vms->fn, vmu);
08015 }
08016 }
08017 }
08018 #endif
08019
08020 done:
08021 if (vms->deleted && vmu->maxmsg) {
08022 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
08023 }
08024 if (vms->heard && vmu->maxmsg) {
08025 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
08026 }
08027
08028 return 0;
08029 }
08030
08031
08032
08033
08034
08035
08036
08037 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08038 {
08039 int cmd;
08040 char *buf;
08041
08042 buf = alloca(strlen(box) + 2);
08043 strcpy(buf, box);
08044 strcat(buf, "s");
08045
08046 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08047 cmd = ast_play_and_wait(chan, buf);
08048 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08049 } else {
08050 cmd = ast_play_and_wait(chan, "vm-messages");
08051 return cmd ? cmd : ast_play_and_wait(chan, box);
08052 }
08053 }
08054
08055 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08056 {
08057 int cmd;
08058
08059 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08060 if (!strcasecmp(box, "vm-INBOX"))
08061 cmd = ast_play_and_wait(chan, "vm-new-e");
08062 else
08063 cmd = ast_play_and_wait(chan, "vm-old-e");
08064 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08065 } else {
08066 cmd = ast_play_and_wait(chan, "vm-messages");
08067 return cmd ? cmd : ast_play_and_wait(chan, box);
08068 }
08069 }
08070
08071 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08072 {
08073 int cmd;
08074
08075 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08076 cmd = ast_play_and_wait(chan, "vm-messages");
08077 return cmd ? cmd : ast_play_and_wait(chan, box);
08078 } else {
08079 cmd = ast_play_and_wait(chan, box);
08080 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08081 }
08082 }
08083
08084 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08085 {
08086 int cmd;
08087
08088 if ( !strncasecmp(chan->language, "it", 2) ||
08089 !strncasecmp(chan->language, "es", 2) ||
08090 !strncasecmp(chan->language, "pt", 2)) {
08091 cmd = ast_play_and_wait(chan, "vm-messages");
08092 return cmd ? cmd : ast_play_and_wait(chan, box);
08093 } else if (!strncasecmp(chan->language, "gr", 2)) {
08094 return vm_play_folder_name_gr(chan, box);
08095 } else if (!strncasecmp(chan->language, "he", 2)) {
08096 return ast_play_and_wait(chan, box);
08097 } else if (!strncasecmp(chan->language, "pl", 2)) {
08098 return vm_play_folder_name_pl(chan, box);
08099 } else if (!strncasecmp(chan->language, "ua", 2)) {
08100 return vm_play_folder_name_ua(chan, box);
08101 } else if (!strncasecmp(chan->language, "vi", 2)) {
08102 return ast_play_and_wait(chan, box);
08103 } else {
08104 cmd = ast_play_and_wait(chan, box);
08105 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08106 }
08107 }
08108
08109
08110
08111
08112
08113
08114
08115
08116
08117
08118
08119
08120
08121 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08122 {
08123 int res = 0;
08124
08125 if (vms->newmessages) {
08126 res = ast_play_and_wait(chan, "vm-youhave");
08127 if (!res)
08128 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08129 if (!res) {
08130 if ((vms->newmessages == 1)) {
08131 res = ast_play_and_wait(chan, "vm-INBOX");
08132 if (!res)
08133 res = ast_play_and_wait(chan, "vm-message");
08134 } else {
08135 res = ast_play_and_wait(chan, "vm-INBOXs");
08136 if (!res)
08137 res = ast_play_and_wait(chan, "vm-messages");
08138 }
08139 }
08140 } else if (vms->oldmessages){
08141 res = ast_play_and_wait(chan, "vm-youhave");
08142 if (!res)
08143 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08144 if ((vms->oldmessages == 1)){
08145 res = ast_play_and_wait(chan, "vm-Old");
08146 if (!res)
08147 res = ast_play_and_wait(chan, "vm-message");
08148 } else {
08149 res = ast_play_and_wait(chan, "vm-Olds");
08150 if (!res)
08151 res = ast_play_and_wait(chan, "vm-messages");
08152 }
08153 } else if (!vms->oldmessages && !vms->newmessages)
08154 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08155 return res;
08156 }
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 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08216 {
08217 int res;
08218 int lastnum = 0;
08219
08220 res = ast_play_and_wait(chan, "vm-youhave");
08221
08222 if (!res && vms->newmessages) {
08223 lastnum = vms->newmessages;
08224
08225 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08226 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08227 }
08228
08229 if (!res && vms->oldmessages) {
08230 res = ast_play_and_wait(chan, "vm-and");
08231 }
08232 }
08233
08234 if (!res && vms->oldmessages) {
08235 lastnum = vms->oldmessages;
08236
08237 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08238 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08239 }
08240 }
08241
08242 if (!res) {
08243 if (lastnum == 0) {
08244 res = ast_play_and_wait(chan, "vm-no");
08245 }
08246 if (!res) {
08247 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08248 }
08249 }
08250
08251 return res;
08252 }
08253
08254
08255 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08256 {
08257 int res = 0;
08258
08259
08260 if (!res) {
08261 if ((vms->newmessages) || (vms->oldmessages)) {
08262 res = ast_play_and_wait(chan, "vm-youhave");
08263 }
08264
08265
08266
08267
08268
08269 if (vms->newmessages) {
08270 if (!res) {
08271 if (vms->newmessages == 1) {
08272 res = ast_play_and_wait(chan, "vm-INBOX1");
08273 } else {
08274 if (vms->newmessages == 2) {
08275 res = ast_play_and_wait(chan, "vm-shtei");
08276 } else {
08277 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08278 }
08279 res = ast_play_and_wait(chan, "vm-INBOX");
08280 }
08281 }
08282 if (vms->oldmessages && !res) {
08283 res = ast_play_and_wait(chan, "vm-and");
08284 if (vms->oldmessages == 1) {
08285 res = ast_play_and_wait(chan, "vm-Old1");
08286 } else {
08287 if (vms->oldmessages == 2) {
08288 res = ast_play_and_wait(chan, "vm-shtei");
08289 } else {
08290 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08291 }
08292 res = ast_play_and_wait(chan, "vm-Old");
08293 }
08294 }
08295 }
08296 if (!res && vms->oldmessages && !vms->newmessages) {
08297 if (!res) {
08298 if (vms->oldmessages == 1) {
08299 res = ast_play_and_wait(chan, "vm-Old1");
08300 } else {
08301 if (vms->oldmessages == 2) {
08302 res = ast_play_and_wait(chan, "vm-shtei");
08303 } else {
08304 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08305 }
08306 res = ast_play_and_wait(chan, "vm-Old");
08307 }
08308 }
08309 }
08310 if (!res) {
08311 if (!vms->oldmessages && !vms->newmessages) {
08312 if (!res) {
08313 res = ast_play_and_wait(chan, "vm-nomessages");
08314 }
08315 }
08316 }
08317 }
08318 return res;
08319 }
08320
08321
08322 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08323 {
08324 int res;
08325
08326
08327 res = ast_play_and_wait(chan, "vm-youhave");
08328 if (!res) {
08329 if (vms->urgentmessages) {
08330 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08331 if (!res)
08332 res = ast_play_and_wait(chan, "vm-Urgent");
08333 if ((vms->oldmessages || vms->newmessages) && !res) {
08334 res = ast_play_and_wait(chan, "vm-and");
08335 } else if (!res) {
08336 if ((vms->urgentmessages == 1))
08337 res = ast_play_and_wait(chan, "vm-message");
08338 else
08339 res = ast_play_and_wait(chan, "vm-messages");
08340 }
08341 }
08342 if (vms->newmessages) {
08343 res = say_and_wait(chan, vms->newmessages, chan->language);
08344 if (!res)
08345 res = ast_play_and_wait(chan, "vm-INBOX");
08346 if (vms->oldmessages && !res)
08347 res = ast_play_and_wait(chan, "vm-and");
08348 else if (!res) {
08349 if ((vms->newmessages == 1))
08350 res = ast_play_and_wait(chan, "vm-message");
08351 else
08352 res = ast_play_and_wait(chan, "vm-messages");
08353 }
08354
08355 }
08356 if (!res && vms->oldmessages) {
08357 res = say_and_wait(chan, vms->oldmessages, chan->language);
08358 if (!res)
08359 res = ast_play_and_wait(chan, "vm-Old");
08360 if (!res) {
08361 if (vms->oldmessages == 1)
08362 res = ast_play_and_wait(chan, "vm-message");
08363 else
08364 res = ast_play_and_wait(chan, "vm-messages");
08365 }
08366 }
08367 if (!res) {
08368 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08369 res = ast_play_and_wait(chan, "vm-no");
08370 if (!res)
08371 res = ast_play_and_wait(chan, "vm-messages");
08372 }
08373 }
08374 }
08375 return res;
08376 }
08377
08378
08379 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08380 {
08381
08382 int res;
08383 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08384 res = ast_play_and_wait(chan, "vm-no") ||
08385 ast_play_and_wait(chan, "vm-message");
08386 else
08387 res = ast_play_and_wait(chan, "vm-youhave");
08388 if (!res && vms->newmessages) {
08389 res = (vms->newmessages == 1) ?
08390 ast_play_and_wait(chan, "digits/un") ||
08391 ast_play_and_wait(chan, "vm-nuovo") ||
08392 ast_play_and_wait(chan, "vm-message") :
08393
08394 say_and_wait(chan, vms->newmessages, chan->language) ||
08395 ast_play_and_wait(chan, "vm-nuovi") ||
08396 ast_play_and_wait(chan, "vm-messages");
08397 if (!res && vms->oldmessages)
08398 res = ast_play_and_wait(chan, "vm-and");
08399 }
08400 if (!res && vms->oldmessages) {
08401 res = (vms->oldmessages == 1) ?
08402 ast_play_and_wait(chan, "digits/un") ||
08403 ast_play_and_wait(chan, "vm-vecchio") ||
08404 ast_play_and_wait(chan, "vm-message") :
08405
08406 say_and_wait(chan, vms->oldmessages, chan->language) ||
08407 ast_play_and_wait(chan, "vm-vecchi") ||
08408 ast_play_and_wait(chan, "vm-messages");
08409 }
08410 return res;
08411 }
08412
08413
08414 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08415 {
08416
08417 int res;
08418 div_t num;
08419
08420 if (!vms->oldmessages && !vms->newmessages) {
08421 res = ast_play_and_wait(chan, "vm-no");
08422 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08423 return res;
08424 } else {
08425 res = ast_play_and_wait(chan, "vm-youhave");
08426 }
08427
08428 if (vms->newmessages) {
08429 num = div(vms->newmessages, 10);
08430 if (vms->newmessages == 1) {
08431 res = ast_play_and_wait(chan, "digits/1-a");
08432 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08433 res = res ? res : ast_play_and_wait(chan, "vm-message");
08434 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08435 if (num.rem == 2) {
08436 if (!num.quot) {
08437 res = ast_play_and_wait(chan, "digits/2-ie");
08438 } else {
08439 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08440 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08441 }
08442 } else {
08443 res = say_and_wait(chan, vms->newmessages, chan->language);
08444 }
08445 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08446 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08447 } else {
08448 res = say_and_wait(chan, vms->newmessages, chan->language);
08449 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08450 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08451 }
08452 if (!res && vms->oldmessages)
08453 res = ast_play_and_wait(chan, "vm-and");
08454 }
08455 if (!res && vms->oldmessages) {
08456 num = div(vms->oldmessages, 10);
08457 if (vms->oldmessages == 1) {
08458 res = ast_play_and_wait(chan, "digits/1-a");
08459 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08460 res = res ? res : ast_play_and_wait(chan, "vm-message");
08461 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08462 if (num.rem == 2) {
08463 if (!num.quot) {
08464 res = ast_play_and_wait(chan, "digits/2-ie");
08465 } else {
08466 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08467 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08468 }
08469 } else {
08470 res = say_and_wait(chan, vms->oldmessages, chan->language);
08471 }
08472 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08473 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08474 } else {
08475 res = say_and_wait(chan, vms->oldmessages, chan->language);
08476 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08477 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08478 }
08479 }
08480
08481 return res;
08482 }
08483
08484
08485 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08486 {
08487
08488 int res;
08489
08490 res = ast_play_and_wait(chan, "vm-youhave");
08491 if (res)
08492 return res;
08493
08494 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08495 res = ast_play_and_wait(chan, "vm-no");
08496 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08497 return res;
08498 }
08499
08500 if (vms->newmessages) {
08501 if ((vms->newmessages == 1)) {
08502 res = ast_play_and_wait(chan, "digits/ett");
08503 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08504 res = res ? res : ast_play_and_wait(chan, "vm-message");
08505 } else {
08506 res = say_and_wait(chan, vms->newmessages, chan->language);
08507 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08508 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08509 }
08510 if (!res && vms->oldmessages)
08511 res = ast_play_and_wait(chan, "vm-and");
08512 }
08513 if (!res && vms->oldmessages) {
08514 if (vms->oldmessages == 1) {
08515 res = ast_play_and_wait(chan, "digits/ett");
08516 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08517 res = res ? res : ast_play_and_wait(chan, "vm-message");
08518 } else {
08519 res = say_and_wait(chan, vms->oldmessages, chan->language);
08520 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08521 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08522 }
08523 }
08524
08525 return res;
08526 }
08527
08528
08529 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08530 {
08531
08532 int res;
08533
08534 res = ast_play_and_wait(chan, "vm-youhave");
08535 if (res)
08536 return res;
08537
08538 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08539 res = ast_play_and_wait(chan, "vm-no");
08540 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08541 return res;
08542 }
08543
08544 if (vms->newmessages) {
08545 if ((vms->newmessages == 1)) {
08546 res = ast_play_and_wait(chan, "digits/1");
08547 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08548 res = res ? res : ast_play_and_wait(chan, "vm-message");
08549 } else {
08550 res = say_and_wait(chan, vms->newmessages, chan->language);
08551 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08552 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08553 }
08554 if (!res && vms->oldmessages)
08555 res = ast_play_and_wait(chan, "vm-and");
08556 }
08557 if (!res && vms->oldmessages) {
08558 if (vms->oldmessages == 1) {
08559 res = ast_play_and_wait(chan, "digits/1");
08560 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08561 res = res ? res : ast_play_and_wait(chan, "vm-message");
08562 } else {
08563 res = say_and_wait(chan, vms->oldmessages, chan->language);
08564 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08565 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08566 }
08567 }
08568
08569 return res;
08570 }
08571
08572
08573 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08574 {
08575
08576 int res;
08577 res = ast_play_and_wait(chan, "vm-youhave");
08578 if (!res) {
08579 if (vms->newmessages) {
08580 if ((vms->newmessages == 1))
08581 res = ast_play_and_wait(chan, "digits/1F");
08582 else
08583 res = say_and_wait(chan, vms->newmessages, chan->language);
08584 if (!res)
08585 res = ast_play_and_wait(chan, "vm-INBOX");
08586 if (vms->oldmessages && !res)
08587 res = ast_play_and_wait(chan, "vm-and");
08588 else if (!res) {
08589 if ((vms->newmessages == 1))
08590 res = ast_play_and_wait(chan, "vm-message");
08591 else
08592 res = ast_play_and_wait(chan, "vm-messages");
08593 }
08594
08595 }
08596 if (!res && vms->oldmessages) {
08597 if (vms->oldmessages == 1)
08598 res = ast_play_and_wait(chan, "digits/1F");
08599 else
08600 res = say_and_wait(chan, vms->oldmessages, chan->language);
08601 if (!res)
08602 res = ast_play_and_wait(chan, "vm-Old");
08603 if (!res) {
08604 if (vms->oldmessages == 1)
08605 res = ast_play_and_wait(chan, "vm-message");
08606 else
08607 res = ast_play_and_wait(chan, "vm-messages");
08608 }
08609 }
08610 if (!res) {
08611 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08612 res = ast_play_and_wait(chan, "vm-no");
08613 if (!res)
08614 res = ast_play_and_wait(chan, "vm-messages");
08615 }
08616 }
08617 }
08618 return res;
08619 }
08620
08621
08622 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08623 {
08624
08625 int res;
08626 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08627 res = ast_play_and_wait(chan, "vm-youhaveno");
08628 if (!res)
08629 res = ast_play_and_wait(chan, "vm-messages");
08630 } else {
08631 res = ast_play_and_wait(chan, "vm-youhave");
08632 }
08633 if (!res) {
08634 if (vms->newmessages) {
08635 if (!res) {
08636 if ((vms->newmessages == 1)) {
08637 res = ast_play_and_wait(chan, "digits/1M");
08638 if (!res)
08639 res = ast_play_and_wait(chan, "vm-message");
08640 if (!res)
08641 res = ast_play_and_wait(chan, "vm-INBOXs");
08642 } else {
08643 res = say_and_wait(chan, vms->newmessages, chan->language);
08644 if (!res)
08645 res = ast_play_and_wait(chan, "vm-messages");
08646 if (!res)
08647 res = ast_play_and_wait(chan, "vm-INBOX");
08648 }
08649 }
08650 if (vms->oldmessages && !res)
08651 res = ast_play_and_wait(chan, "vm-and");
08652 }
08653 if (vms->oldmessages) {
08654 if (!res) {
08655 if (vms->oldmessages == 1) {
08656 res = ast_play_and_wait(chan, "digits/1M");
08657 if (!res)
08658 res = ast_play_and_wait(chan, "vm-message");
08659 if (!res)
08660 res = ast_play_and_wait(chan, "vm-Olds");
08661 } else {
08662 res = say_and_wait(chan, vms->oldmessages, chan->language);
08663 if (!res)
08664 res = ast_play_and_wait(chan, "vm-messages");
08665 if (!res)
08666 res = ast_play_and_wait(chan, "vm-Old");
08667 }
08668 }
08669 }
08670 }
08671 return res;
08672 }
08673
08674
08675 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08676
08677 int res;
08678 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08679 res = ast_play_and_wait(chan, "vm-nomessages");
08680 return res;
08681 } else {
08682 res = ast_play_and_wait(chan, "vm-youhave");
08683 }
08684 if (vms->newmessages) {
08685 if (!res)
08686 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08687 if ((vms->newmessages == 1)) {
08688 if (!res)
08689 res = ast_play_and_wait(chan, "vm-message");
08690 if (!res)
08691 res = ast_play_and_wait(chan, "vm-INBOXs");
08692 } else {
08693 if (!res)
08694 res = ast_play_and_wait(chan, "vm-messages");
08695 if (!res)
08696 res = ast_play_and_wait(chan, "vm-INBOX");
08697 }
08698 if (vms->oldmessages && !res)
08699 res = ast_play_and_wait(chan, "vm-and");
08700 }
08701 if (vms->oldmessages) {
08702 if (!res)
08703 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08704 if (vms->oldmessages == 1) {
08705 if (!res)
08706 res = ast_play_and_wait(chan, "vm-message");
08707 if (!res)
08708 res = ast_play_and_wait(chan, "vm-Olds");
08709 } else {
08710 if (!res)
08711 res = ast_play_and_wait(chan, "vm-messages");
08712 if (!res)
08713 res = ast_play_and_wait(chan, "vm-Old");
08714 }
08715 }
08716 return res;
08717 }
08718
08719
08720 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08721 {
08722
08723 int res;
08724 res = ast_play_and_wait(chan, "vm-youhave");
08725 if (!res) {
08726 if (vms->newmessages) {
08727 res = say_and_wait(chan, vms->newmessages, chan->language);
08728 if (!res)
08729 res = ast_play_and_wait(chan, "vm-INBOX");
08730 if (vms->oldmessages && !res)
08731 res = ast_play_and_wait(chan, "vm-and");
08732 else if (!res) {
08733 if ((vms->newmessages == 1))
08734 res = ast_play_and_wait(chan, "vm-message");
08735 else
08736 res = ast_play_and_wait(chan, "vm-messages");
08737 }
08738
08739 }
08740 if (!res && vms->oldmessages) {
08741 res = say_and_wait(chan, vms->oldmessages, chan->language);
08742 if (!res)
08743 res = ast_play_and_wait(chan, "vm-Old");
08744 if (!res) {
08745 if (vms->oldmessages == 1)
08746 res = ast_play_and_wait(chan, "vm-message");
08747 else
08748 res = ast_play_and_wait(chan, "vm-messages");
08749 }
08750 }
08751 if (!res) {
08752 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08753 res = ast_play_and_wait(chan, "vm-no");
08754 if (!res)
08755 res = ast_play_and_wait(chan, "vm-messages");
08756 }
08757 }
08758 }
08759 return res;
08760 }
08761
08762
08763 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08764 {
08765
08766 int res;
08767 res = ast_play_and_wait(chan, "vm-youhave");
08768 if (!res) {
08769 if (vms->newmessages) {
08770 res = say_and_wait(chan, vms->newmessages, chan->language);
08771 if (!res) {
08772 if (vms->newmessages == 1)
08773 res = ast_play_and_wait(chan, "vm-INBOXs");
08774 else
08775 res = ast_play_and_wait(chan, "vm-INBOX");
08776 }
08777 if (vms->oldmessages && !res)
08778 res = ast_play_and_wait(chan, "vm-and");
08779 else if (!res) {
08780 if ((vms->newmessages == 1))
08781 res = ast_play_and_wait(chan, "vm-message");
08782 else
08783 res = ast_play_and_wait(chan, "vm-messages");
08784 }
08785
08786 }
08787 if (!res && vms->oldmessages) {
08788 res = say_and_wait(chan, vms->oldmessages, chan->language);
08789 if (!res) {
08790 if (vms->oldmessages == 1)
08791 res = ast_play_and_wait(chan, "vm-Olds");
08792 else
08793 res = ast_play_and_wait(chan, "vm-Old");
08794 }
08795 if (!res) {
08796 if (vms->oldmessages == 1)
08797 res = ast_play_and_wait(chan, "vm-message");
08798 else
08799 res = ast_play_and_wait(chan, "vm-messages");
08800 }
08801 }
08802 if (!res) {
08803 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08804 res = ast_play_and_wait(chan, "vm-no");
08805 if (!res)
08806 res = ast_play_and_wait(chan, "vm-messages");
08807 }
08808 }
08809 }
08810 return res;
08811 }
08812
08813
08814 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08815 {
08816
08817 int res;
08818 res = ast_play_and_wait(chan, "vm-youhave");
08819 if (!res) {
08820 if (vms->newmessages) {
08821 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08822 if (!res) {
08823 if ((vms->newmessages == 1)) {
08824 res = ast_play_and_wait(chan, "vm-message");
08825 if (!res)
08826 res = ast_play_and_wait(chan, "vm-INBOXs");
08827 } else {
08828 res = ast_play_and_wait(chan, "vm-messages");
08829 if (!res)
08830 res = ast_play_and_wait(chan, "vm-INBOX");
08831 }
08832 }
08833 if (vms->oldmessages && !res)
08834 res = ast_play_and_wait(chan, "vm-and");
08835 }
08836 if (!res && vms->oldmessages) {
08837 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08838 if (!res) {
08839 if (vms->oldmessages == 1) {
08840 res = ast_play_and_wait(chan, "vm-message");
08841 if (!res)
08842 res = ast_play_and_wait(chan, "vm-Olds");
08843 } else {
08844 res = ast_play_and_wait(chan, "vm-messages");
08845 if (!res)
08846 res = ast_play_and_wait(chan, "vm-Old");
08847 }
08848 }
08849 }
08850 if (!res) {
08851 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08852 res = ast_play_and_wait(chan, "vm-no");
08853 if (!res)
08854 res = ast_play_and_wait(chan, "vm-messages");
08855 }
08856 }
08857 }
08858 return res;
08859 }
08860
08861
08862
08863
08864
08865
08866
08867
08868
08869
08870
08871
08872
08873
08874
08875
08876
08877 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08878 {
08879 int res;
08880 res = ast_play_and_wait(chan, "vm-youhave");
08881 if (!res) {
08882 if (vms->newmessages) {
08883 if (vms->newmessages == 1) {
08884 res = ast_play_and_wait(chan, "digits/jednu");
08885 } else {
08886 res = say_and_wait(chan, vms->newmessages, chan->language);
08887 }
08888 if (!res) {
08889 if ((vms->newmessages == 1))
08890 res = ast_play_and_wait(chan, "vm-novou");
08891 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08892 res = ast_play_and_wait(chan, "vm-nove");
08893 if (vms->newmessages > 4)
08894 res = ast_play_and_wait(chan, "vm-novych");
08895 }
08896 if (vms->oldmessages && !res)
08897 res = ast_play_and_wait(chan, "vm-and");
08898 else if (!res) {
08899 if ((vms->newmessages == 1))
08900 res = ast_play_and_wait(chan, "vm-zpravu");
08901 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08902 res = ast_play_and_wait(chan, "vm-zpravy");
08903 if (vms->newmessages > 4)
08904 res = ast_play_and_wait(chan, "vm-zprav");
08905 }
08906 }
08907 if (!res && vms->oldmessages) {
08908 res = say_and_wait(chan, vms->oldmessages, chan->language);
08909 if (!res) {
08910 if ((vms->oldmessages == 1))
08911 res = ast_play_and_wait(chan, "vm-starou");
08912 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08913 res = ast_play_and_wait(chan, "vm-stare");
08914 if (vms->oldmessages > 4)
08915 res = ast_play_and_wait(chan, "vm-starych");
08916 }
08917 if (!res) {
08918 if ((vms->oldmessages == 1))
08919 res = ast_play_and_wait(chan, "vm-zpravu");
08920 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08921 res = ast_play_and_wait(chan, "vm-zpravy");
08922 if (vms->oldmessages > 4)
08923 res = ast_play_and_wait(chan, "vm-zprav");
08924 }
08925 }
08926 if (!res) {
08927 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08928 res = ast_play_and_wait(chan, "vm-no");
08929 if (!res)
08930 res = ast_play_and_wait(chan, "vm-zpravy");
08931 }
08932 }
08933 }
08934 return res;
08935 }
08936
08937
08938 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08939 {
08940 int res;
08941
08942 res = ast_play_and_wait(chan, "vm-you");
08943
08944 if (!res && vms->newmessages) {
08945 res = ast_play_and_wait(chan, "vm-have");
08946 if (!res)
08947 res = say_and_wait(chan, vms->newmessages, chan->language);
08948 if (!res)
08949 res = ast_play_and_wait(chan, "vm-tong");
08950 if (!res)
08951 res = ast_play_and_wait(chan, "vm-INBOX");
08952 if (vms->oldmessages && !res)
08953 res = ast_play_and_wait(chan, "vm-and");
08954 else if (!res)
08955 res = ast_play_and_wait(chan, "vm-messages");
08956 }
08957 if (!res && vms->oldmessages) {
08958 res = ast_play_and_wait(chan, "vm-have");
08959 if (!res)
08960 res = say_and_wait(chan, vms->oldmessages, chan->language);
08961 if (!res)
08962 res = ast_play_and_wait(chan, "vm-tong");
08963 if (!res)
08964 res = ast_play_and_wait(chan, "vm-Old");
08965 if (!res)
08966 res = ast_play_and_wait(chan, "vm-messages");
08967 }
08968 if (!res && !vms->oldmessages && !vms->newmessages) {
08969 res = ast_play_and_wait(chan, "vm-haveno");
08970 if (!res)
08971 res = ast_play_and_wait(chan, "vm-messages");
08972 }
08973 return res;
08974 }
08975
08976
08977 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08978 {
08979 int res;
08980
08981
08982 res = ast_play_and_wait(chan, "vm-youhave");
08983 if (!res) {
08984 if (vms->newmessages) {
08985 res = say_and_wait(chan, vms->newmessages, chan->language);
08986 if (!res)
08987 res = ast_play_and_wait(chan, "vm-INBOX");
08988 if (vms->oldmessages && !res)
08989 res = ast_play_and_wait(chan, "vm-and");
08990 }
08991 if (!res && vms->oldmessages) {
08992 res = say_and_wait(chan, vms->oldmessages, chan->language);
08993 if (!res)
08994 res = ast_play_and_wait(chan, "vm-Old");
08995 }
08996 if (!res) {
08997 if (!vms->oldmessages && !vms->newmessages) {
08998 res = ast_play_and_wait(chan, "vm-no");
08999 if (!res)
09000 res = ast_play_and_wait(chan, "vm-message");
09001 }
09002 }
09003 }
09004 return res;
09005 }
09006
09007 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09008 {
09009 char prefile[256];
09010
09011
09012 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09013 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09014 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09015 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09016 ast_play_and_wait(chan, "vm-tempgreetactive");
09017 }
09018 DISPOSE(prefile, -1);
09019 }
09020
09021
09022 if (0) {
09023 return 0;
09024 } else if (!strncasecmp(chan->language, "cs", 2)) {
09025 return vm_intro_cs(chan, vms);
09026 } else if (!strncasecmp(chan->language, "cz", 2)) {
09027 static int deprecation_warning = 0;
09028 if (deprecation_warning++ % 10 == 0) {
09029 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09030 }
09031 return vm_intro_cs(chan, vms);
09032 } else if (!strncasecmp(chan->language, "de", 2)) {
09033 return vm_intro_de(chan, vms);
09034 } else if (!strncasecmp(chan->language, "es", 2)) {
09035 return vm_intro_es(chan, vms);
09036 } else if (!strncasecmp(chan->language, "fr", 2)) {
09037 return vm_intro_fr(chan, vms);
09038 } else if (!strncasecmp(chan->language, "gr", 2)) {
09039 return vm_intro_gr(chan, vms);
09040 } else if (!strncasecmp(chan->language, "he", 2)) {
09041 return vm_intro_he(chan, vms);
09042 } else if (!strncasecmp(chan->language, "it", 2)) {
09043 return vm_intro_it(chan, vms);
09044 } else if (!strncasecmp(chan->language, "nl", 2)) {
09045 return vm_intro_nl(chan, vms);
09046 } else if (!strncasecmp(chan->language, "no", 2)) {
09047 return vm_intro_no(chan, vms);
09048 } else if (!strncasecmp(chan->language, "pl", 2)) {
09049 return vm_intro_pl(chan, vms);
09050 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09051 return vm_intro_pt_BR(chan, vms);
09052 } else if (!strncasecmp(chan->language, "pt", 2)) {
09053 return vm_intro_pt(chan, vms);
09054 } else if (!strncasecmp(chan->language, "ru", 2)) {
09055 return vm_intro_multilang(chan, vms, "n");
09056 } else if (!strncasecmp(chan->language, "se", 2)) {
09057 return vm_intro_se(chan, vms);
09058 } else if (!strncasecmp(chan->language, "ua", 2)) {
09059 return vm_intro_multilang(chan, vms, "n");
09060 } else if (!strncasecmp(chan->language, "vi", 2)) {
09061 return vm_intro_vi(chan, vms);
09062 } else if (!strncasecmp(chan->language, "zh", 2)) {
09063 return vm_intro_zh(chan, vms);
09064 } else {
09065 return vm_intro_en(chan, vms);
09066 }
09067 }
09068
09069 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09070 {
09071 int res = 0;
09072
09073 while (!res) {
09074 if (vms->starting) {
09075 if (vms->lastmsg > -1) {
09076 if (skipadvanced)
09077 res = ast_play_and_wait(chan, "vm-onefor-full");
09078 else
09079 res = ast_play_and_wait(chan, "vm-onefor");
09080 if (!res)
09081 res = vm_play_folder_name(chan, vms->vmbox);
09082 }
09083 if (!res) {
09084 if (skipadvanced)
09085 res = ast_play_and_wait(chan, "vm-opts-full");
09086 else
09087 res = ast_play_and_wait(chan, "vm-opts");
09088 }
09089 } else {
09090
09091 if (skipadvanced) {
09092 res = ast_play_and_wait(chan, "vm-onefor-full");
09093 if (!res)
09094 res = vm_play_folder_name(chan, vms->vmbox);
09095 res = ast_play_and_wait(chan, "vm-opts-full");
09096 }
09097
09098
09099
09100
09101
09102
09103 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09104 res = ast_play_and_wait(chan, "vm-prev");
09105 }
09106 if (!res && !skipadvanced)
09107 res = ast_play_and_wait(chan, "vm-advopts");
09108 if (!res)
09109 res = ast_play_and_wait(chan, "vm-repeat");
09110
09111
09112
09113
09114
09115
09116 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09117 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09118 res = ast_play_and_wait(chan, "vm-next");
09119 }
09120 if (!res) {
09121 if (!vms->deleted[vms->curmsg])
09122 res = ast_play_and_wait(chan, "vm-delete");
09123 else
09124 res = ast_play_and_wait(chan, "vm-undelete");
09125 if (!res)
09126 res = ast_play_and_wait(chan, "vm-toforward");
09127 if (!res)
09128 res = ast_play_and_wait(chan, "vm-savemessage");
09129 }
09130 }
09131 if (!res) {
09132 res = ast_play_and_wait(chan, "vm-helpexit");
09133 }
09134 if (!res)
09135 res = ast_waitfordigit(chan, 6000);
09136 if (!res) {
09137 vms->repeats++;
09138 if (vms->repeats > 2) {
09139 res = 't';
09140 }
09141 }
09142 }
09143 return res;
09144 }
09145
09146 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09147 {
09148 int res = 0;
09149
09150 while (!res) {
09151 if (vms->lastmsg > -1) {
09152 res = ast_play_and_wait(chan, "vm-listen");
09153 if (!res)
09154 res = vm_play_folder_name(chan, vms->vmbox);
09155 if (!res)
09156 res = ast_play_and_wait(chan, "press");
09157 if (!res)
09158 res = ast_play_and_wait(chan, "digits/1");
09159 }
09160 if (!res)
09161 res = ast_play_and_wait(chan, "vm-opts");
09162 if (!res) {
09163 vms->starting = 0;
09164 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09165 }
09166 }
09167 return res;
09168 }
09169
09170 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09171 {
09172 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09173 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09174 } else {
09175 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09176 }
09177 }
09178
09179
09180 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09181 {
09182 int cmd = 0;
09183 int duration = 0;
09184 int tries = 0;
09185 char newpassword[80] = "";
09186 char newpassword2[80] = "";
09187 char prefile[PATH_MAX] = "";
09188 unsigned char buf[256];
09189 int bytes = 0;
09190
09191 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09192 if (ast_adsi_available(chan)) {
09193 bytes += adsi_logo(buf + bytes);
09194 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09195 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09196 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09197 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09198 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09199 }
09200
09201
09202
09203 for (;;) {
09204 newpassword[1] = '\0';
09205 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09206 if (cmd == '#')
09207 newpassword[0] = '\0';
09208 if (cmd < 0 || cmd == 't' || cmd == '#')
09209 return cmd;
09210 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09211 if (cmd < 0 || cmd == 't' || cmd == '#')
09212 return cmd;
09213 cmd = check_password(vmu, newpassword);
09214 if (cmd != 0) {
09215 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09216 cmd = ast_play_and_wait(chan, vm_invalid_password);
09217 } else {
09218 newpassword2[1] = '\0';
09219 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09220 if (cmd == '#')
09221 newpassword2[0] = '\0';
09222 if (cmd < 0 || cmd == 't' || cmd == '#')
09223 return cmd;
09224 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09225 if (cmd < 0 || cmd == 't' || cmd == '#')
09226 return cmd;
09227 if (!strcmp(newpassword, newpassword2))
09228 break;
09229 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09230 cmd = ast_play_and_wait(chan, vm_mismatch);
09231 }
09232 if (++tries == 3)
09233 return -1;
09234 if (cmd != 0) {
09235 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09236 }
09237 }
09238 if (pwdchange & PWDCHANGE_INTERNAL)
09239 vm_change_password(vmu, newpassword);
09240 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09241 vm_change_password_shell(vmu, newpassword);
09242
09243 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09244 cmd = ast_play_and_wait(chan, vm_passchanged);
09245
09246
09247 if (ast_test_flag(vmu, VM_FORCENAME)) {
09248 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09249 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09250 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09251 if (cmd < 0 || cmd == 't' || cmd == '#')
09252 return cmd;
09253 }
09254 }
09255
09256
09257 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09258 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09259 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09260 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09261 if (cmd < 0 || cmd == 't' || cmd == '#')
09262 return cmd;
09263 }
09264
09265 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09266 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09267 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09268 if (cmd < 0 || cmd == 't' || cmd == '#')
09269 return cmd;
09270 }
09271 }
09272
09273 return cmd;
09274 }
09275
09276 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09277 {
09278 int cmd = 0;
09279 int retries = 0;
09280 int duration = 0;
09281 char newpassword[80] = "";
09282 char newpassword2[80] = "";
09283 char prefile[PATH_MAX] = "";
09284 unsigned char buf[256];
09285 int bytes = 0;
09286
09287 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09288 if (ast_adsi_available(chan)) {
09289 bytes += adsi_logo(buf + bytes);
09290 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09291 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09292 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09293 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09294 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09295 }
09296 while ((cmd >= 0) && (cmd != 't')) {
09297 if (cmd)
09298 retries = 0;
09299 switch (cmd) {
09300 case '1':
09301 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09302 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09303 break;
09304 case '2':
09305 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09306 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09307 break;
09308 case '3':
09309 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09310 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09311 break;
09312 case '4':
09313 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09314 break;
09315 case '5':
09316 if (vmu->password[0] == '-') {
09317 cmd = ast_play_and_wait(chan, "vm-no");
09318 break;
09319 }
09320 newpassword[1] = '\0';
09321 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09322 if (cmd == '#')
09323 newpassword[0] = '\0';
09324 else {
09325 if (cmd < 0)
09326 break;
09327 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09328 break;
09329 }
09330 }
09331 cmd = check_password(vmu, newpassword);
09332 if (cmd != 0) {
09333 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09334 cmd = ast_play_and_wait(chan, vm_invalid_password);
09335 if (!cmd) {
09336 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09337 }
09338 break;
09339 }
09340 newpassword2[1] = '\0';
09341 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09342 if (cmd == '#')
09343 newpassword2[0] = '\0';
09344 else {
09345 if (cmd < 0)
09346 break;
09347
09348 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09349 break;
09350 }
09351 }
09352 if (strcmp(newpassword, newpassword2)) {
09353 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09354 cmd = ast_play_and_wait(chan, vm_mismatch);
09355 if (!cmd) {
09356 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09357 }
09358 break;
09359 }
09360
09361 if (pwdchange & PWDCHANGE_INTERNAL) {
09362 vm_change_password(vmu, newpassword);
09363 }
09364 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09365 vm_change_password_shell(vmu, newpassword);
09366 }
09367
09368 ast_debug(1, "User %s set password to %s of length %d\n",
09369 vms->username, newpassword, (int) strlen(newpassword));
09370 cmd = ast_play_and_wait(chan, vm_passchanged);
09371 break;
09372 case '*':
09373 cmd = 't';
09374 break;
09375 default:
09376 cmd = 0;
09377 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09378 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09379 if (ast_fileexists(prefile, NULL, NULL)) {
09380 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09381 }
09382 DISPOSE(prefile, -1);
09383 if (!cmd) {
09384 cmd = ast_play_and_wait(chan, "vm-options");
09385 }
09386 if (!cmd) {
09387 cmd = ast_waitfordigit(chan, 6000);
09388 }
09389 if (!cmd) {
09390 retries++;
09391 }
09392 if (retries > 3) {
09393 cmd = 't';
09394 }
09395 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09396 }
09397 }
09398 if (cmd == 't')
09399 cmd = 0;
09400 return cmd;
09401 }
09402
09403
09404
09405
09406
09407
09408
09409
09410
09411
09412
09413
09414
09415
09416
09417
09418
09419 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09420 {
09421 int cmd = 0;
09422 int retries = 0;
09423 int duration = 0;
09424 char prefile[PATH_MAX] = "";
09425 unsigned char buf[256];
09426 int bytes = 0;
09427
09428 if (ast_adsi_available(chan)) {
09429 bytes += adsi_logo(buf + bytes);
09430 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09431 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09432 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09433 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09434 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09435 }
09436
09437 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09438 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09439 while ((cmd >= 0) && (cmd != 't')) {
09440 if (cmd)
09441 retries = 0;
09442 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09443 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09444 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09445 cmd = 't';
09446 } else {
09447 switch (cmd) {
09448 case '1':
09449 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09450 break;
09451 case '2':
09452 DELETE(prefile, -1, prefile, vmu);
09453 ast_play_and_wait(chan, "vm-tempremoved");
09454 cmd = 't';
09455 break;
09456 case '*':
09457 cmd = 't';
09458 break;
09459 default:
09460 cmd = ast_play_and_wait(chan,
09461 ast_fileexists(prefile, NULL, NULL) > 0 ?
09462 "vm-tempgreeting2" : "vm-tempgreeting");
09463 if (!cmd) {
09464 cmd = ast_waitfordigit(chan, 6000);
09465 }
09466 if (!cmd) {
09467 retries++;
09468 }
09469 if (retries > 3) {
09470 cmd = 't';
09471 }
09472 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09473 }
09474 }
09475 DISPOSE(prefile, -1);
09476 }
09477 if (cmd == 't')
09478 cmd = 0;
09479 return cmd;
09480 }
09481
09482
09483
09484
09485
09486
09487
09488
09489
09490 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09491 {
09492 int cmd = 0;
09493
09494 if (vms->lastmsg > -1) {
09495 cmd = play_message(chan, vmu, vms);
09496 } else {
09497 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09498 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09499 if (!cmd) {
09500 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09501 cmd = ast_play_and_wait(chan, vms->fn);
09502 }
09503 if (!cmd)
09504 cmd = ast_play_and_wait(chan, "vm-messages");
09505 } else {
09506 if (!cmd)
09507 cmd = ast_play_and_wait(chan, "vm-messages");
09508 if (!cmd) {
09509 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09510 cmd = ast_play_and_wait(chan, vms->fn);
09511 }
09512 }
09513 }
09514 return cmd;
09515 }
09516
09517
09518 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09519 {
09520 int cmd = 0;
09521
09522 if (vms->lastmsg > -1) {
09523 cmd = play_message(chan, vmu, vms);
09524 } else {
09525 if (!strcasecmp(vms->fn, "INBOX")) {
09526 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09527 } else {
09528 cmd = ast_play_and_wait(chan, "vm-nomessages");
09529 }
09530 }
09531 return cmd;
09532 }
09533
09534
09535
09536
09537
09538
09539
09540
09541
09542 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09543 {
09544 int cmd = 0;
09545
09546 if (vms->lastmsg > -1) {
09547 cmd = play_message(chan, vmu, vms);
09548 } else {
09549 cmd = ast_play_and_wait(chan, "vm-youhave");
09550 if (!cmd)
09551 cmd = ast_play_and_wait(chan, "vm-no");
09552 if (!cmd) {
09553 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09554 cmd = ast_play_and_wait(chan, vms->fn);
09555 }
09556 if (!cmd)
09557 cmd = ast_play_and_wait(chan, "vm-messages");
09558 }
09559 return cmd;
09560 }
09561
09562
09563
09564
09565
09566
09567
09568
09569
09570 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09571 {
09572 int cmd;
09573
09574 if (vms->lastmsg > -1) {
09575 cmd = play_message(chan, vmu, vms);
09576 } else {
09577 cmd = ast_play_and_wait(chan, "vm-no");
09578 if (!cmd)
09579 cmd = ast_play_and_wait(chan, "vm-message");
09580 if (!cmd) {
09581 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09582 cmd = ast_play_and_wait(chan, vms->fn);
09583 }
09584 }
09585 return cmd;
09586 }
09587
09588
09589
09590
09591
09592
09593
09594
09595
09596 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09597 {
09598 int cmd;
09599
09600 if (vms->lastmsg > -1) {
09601 cmd = play_message(chan, vmu, vms);
09602 } else {
09603 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09604 if (!cmd)
09605 cmd = ast_play_and_wait(chan, "vm-messages");
09606 if (!cmd) {
09607 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09608 cmd = ast_play_and_wait(chan, vms->fn);
09609 }
09610 }
09611 return cmd;
09612 }
09613
09614
09615
09616
09617
09618
09619
09620
09621
09622 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09623 {
09624 int cmd;
09625
09626 if (vms->lastmsg > -1) {
09627 cmd = play_message(chan, vmu, vms);
09628 } else {
09629 cmd = ast_play_and_wait(chan, "vm-no");
09630 if (!cmd) {
09631 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09632 cmd = ast_play_and_wait(chan, vms->fn);
09633 }
09634 if (!cmd)
09635 cmd = ast_play_and_wait(chan, "vm-messages");
09636 }
09637 return cmd;
09638 }
09639
09640
09641
09642
09643
09644
09645
09646
09647
09648 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09649 {
09650 int cmd;
09651
09652 if (vms->lastmsg > -1) {
09653 cmd = play_message(chan, vmu, vms);
09654 } else {
09655 cmd = ast_play_and_wait(chan, "vm-you");
09656 if (!cmd)
09657 cmd = ast_play_and_wait(chan, "vm-haveno");
09658 if (!cmd)
09659 cmd = ast_play_and_wait(chan, "vm-messages");
09660 if (!cmd) {
09661 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09662 cmd = ast_play_and_wait(chan, vms->fn);
09663 }
09664 }
09665 return cmd;
09666 }
09667
09668
09669
09670
09671
09672
09673
09674
09675
09676 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09677 {
09678 int cmd = 0;
09679
09680 if (vms->lastmsg > -1) {
09681 cmd = play_message(chan, vmu, vms);
09682 } else {
09683 cmd = ast_play_and_wait(chan, "vm-no");
09684 if (!cmd) {
09685 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09686 cmd = ast_play_and_wait(chan, vms->fn);
09687 }
09688 }
09689 return cmd;
09690 }
09691
09692
09693
09694
09695
09696
09697
09698
09699
09700
09701
09702
09703 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09704 {
09705 if (!strncasecmp(chan->language, "es", 2)) {
09706 return vm_browse_messages_es(chan, vms, vmu);
09707 } else if (!strncasecmp(chan->language, "gr", 2)) {
09708 return vm_browse_messages_gr(chan, vms, vmu);
09709 } else if (!strncasecmp(chan->language, "he", 2)) {
09710 return vm_browse_messages_he(chan, vms, vmu);
09711 } else if (!strncasecmp(chan->language, "it", 2)) {
09712 return vm_browse_messages_it(chan, vms, vmu);
09713 } else if (!strncasecmp(chan->language, "pt", 2)) {
09714 return vm_browse_messages_pt(chan, vms, vmu);
09715 } else if (!strncasecmp(chan->language, "vi", 2)) {
09716 return vm_browse_messages_vi(chan, vms, vmu);
09717 } else if (!strncasecmp(chan->language, "zh", 2)) {
09718 return vm_browse_messages_zh(chan, vms, vmu);
09719 } else {
09720 return vm_browse_messages_en(chan, vms, vmu);
09721 }
09722 }
09723
09724 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09725 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09726 int skipuser, int max_logins, int silent)
09727 {
09728 int useadsi = 0, valid = 0, logretries = 0;
09729 char password[AST_MAX_EXTENSION]="", *passptr;
09730 struct ast_vm_user vmus, *vmu = NULL;
09731
09732
09733 adsi_begin(chan, &useadsi);
09734 if (!skipuser && useadsi)
09735 adsi_login(chan);
09736 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09737 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09738 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09739 return -1;
09740 }
09741
09742
09743
09744 while (!valid && (logretries < max_logins)) {
09745
09746 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09747 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09748 return -1;
09749 }
09750 if (ast_strlen_zero(mailbox)) {
09751 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09752 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09753 } else {
09754 ast_verb(3, "Username not entered\n");
09755 return -1;
09756 }
09757 } else if (mailbox[0] == '*') {
09758
09759 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09760 if (ast_exists_extension(chan, chan->context, "a", 1,
09761 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09762 return -1;
09763 }
09764 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09765 mailbox[0] = '\0';
09766 }
09767
09768 if (useadsi)
09769 adsi_password(chan);
09770
09771 if (!ast_strlen_zero(prefix)) {
09772 char fullusername[80] = "";
09773 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09774 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09775 ast_copy_string(mailbox, fullusername, mailbox_size);
09776 }
09777
09778 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09779 vmu = find_user(&vmus, context, mailbox);
09780 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09781
09782 password[0] = '\0';
09783 } else {
09784 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09785 if (ast_streamfile(chan, vm_password, chan->language)) {
09786 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09787 return -1;
09788 }
09789 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09790 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09791 return -1;
09792 } else if (password[0] == '*') {
09793
09794 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09795 if (ast_exists_extension(chan, chan->context, "a", 1,
09796 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09797 mailbox[0] = '*';
09798 return -1;
09799 }
09800 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09801 mailbox[0] = '\0';
09802
09803 vmu = NULL;
09804 }
09805 }
09806
09807 if (vmu) {
09808 passptr = vmu->password;
09809 if (passptr[0] == '-') passptr++;
09810 }
09811 if (vmu && !strcmp(passptr, password))
09812 valid++;
09813 else {
09814 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09815 if (!ast_strlen_zero(prefix))
09816 mailbox[0] = '\0';
09817 }
09818 logretries++;
09819 if (!valid) {
09820 if (skipuser || logretries >= max_logins) {
09821 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09822 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09823 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09824 return -1;
09825 }
09826 } else {
09827 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09828 if (useadsi)
09829 adsi_login(chan);
09830 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09831 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09832 return -1;
09833 }
09834 }
09835 if (ast_waitstream(chan, ""))
09836 return -1;
09837 }
09838 }
09839 if (!valid && (logretries >= max_logins)) {
09840 ast_stopstream(chan);
09841 ast_play_and_wait(chan, "vm-goodbye");
09842 return -1;
09843 }
09844 if (vmu && !skipuser) {
09845 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09846 }
09847 return 0;
09848 }
09849
09850 static int vm_execmain(struct ast_channel *chan, const char *data)
09851 {
09852
09853
09854
09855 int res = -1;
09856 int cmd = 0;
09857 int valid = 0;
09858 char prefixstr[80] ="";
09859 char ext_context[256]="";
09860 int box;
09861 int useadsi = 0;
09862 int skipuser = 0;
09863 struct vm_state vms;
09864 struct ast_vm_user *vmu = NULL, vmus;
09865 char *context = NULL;
09866 int silentexit = 0;
09867 struct ast_flags flags = { 0 };
09868 signed char record_gain = 0;
09869 int play_auto = 0;
09870 int play_folder = 0;
09871 int in_urgent = 0;
09872 #ifdef IMAP_STORAGE
09873 int deleted = 0;
09874 #endif
09875
09876
09877 memset(&vms, 0, sizeof(vms));
09878
09879 vms.lastmsg = -1;
09880
09881 memset(&vmus, 0, sizeof(vmus));
09882
09883 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09884 if (chan->_state != AST_STATE_UP) {
09885 ast_debug(1, "Before ast_answer\n");
09886 ast_answer(chan);
09887 }
09888
09889 if (!ast_strlen_zero(data)) {
09890 char *opts[OPT_ARG_ARRAY_SIZE];
09891 char *parse;
09892 AST_DECLARE_APP_ARGS(args,
09893 AST_APP_ARG(argv0);
09894 AST_APP_ARG(argv1);
09895 );
09896
09897 parse = ast_strdupa(data);
09898
09899 AST_STANDARD_APP_ARGS(args, parse);
09900
09901 if (args.argc == 2) {
09902 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09903 return -1;
09904 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09905 int gain;
09906 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09907 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09908 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09909 return -1;
09910 } else {
09911 record_gain = (signed char) gain;
09912 }
09913 } else {
09914 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09915 }
09916 }
09917 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09918 play_auto = 1;
09919 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09920
09921 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09922 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09923 play_folder = -1;
09924 }
09925 } else {
09926 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09927 }
09928 } else {
09929 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09930 }
09931 if (play_folder > 9 || play_folder < 0) {
09932 ast_log(AST_LOG_WARNING,
09933 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09934 opts[OPT_ARG_PLAYFOLDER]);
09935 play_folder = 0;
09936 }
09937 }
09938 } else {
09939
09940 while (*(args.argv0)) {
09941 if (*(args.argv0) == 's')
09942 ast_set_flag(&flags, OPT_SILENT);
09943 else if (*(args.argv0) == 'p')
09944 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09945 else
09946 break;
09947 (args.argv0)++;
09948 }
09949
09950 }
09951
09952 valid = ast_test_flag(&flags, OPT_SILENT);
09953
09954 if ((context = strchr(args.argv0, '@')))
09955 *context++ = '\0';
09956
09957 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09958 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09959 else
09960 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09961
09962 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09963 skipuser++;
09964 else
09965 valid = 0;
09966 }
09967
09968 if (!valid)
09969 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09970
09971 ast_debug(1, "After vm_authenticate\n");
09972
09973 if (vms.username[0] == '*') {
09974 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09975
09976
09977 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09978 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
09979 res = 0;
09980 goto out;
09981 }
09982 }
09983
09984 if (!res) {
09985 valid = 1;
09986 if (!skipuser)
09987 vmu = &vmus;
09988 } else {
09989 res = 0;
09990 }
09991
09992
09993 adsi_begin(chan, &useadsi);
09994
09995 ast_test_suite_assert(valid);
09996 if (!valid) {
09997 goto out;
09998 }
09999 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10000
10001 #ifdef IMAP_STORAGE
10002 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10003 pthread_setspecific(ts_vmstate.key, &vms);
10004
10005 vms.interactive = 1;
10006 vms.updated = 1;
10007 if (vmu)
10008 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10009 vmstate_insert(&vms);
10010 init_vm_state(&vms);
10011 #endif
10012
10013 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
10014 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
10015 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10016 return -1;
10017 }
10018 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
10019 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
10020 cmd = ast_play_and_wait(chan, "an-error-has-occured");
10021 return -1;
10022 }
10023
10024
10025 if (!ast_strlen_zero(vmu->language))
10026 ast_string_field_set(chan, language, vmu->language);
10027
10028
10029 ast_debug(1, "Before open_mailbox\n");
10030 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10031 if (res < 0)
10032 goto out;
10033 vms.oldmessages = vms.lastmsg + 1;
10034 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10035
10036 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10037 if (res < 0)
10038 goto out;
10039 vms.newmessages = vms.lastmsg + 1;
10040 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10041
10042 in_urgent = 1;
10043 res = open_mailbox(&vms, vmu, 11);
10044 if (res < 0)
10045 goto out;
10046 vms.urgentmessages = vms.lastmsg + 1;
10047 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10048
10049
10050 if (play_auto) {
10051 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10052 if (vms.urgentmessages) {
10053 in_urgent = 1;
10054 res = open_mailbox(&vms, vmu, 11);
10055 } else {
10056 in_urgent = 0;
10057 res = open_mailbox(&vms, vmu, play_folder);
10058 }
10059 if (res < 0)
10060 goto out;
10061
10062
10063 if (vms.lastmsg == -1) {
10064 in_urgent = 0;
10065 cmd = vm_browse_messages(chan, &vms, vmu);
10066 res = 0;
10067 goto out;
10068 }
10069 } else {
10070 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10071
10072 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10073 in_urgent = 0;
10074 play_folder = 1;
10075 if (res < 0)
10076 goto out;
10077 } else if (!vms.urgentmessages && vms.newmessages) {
10078
10079 in_urgent = 0;
10080 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10081 if (res < 0)
10082 goto out;
10083 }
10084 }
10085
10086 if (useadsi)
10087 adsi_status(chan, &vms);
10088 res = 0;
10089
10090
10091 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10092 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10093 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10094 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10095 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10096 if ((cmd == 't') || (cmd == '#')) {
10097
10098 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10099 res = 0;
10100 goto out;
10101 } else if (cmd < 0) {
10102
10103 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10104 res = -1;
10105 goto out;
10106 }
10107 }
10108 #ifdef IMAP_STORAGE
10109 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10110 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10111 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10112 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10113 }
10114 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10115 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10116 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10117 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10118 }
10119 #endif
10120
10121 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10122 if (play_auto) {
10123 cmd = '1';
10124 } else {
10125 cmd = vm_intro(chan, vmu, &vms);
10126 }
10127 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10128
10129 vms.repeats = 0;
10130 vms.starting = 1;
10131 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10132
10133 switch (cmd) {
10134 case '1':
10135 vms.curmsg = 0;
10136
10137 case '5':
10138 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10139 cmd = vm_browse_messages(chan, &vms, vmu);
10140 break;
10141 case '2':
10142 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10143 if (useadsi)
10144 adsi_folders(chan, 0, "Change to folder...");
10145
10146 cmd = get_folder2(chan, "vm-changeto", 0);
10147 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10148 if (cmd == '#') {
10149 cmd = 0;
10150 } else if (cmd > 0) {
10151 cmd = cmd - '0';
10152 res = close_mailbox(&vms, vmu);
10153 if (res == ERROR_LOCK_PATH)
10154 goto out;
10155
10156 if (cmd != 11) in_urgent = 0;
10157 res = open_mailbox(&vms, vmu, cmd);
10158 if (res < 0)
10159 goto out;
10160 play_folder = cmd;
10161 cmd = 0;
10162 }
10163 if (useadsi)
10164 adsi_status2(chan, &vms);
10165
10166 if (!cmd) {
10167 cmd = vm_play_folder_name(chan, vms.vmbox);
10168 }
10169
10170 vms.starting = 1;
10171 break;
10172 case '3':
10173 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10174 cmd = 0;
10175 vms.repeats = 0;
10176 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10177 switch (cmd) {
10178 case '1':
10179 if (vms.lastmsg > -1 && !vms.starting) {
10180 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10181 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10182 res = cmd;
10183 goto out;
10184 }
10185 } else {
10186 cmd = ast_play_and_wait(chan, "vm-sorry");
10187 }
10188 cmd = 't';
10189 break;
10190 case '2':
10191 if (!vms.starting)
10192 ast_verb(3, "Callback Requested\n");
10193 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10194 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10195 if (cmd == 9) {
10196 silentexit = 1;
10197 goto out;
10198 } else if (cmd == ERROR_LOCK_PATH) {
10199 res = cmd;
10200 goto out;
10201 }
10202 } else {
10203 cmd = ast_play_and_wait(chan, "vm-sorry");
10204 }
10205 cmd = 't';
10206 break;
10207 case '3':
10208 if (vms.lastmsg > -1 && !vms.starting) {
10209 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10210 if (cmd == ERROR_LOCK_PATH) {
10211 res = cmd;
10212 goto out;
10213 }
10214 } else {
10215 cmd = ast_play_and_wait(chan, "vm-sorry");
10216 }
10217 cmd = 't';
10218 break;
10219 case '4':
10220 if (!ast_strlen_zero(vmu->dialout)) {
10221 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10222 if (cmd == 9) {
10223 silentexit = 1;
10224 goto out;
10225 }
10226 } else {
10227 cmd = ast_play_and_wait(chan, "vm-sorry");
10228 }
10229 cmd = 't';
10230 break;
10231
10232 case '5':
10233 if (ast_test_flag(vmu, VM_SVMAIL)) {
10234 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10235 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10236 res = cmd;
10237 goto out;
10238 }
10239 } else {
10240 cmd = ast_play_and_wait(chan, "vm-sorry");
10241 }
10242 cmd = 't';
10243 break;
10244
10245 case '*':
10246 cmd = 't';
10247 break;
10248
10249 default:
10250 cmd = 0;
10251 if (!vms.starting) {
10252 cmd = ast_play_and_wait(chan, "vm-toreply");
10253 }
10254 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10255 cmd = ast_play_and_wait(chan, "vm-tocallback");
10256 }
10257 if (!cmd && !vms.starting) {
10258 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10259 }
10260 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10261 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10262 }
10263 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10264 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10265 }
10266 if (!cmd) {
10267 cmd = ast_play_and_wait(chan, "vm-starmain");
10268 }
10269 if (!cmd) {
10270 cmd = ast_waitfordigit(chan, 6000);
10271 }
10272 if (!cmd) {
10273 vms.repeats++;
10274 }
10275 if (vms.repeats > 3) {
10276 cmd = 't';
10277 }
10278 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10279 }
10280 }
10281 if (cmd == 't') {
10282 cmd = 0;
10283 vms.repeats = 0;
10284 }
10285 break;
10286 case '4':
10287 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10288 if (vms.curmsg > 0) {
10289 vms.curmsg--;
10290 cmd = play_message(chan, vmu, &vms);
10291 } else {
10292
10293
10294
10295
10296 if (in_urgent == 0 && vms.urgentmessages > 0) {
10297
10298 in_urgent = 1;
10299 res = close_mailbox(&vms, vmu);
10300 if (res == ERROR_LOCK_PATH)
10301 goto out;
10302 res = open_mailbox(&vms, vmu, 11);
10303 if (res < 0)
10304 goto out;
10305 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10306 vms.curmsg = vms.lastmsg;
10307 if (vms.lastmsg < 0) {
10308 cmd = ast_play_and_wait(chan, "vm-nomore");
10309 }
10310 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10311 vms.curmsg = vms.lastmsg;
10312 cmd = play_message(chan, vmu, &vms);
10313 } else {
10314 cmd = ast_play_and_wait(chan, "vm-nomore");
10315 }
10316 }
10317 break;
10318 case '6':
10319 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10320 if (vms.curmsg < vms.lastmsg) {
10321 vms.curmsg++;
10322 cmd = play_message(chan, vmu, &vms);
10323 } else {
10324 if (in_urgent && vms.newmessages > 0) {
10325
10326
10327
10328
10329 in_urgent = 0;
10330 res = close_mailbox(&vms, vmu);
10331 if (res == ERROR_LOCK_PATH)
10332 goto out;
10333 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10334 if (res < 0)
10335 goto out;
10336 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10337 vms.curmsg = -1;
10338 if (vms.lastmsg < 0) {
10339 cmd = ast_play_and_wait(chan, "vm-nomore");
10340 }
10341 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10342 vms.curmsg = 0;
10343 cmd = play_message(chan, vmu, &vms);
10344 } else {
10345 cmd = ast_play_and_wait(chan, "vm-nomore");
10346 }
10347 }
10348 break;
10349 case '7':
10350 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10351 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10352 if (useadsi)
10353 adsi_delete(chan, &vms);
10354 if (vms.deleted[vms.curmsg]) {
10355 if (play_folder == 0) {
10356 if (in_urgent) {
10357 vms.urgentmessages--;
10358 } else {
10359 vms.newmessages--;
10360 }
10361 }
10362 else if (play_folder == 1)
10363 vms.oldmessages--;
10364 cmd = ast_play_and_wait(chan, "vm-deleted");
10365 } else {
10366 if (play_folder == 0) {
10367 if (in_urgent) {
10368 vms.urgentmessages++;
10369 } else {
10370 vms.newmessages++;
10371 }
10372 }
10373 else if (play_folder == 1)
10374 vms.oldmessages++;
10375 cmd = ast_play_and_wait(chan, "vm-undeleted");
10376 }
10377 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10378 if (vms.curmsg < vms.lastmsg) {
10379 vms.curmsg++;
10380 cmd = play_message(chan, vmu, &vms);
10381 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10382 vms.curmsg = 0;
10383 cmd = play_message(chan, vmu, &vms);
10384 } else {
10385
10386
10387
10388
10389 if (in_urgent == 1) {
10390
10391 in_urgent = 0;
10392 res = close_mailbox(&vms, vmu);
10393 if (res == ERROR_LOCK_PATH)
10394 goto out;
10395 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10396 if (res < 0)
10397 goto out;
10398 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10399 vms.curmsg = -1;
10400 if (vms.lastmsg < 0) {
10401 cmd = ast_play_and_wait(chan, "vm-nomore");
10402 }
10403 } else {
10404 cmd = ast_play_and_wait(chan, "vm-nomore");
10405 }
10406 }
10407 }
10408 } else
10409 cmd = 0;
10410 #ifdef IMAP_STORAGE
10411 deleted = 1;
10412 #endif
10413 break;
10414
10415 case '8':
10416 if (vms.lastmsg > -1) {
10417 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10418 if (cmd == ERROR_LOCK_PATH) {
10419 res = cmd;
10420 goto out;
10421 }
10422 } else {
10423
10424
10425
10426
10427 if (in_urgent == 1 && vms.newmessages > 0) {
10428
10429 in_urgent = 0;
10430 res = close_mailbox(&vms, vmu);
10431 if (res == ERROR_LOCK_PATH)
10432 goto out;
10433 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10434 if (res < 0)
10435 goto out;
10436 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10437 vms.curmsg = -1;
10438 if (vms.lastmsg < 0) {
10439 cmd = ast_play_and_wait(chan, "vm-nomore");
10440 }
10441 } else {
10442 cmd = ast_play_and_wait(chan, "vm-nomore");
10443 }
10444 }
10445 break;
10446 case '9':
10447 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10448 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10449
10450 cmd = 0;
10451 break;
10452 }
10453 if (useadsi)
10454 adsi_folders(chan, 1, "Save to folder...");
10455 cmd = get_folder2(chan, "vm-savefolder", 1);
10456 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10457 box = 0;
10458 if (cmd == '#') {
10459 cmd = 0;
10460 break;
10461 } else if (cmd > 0) {
10462 box = cmd = cmd - '0';
10463 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10464 if (cmd == ERROR_LOCK_PATH) {
10465 res = cmd;
10466 goto out;
10467 #ifndef IMAP_STORAGE
10468 } else if (!cmd) {
10469 vms.deleted[vms.curmsg] = 1;
10470 #endif
10471 } else {
10472 vms.deleted[vms.curmsg] = 0;
10473 vms.heard[vms.curmsg] = 0;
10474 }
10475 }
10476 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10477 if (useadsi)
10478 adsi_message(chan, &vms);
10479 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10480 if (!cmd) {
10481 cmd = ast_play_and_wait(chan, "vm-message");
10482 if (!cmd)
10483 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10484 if (!cmd)
10485 cmd = ast_play_and_wait(chan, "vm-savedto");
10486 if (!cmd)
10487 cmd = vm_play_folder_name(chan, vms.fn);
10488 } else {
10489 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10490 }
10491 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10492 if (vms.curmsg < vms.lastmsg) {
10493 vms.curmsg++;
10494 cmd = play_message(chan, vmu, &vms);
10495 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10496 vms.curmsg = 0;
10497 cmd = play_message(chan, vmu, &vms);
10498 } else {
10499
10500
10501
10502
10503 if (in_urgent == 1 && vms.newmessages > 0) {
10504
10505 in_urgent = 0;
10506 res = close_mailbox(&vms, vmu);
10507 if (res == ERROR_LOCK_PATH)
10508 goto out;
10509 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10510 if (res < 0)
10511 goto out;
10512 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10513 vms.curmsg = -1;
10514 if (vms.lastmsg < 0) {
10515 cmd = ast_play_and_wait(chan, "vm-nomore");
10516 }
10517 } else {
10518 cmd = ast_play_and_wait(chan, "vm-nomore");
10519 }
10520 }
10521 }
10522 break;
10523 case '*':
10524 if (!vms.starting) {
10525 cmd = ast_play_and_wait(chan, "vm-onefor");
10526 if (!strncasecmp(chan->language, "he", 2)) {
10527 cmd = ast_play_and_wait(chan, "vm-for");
10528 }
10529 if (!cmd)
10530 cmd = vm_play_folder_name(chan, vms.vmbox);
10531 if (!cmd)
10532 cmd = ast_play_and_wait(chan, "vm-opts");
10533 if (!cmd)
10534 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10535 } else
10536 cmd = 0;
10537 break;
10538 case '0':
10539 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10540 if (useadsi)
10541 adsi_status(chan, &vms);
10542 break;
10543 default:
10544 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10545 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10546 break;
10547 }
10548 }
10549 if ((cmd == 't') || (cmd == '#')) {
10550
10551 res = 0;
10552 } else {
10553
10554 res = -1;
10555 }
10556
10557 out:
10558 if (res > -1) {
10559 ast_stopstream(chan);
10560 adsi_goodbye(chan);
10561 if (valid && res != OPERATOR_EXIT) {
10562 if (silentexit)
10563 res = ast_play_and_wait(chan, "vm-dialout");
10564 else
10565 res = ast_play_and_wait(chan, "vm-goodbye");
10566 }
10567 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10568 res = 0;
10569 }
10570 if (useadsi)
10571 ast_adsi_unload_session(chan);
10572 }
10573 if (vmu)
10574 close_mailbox(&vms, vmu);
10575 if (valid) {
10576 int new = 0, old = 0, urgent = 0;
10577 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10578 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10579
10580 run_externnotify(vmu->context, vmu->mailbox, NULL);
10581 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10582 queue_mwi_event(ext_context, urgent, new, old);
10583 }
10584 #ifdef IMAP_STORAGE
10585
10586 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10587 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10588 ast_mutex_lock(&vms.lock);
10589 #ifdef HAVE_IMAP_TK2006
10590 if (LEVELUIDPLUS (vms.mailstream)) {
10591 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10592 } else
10593 #endif
10594 mail_expunge(vms.mailstream);
10595 ast_mutex_unlock(&vms.lock);
10596 }
10597
10598
10599 if (vmu) {
10600 vmstate_delete(&vms);
10601 }
10602 #endif
10603 if (vmu)
10604 free_user(vmu);
10605 if (vms.deleted)
10606 ast_free(vms.deleted);
10607 if (vms.heard)
10608 ast_free(vms.heard);
10609
10610 #ifdef IMAP_STORAGE
10611 pthread_setspecific(ts_vmstate.key, NULL);
10612 #endif
10613 return res;
10614 }
10615
10616 static int vm_exec(struct ast_channel *chan, const char *data)
10617 {
10618 int res = 0;
10619 char *tmp;
10620 struct leave_vm_options leave_options;
10621 struct ast_flags flags = { 0 };
10622 char *opts[OPT_ARG_ARRAY_SIZE];
10623 AST_DECLARE_APP_ARGS(args,
10624 AST_APP_ARG(argv0);
10625 AST_APP_ARG(argv1);
10626 );
10627
10628 memset(&leave_options, 0, sizeof(leave_options));
10629
10630 if (chan->_state != AST_STATE_UP)
10631 ast_answer(chan);
10632
10633 if (!ast_strlen_zero(data)) {
10634 tmp = ast_strdupa(data);
10635 AST_STANDARD_APP_ARGS(args, tmp);
10636 if (args.argc == 2) {
10637 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10638 return -1;
10639 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10640 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10641 int gain;
10642
10643 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10644 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10645 return -1;
10646 } else {
10647 leave_options.record_gain = (signed char) gain;
10648 }
10649 }
10650 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10651 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10652 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10653 }
10654 }
10655 } else {
10656 char temp[256];
10657 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10658 if (res < 0)
10659 return res;
10660 if (ast_strlen_zero(temp))
10661 return 0;
10662 args.argv0 = ast_strdupa(temp);
10663 }
10664
10665 res = leave_voicemail(chan, args.argv0, &leave_options);
10666 if (res == 't') {
10667 ast_play_and_wait(chan, "vm-goodbye");
10668 res = 0;
10669 }
10670
10671 if (res == OPERATOR_EXIT) {
10672 res = 0;
10673 }
10674
10675 if (res == ERROR_LOCK_PATH) {
10676 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10677 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10678 res = 0;
10679 }
10680
10681 return res;
10682 }
10683
10684 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10685 {
10686 struct ast_vm_user *vmu;
10687
10688 if (!ast_strlen_zero(box) && box[0] == '*') {
10689 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10690 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10691 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10692 "\n\tand will be ignored.\n", box, context);
10693 return NULL;
10694 }
10695
10696 AST_LIST_TRAVERSE(&users, vmu, list) {
10697 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10698 if (strcasecmp(vmu->context, context)) {
10699 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10700 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10701 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10702 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10703 }
10704 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10705 return NULL;
10706 }
10707 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10708 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10709 return NULL;
10710 }
10711 }
10712
10713 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10714 return NULL;
10715
10716 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10717 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10718
10719 AST_LIST_INSERT_TAIL(&users, vmu, list);
10720
10721 return vmu;
10722 }
10723
10724 static int append_mailbox(const char *context, const char *box, const char *data)
10725 {
10726
10727 char *tmp;
10728 char *stringp;
10729 char *s;
10730 struct ast_vm_user *vmu;
10731 char *mailbox_full;
10732 int new = 0, old = 0, urgent = 0;
10733 char secretfn[PATH_MAX] = "";
10734
10735 tmp = ast_strdupa(data);
10736
10737 if (!(vmu = find_or_create(context, box)))
10738 return -1;
10739
10740 populate_defaults(vmu);
10741
10742 stringp = tmp;
10743 if ((s = strsep(&stringp, ","))) {
10744 if (!ast_strlen_zero(s) && s[0] == '*') {
10745 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10746 "\n\tmust be reset in voicemail.conf.\n", box);
10747 }
10748
10749 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10750 }
10751 if (stringp && (s = strsep(&stringp, ","))) {
10752 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10753 }
10754 if (stringp && (s = strsep(&stringp, ","))) {
10755 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10756 }
10757 if (stringp && (s = strsep(&stringp, ","))) {
10758 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10759 }
10760 if (stringp && (s = strsep(&stringp, ","))) {
10761 apply_options(vmu, s);
10762 }
10763
10764 switch (vmu->passwordlocation) {
10765 case OPT_PWLOC_SPOOLDIR:
10766 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10767 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10768 }
10769
10770 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10771 strcpy(mailbox_full, box);
10772 strcat(mailbox_full, "@");
10773 strcat(mailbox_full, context);
10774
10775 inboxcount2(mailbox_full, &urgent, &new, &old);
10776 queue_mwi_event(mailbox_full, urgent, new, old);
10777
10778 return 0;
10779 }
10780
10781 AST_TEST_DEFINE(test_voicemail_vmuser)
10782 {
10783 int res = 0;
10784 struct ast_vm_user *vmu;
10785
10786 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10787 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10788 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10789 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10790 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10791 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10792 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10793 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10794 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10795 #ifdef IMAP_STORAGE
10796 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10797 "imapfolder=INBOX|imapvmshareid=6000";
10798 #endif
10799
10800 switch (cmd) {
10801 case TEST_INIT:
10802 info->name = "vmuser";
10803 info->category = "/apps/app_voicemail/";
10804 info->summary = "Vmuser unit test";
10805 info->description =
10806 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10807 return AST_TEST_NOT_RUN;
10808 case TEST_EXECUTE:
10809 break;
10810 }
10811
10812 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10813 return AST_TEST_NOT_RUN;
10814 }
10815 ast_set_flag(vmu, VM_ALLOCED);
10816 populate_defaults(vmu);
10817
10818 apply_options(vmu, options_string);
10819
10820 if (!ast_test_flag(vmu, VM_ATTACH)) {
10821 ast_test_status_update(test, "Parse failure for attach option\n");
10822 res = 1;
10823 }
10824 if (strcasecmp(vmu->attachfmt, "wav49")) {
10825 ast_test_status_update(test, "Parse failure for attachftm option\n");
10826 res = 1;
10827 }
10828 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10829 ast_test_status_update(test, "Parse failure for serveremail option\n");
10830 res = 1;
10831 }
10832 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10833 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10834 res = 1;
10835 }
10836 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10837 ast_test_status_update(test, "Parse failure for emailbody option\n");
10838 res = 1;
10839 }
10840 if (strcasecmp(vmu->zonetag, "central")) {
10841 ast_test_status_update(test, "Parse failure for tz option\n");
10842 res = 1;
10843 }
10844 if (!ast_test_flag(vmu, VM_DELETE)) {
10845 ast_test_status_update(test, "Parse failure for delete option\n");
10846 res = 1;
10847 }
10848 if (!ast_test_flag(vmu, VM_SAYCID)) {
10849 ast_test_status_update(test, "Parse failure for saycid option\n");
10850 res = 1;
10851 }
10852 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10853 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10854 res = 1;
10855 }
10856 if (!ast_test_flag(vmu, VM_REVIEW)) {
10857 ast_test_status_update(test, "Parse failure for review option\n");
10858 res = 1;
10859 }
10860 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10861 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10862 res = 1;
10863 }
10864 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10865 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10866 res = 1;
10867 }
10868 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10869 ast_test_status_update(test, "Parse failure for operator option\n");
10870 res = 1;
10871 }
10872 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10873 ast_test_status_update(test, "Parse failure for envelope option\n");
10874 res = 1;
10875 }
10876 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10877 ast_test_status_update(test, "Parse failure for moveheard option\n");
10878 res = 1;
10879 }
10880 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10881 ast_test_status_update(test, "Parse failure for sayduration option\n");
10882 res = 1;
10883 }
10884 if (vmu->saydurationm != 5) {
10885 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10886 res = 1;
10887 }
10888 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10889 ast_test_status_update(test, "Parse failure for forcename option\n");
10890 res = 1;
10891 }
10892 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10893 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10894 res = 1;
10895 }
10896 if (strcasecmp(vmu->callback, "somecontext")) {
10897 ast_test_status_update(test, "Parse failure for callbacks option\n");
10898 res = 1;
10899 }
10900 if (strcasecmp(vmu->dialout, "somecontext2")) {
10901 ast_test_status_update(test, "Parse failure for dialout option\n");
10902 res = 1;
10903 }
10904 if (strcasecmp(vmu->exit, "somecontext3")) {
10905 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10906 res = 1;
10907 }
10908 if (vmu->minsecs != 10) {
10909 ast_test_status_update(test, "Parse failure for minsecs option\n");
10910 res = 1;
10911 }
10912 if (vmu->maxsecs != 100) {
10913 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10914 res = 1;
10915 }
10916 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10917 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10918 res = 1;
10919 }
10920 if (vmu->maxdeletedmsg != 50) {
10921 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10922 res = 1;
10923 }
10924 if (vmu->volgain != 1.3) {
10925 ast_test_status_update(test, "Parse failure for volgain option\n");
10926 res = 1;
10927 }
10928 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10929 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10930 res = 1;
10931 }
10932 #ifdef IMAP_STORAGE
10933 apply_options(vmu, option_string2);
10934
10935 if (strcasecmp(vmu->imapuser, "imapuser")) {
10936 ast_test_status_update(test, "Parse failure for imapuser option\n");
10937 res = 1;
10938 }
10939 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10940 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10941 res = 1;
10942 }
10943 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10944 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10945 res = 1;
10946 }
10947 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10948 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10949 res = 1;
10950 }
10951 #endif
10952
10953 free_user(vmu);
10954 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10955 }
10956
10957 static int vm_box_exists(struct ast_channel *chan, const char *data)
10958 {
10959 struct ast_vm_user svm;
10960 char *context, *box;
10961 AST_DECLARE_APP_ARGS(args,
10962 AST_APP_ARG(mbox);
10963 AST_APP_ARG(options);
10964 );
10965 static int dep_warning = 0;
10966
10967 if (ast_strlen_zero(data)) {
10968 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10969 return -1;
10970 }
10971
10972 if (!dep_warning) {
10973 dep_warning = 1;
10974 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10975 }
10976
10977 box = ast_strdupa(data);
10978
10979 AST_STANDARD_APP_ARGS(args, box);
10980
10981 if (args.options) {
10982 }
10983
10984 if ((context = strchr(args.mbox, '@'))) {
10985 *context = '\0';
10986 context++;
10987 }
10988
10989 if (find_user(&svm, context, args.mbox)) {
10990 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10991 } else
10992 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10993
10994 return 0;
10995 }
10996
10997 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10998 {
10999 struct ast_vm_user svm;
11000 AST_DECLARE_APP_ARGS(arg,
11001 AST_APP_ARG(mbox);
11002 AST_APP_ARG(context);
11003 );
11004
11005 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11006
11007 if (ast_strlen_zero(arg.mbox)) {
11008 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11009 return -1;
11010 }
11011
11012 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11013 return 0;
11014 }
11015
11016 static struct ast_custom_function mailbox_exists_acf = {
11017 .name = "MAILBOX_EXISTS",
11018 .read = acf_mailbox_exists,
11019 };
11020
11021 static int vmauthenticate(struct ast_channel *chan, const char *data)
11022 {
11023 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11024 struct ast_vm_user vmus;
11025 char *options = NULL;
11026 int silent = 0, skipuser = 0;
11027 int res = -1;
11028
11029 if (data) {
11030 s = ast_strdupa(data);
11031 user = strsep(&s, ",");
11032 options = strsep(&s, ",");
11033 if (user) {
11034 s = user;
11035 user = strsep(&s, "@");
11036 context = strsep(&s, "");
11037 if (!ast_strlen_zero(user))
11038 skipuser++;
11039 ast_copy_string(mailbox, user, sizeof(mailbox));
11040 }
11041 }
11042
11043 if (options) {
11044 silent = (strchr(options, 's')) != NULL;
11045 }
11046
11047 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11048 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11049 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11050 ast_play_and_wait(chan, "auth-thankyou");
11051 res = 0;
11052 } else if (mailbox[0] == '*') {
11053
11054 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11055 res = 0;
11056 }
11057 }
11058
11059 return res;
11060 }
11061
11062 static char *show_users_realtime(int fd, const char *context)
11063 {
11064 struct ast_config *cfg;
11065 const char *cat = NULL;
11066
11067 if (!(cfg = ast_load_realtime_multientry("voicemail",
11068 "context", context, SENTINEL))) {
11069 return CLI_FAILURE;
11070 }
11071
11072 ast_cli(fd,
11073 "\n"
11074 "=============================================================\n"
11075 "=== Configured Voicemail Users ==============================\n"
11076 "=============================================================\n"
11077 "===\n");
11078
11079 while ((cat = ast_category_browse(cfg, cat))) {
11080 struct ast_variable *var = NULL;
11081 ast_cli(fd,
11082 "=== Mailbox ...\n"
11083 "===\n");
11084 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11085 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11086 ast_cli(fd,
11087 "===\n"
11088 "=== ---------------------------------------------------------\n"
11089 "===\n");
11090 }
11091
11092 ast_cli(fd,
11093 "=============================================================\n"
11094 "\n");
11095
11096 ast_config_destroy(cfg);
11097
11098 return CLI_SUCCESS;
11099 }
11100
11101 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11102 {
11103 int which = 0;
11104 int wordlen;
11105 struct ast_vm_user *vmu;
11106 const char *context = "";
11107
11108
11109 if (pos > 4)
11110 return NULL;
11111 if (pos == 3)
11112 return (state == 0) ? ast_strdup("for") : NULL;
11113 wordlen = strlen(word);
11114 AST_LIST_TRAVERSE(&users, vmu, list) {
11115 if (!strncasecmp(word, vmu->context, wordlen)) {
11116 if (context && strcmp(context, vmu->context) && ++which > state)
11117 return ast_strdup(vmu->context);
11118
11119 context = vmu->context;
11120 }
11121 }
11122 return NULL;
11123 }
11124
11125
11126 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11127 {
11128 struct ast_vm_user *vmu;
11129 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11130 const char *context = NULL;
11131 int users_counter = 0;
11132
11133 switch (cmd) {
11134 case CLI_INIT:
11135 e->command = "voicemail show users";
11136 e->usage =
11137 "Usage: voicemail show users [for <context>]\n"
11138 " Lists all mailboxes currently set up\n";
11139 return NULL;
11140 case CLI_GENERATE:
11141 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11142 }
11143
11144 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11145 return CLI_SHOWUSAGE;
11146 if (a->argc == 5) {
11147 if (strcmp(a->argv[3],"for"))
11148 return CLI_SHOWUSAGE;
11149 context = a->argv[4];
11150 }
11151
11152 if (ast_check_realtime("voicemail")) {
11153 if (!context) {
11154 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11155 return CLI_SHOWUSAGE;
11156 }
11157 return show_users_realtime(a->fd, context);
11158 }
11159
11160 AST_LIST_LOCK(&users);
11161 if (AST_LIST_EMPTY(&users)) {
11162 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11163 AST_LIST_UNLOCK(&users);
11164 return CLI_FAILURE;
11165 }
11166 if (a->argc == 3)
11167 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11168 else {
11169 int count = 0;
11170 AST_LIST_TRAVERSE(&users, vmu, list) {
11171 if (!strcmp(context, vmu->context))
11172 count++;
11173 }
11174 if (count) {
11175 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11176 } else {
11177 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11178 AST_LIST_UNLOCK(&users);
11179 return CLI_FAILURE;
11180 }
11181 }
11182 AST_LIST_TRAVERSE(&users, vmu, list) {
11183 int newmsgs = 0, oldmsgs = 0;
11184 char count[12], tmp[256] = "";
11185
11186 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
11187 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11188 inboxcount(tmp, &newmsgs, &oldmsgs);
11189 snprintf(count, sizeof(count), "%d", newmsgs);
11190 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11191 users_counter++;
11192 }
11193 }
11194 AST_LIST_UNLOCK(&users);
11195 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11196 return CLI_SUCCESS;
11197 }
11198
11199
11200 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11201 {
11202 struct vm_zone *zone;
11203 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11204 char *res = CLI_SUCCESS;
11205
11206 switch (cmd) {
11207 case CLI_INIT:
11208 e->command = "voicemail show zones";
11209 e->usage =
11210 "Usage: voicemail show zones\n"
11211 " Lists zone message formats\n";
11212 return NULL;
11213 case CLI_GENERATE:
11214 return NULL;
11215 }
11216
11217 if (a->argc != 3)
11218 return CLI_SHOWUSAGE;
11219
11220 AST_LIST_LOCK(&zones);
11221 if (!AST_LIST_EMPTY(&zones)) {
11222 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11223 AST_LIST_TRAVERSE(&zones, zone, list) {
11224 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11225 }
11226 } else {
11227 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11228 res = CLI_FAILURE;
11229 }
11230 AST_LIST_UNLOCK(&zones);
11231
11232 return res;
11233 }
11234
11235
11236 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11237 {
11238 switch (cmd) {
11239 case CLI_INIT:
11240 e->command = "voicemail reload";
11241 e->usage =
11242 "Usage: voicemail reload\n"
11243 " Reload voicemail configuration\n";
11244 return NULL;
11245 case CLI_GENERATE:
11246 return NULL;
11247 }
11248
11249 if (a->argc != 2)
11250 return CLI_SHOWUSAGE;
11251
11252 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11253 load_config(1);
11254
11255 return CLI_SUCCESS;
11256 }
11257
11258 static struct ast_cli_entry cli_voicemail[] = {
11259 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11260 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11261 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11262 };
11263
11264 #ifdef IMAP_STORAGE
11265 #define DATA_EXPORT_VM_USERS(USER) \
11266 USER(ast_vm_user, context, AST_DATA_STRING) \
11267 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11268 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11269 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11270 USER(ast_vm_user, email, AST_DATA_STRING) \
11271 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11272 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11273 USER(ast_vm_user, pager, AST_DATA_STRING) \
11274 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11275 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11276 USER(ast_vm_user, language, AST_DATA_STRING) \
11277 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11278 USER(ast_vm_user, callback, AST_DATA_STRING) \
11279 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11280 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11281 USER(ast_vm_user, exit, AST_DATA_STRING) \
11282 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11283 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11284 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11285 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11286 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11287 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11288 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11289 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11290 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11291 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11292 #else
11293 #define DATA_EXPORT_VM_USERS(USER) \
11294 USER(ast_vm_user, context, AST_DATA_STRING) \
11295 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11296 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11297 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11298 USER(ast_vm_user, email, AST_DATA_STRING) \
11299 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11300 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11301 USER(ast_vm_user, pager, AST_DATA_STRING) \
11302 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11303 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11304 USER(ast_vm_user, language, AST_DATA_STRING) \
11305 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11306 USER(ast_vm_user, callback, AST_DATA_STRING) \
11307 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11308 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11309 USER(ast_vm_user, exit, AST_DATA_STRING) \
11310 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11311 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11312 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11313 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11314 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11315 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11316 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11317 #endif
11318
11319 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11320
11321 #define DATA_EXPORT_VM_ZONES(ZONE) \
11322 ZONE(vm_zone, name, AST_DATA_STRING) \
11323 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11324 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11325
11326 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11327
11328
11329
11330
11331
11332
11333
11334
11335 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11336 struct ast_data *data_root, struct ast_vm_user *user)
11337 {
11338 struct ast_data *data_user, *data_zone;
11339 struct ast_data *data_state;
11340 struct vm_zone *zone = NULL;
11341 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11342 char ext_context[256] = "";
11343
11344 data_user = ast_data_add_node(data_root, "user");
11345 if (!data_user) {
11346 return -1;
11347 }
11348
11349 ast_data_add_structure(ast_vm_user, data_user, user);
11350
11351 AST_LIST_LOCK(&zones);
11352 AST_LIST_TRAVERSE(&zones, zone, list) {
11353 if (!strcmp(zone->name, user->zonetag)) {
11354 break;
11355 }
11356 }
11357 AST_LIST_UNLOCK(&zones);
11358
11359
11360 data_state = ast_data_add_node(data_user, "state");
11361 if (!data_state) {
11362 return -1;
11363 }
11364 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11365 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11366 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11367 ast_data_add_int(data_state, "newmsg", newmsg);
11368 ast_data_add_int(data_state, "oldmsg", oldmsg);
11369
11370 if (zone) {
11371 data_zone = ast_data_add_node(data_user, "zone");
11372 ast_data_add_structure(vm_zone, data_zone, zone);
11373 }
11374
11375 if (!ast_data_search_match(search, data_user)) {
11376 ast_data_remove_node(data_root, data_user);
11377 }
11378
11379 return 0;
11380 }
11381
11382 static int vm_users_data_provider_get(const struct ast_data_search *search,
11383 struct ast_data *data_root)
11384 {
11385 struct ast_vm_user *user;
11386
11387 AST_LIST_LOCK(&users);
11388 AST_LIST_TRAVERSE(&users, user, list) {
11389 vm_users_data_provider_get_helper(search, data_root, user);
11390 }
11391 AST_LIST_UNLOCK(&users);
11392
11393 return 0;
11394 }
11395
11396 static const struct ast_data_handler vm_users_data_provider = {
11397 .version = AST_DATA_HANDLER_VERSION,
11398 .get = vm_users_data_provider_get
11399 };
11400
11401 static const struct ast_data_entry vm_data_providers[] = {
11402 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11403 };
11404
11405 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11406 {
11407 int new = 0, old = 0, urgent = 0;
11408
11409 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11410
11411 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11412 mwi_sub->old_urgent = urgent;
11413 mwi_sub->old_new = new;
11414 mwi_sub->old_old = old;
11415 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11416 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11417 }
11418 }
11419
11420 static void poll_subscribed_mailboxes(void)
11421 {
11422 struct mwi_sub *mwi_sub;
11423
11424 AST_RWLIST_RDLOCK(&mwi_subs);
11425 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11426 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11427 poll_subscribed_mailbox(mwi_sub);
11428 }
11429 }
11430 AST_RWLIST_UNLOCK(&mwi_subs);
11431 }
11432
11433 static void *mb_poll_thread(void *data)
11434 {
11435 while (poll_thread_run) {
11436 struct timespec ts = { 0, };
11437 struct timeval wait;
11438
11439 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11440 ts.tv_sec = wait.tv_sec;
11441 ts.tv_nsec = wait.tv_usec * 1000;
11442
11443 ast_mutex_lock(&poll_lock);
11444 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11445 ast_mutex_unlock(&poll_lock);
11446
11447 if (!poll_thread_run)
11448 break;
11449
11450 poll_subscribed_mailboxes();
11451 }
11452
11453 return NULL;
11454 }
11455
11456 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11457 {
11458 ast_free(mwi_sub);
11459 }
11460
11461 static int handle_unsubscribe(void *datap)
11462 {
11463 struct mwi_sub *mwi_sub;
11464 uint32_t *uniqueid = datap;
11465
11466 AST_RWLIST_WRLOCK(&mwi_subs);
11467 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11468 if (mwi_sub->uniqueid == *uniqueid) {
11469 AST_LIST_REMOVE_CURRENT(entry);
11470 break;
11471 }
11472 }
11473 AST_RWLIST_TRAVERSE_SAFE_END
11474 AST_RWLIST_UNLOCK(&mwi_subs);
11475
11476 if (mwi_sub)
11477 mwi_sub_destroy(mwi_sub);
11478
11479 ast_free(uniqueid);
11480 return 0;
11481 }
11482
11483 static int handle_subscribe(void *datap)
11484 {
11485 unsigned int len;
11486 struct mwi_sub *mwi_sub;
11487 struct mwi_sub_task *p = datap;
11488
11489 len = sizeof(*mwi_sub);
11490 if (!ast_strlen_zero(p->mailbox))
11491 len += strlen(p->mailbox);
11492
11493 if (!ast_strlen_zero(p->context))
11494 len += strlen(p->context) + 1;
11495
11496 if (!(mwi_sub = ast_calloc(1, len)))
11497 return -1;
11498
11499 mwi_sub->uniqueid = p->uniqueid;
11500 if (!ast_strlen_zero(p->mailbox))
11501 strcpy(mwi_sub->mailbox, p->mailbox);
11502
11503 if (!ast_strlen_zero(p->context)) {
11504 strcat(mwi_sub->mailbox, "@");
11505 strcat(mwi_sub->mailbox, p->context);
11506 }
11507
11508 AST_RWLIST_WRLOCK(&mwi_subs);
11509 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11510 AST_RWLIST_UNLOCK(&mwi_subs);
11511 ast_free((void *) p->mailbox);
11512 ast_free((void *) p->context);
11513 ast_free(p);
11514 poll_subscribed_mailbox(mwi_sub);
11515 return 0;
11516 }
11517
11518 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11519 {
11520 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11521 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11522 return;
11523
11524 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11525 return;
11526
11527 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11528 *uniqueid = u;
11529 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11530 ast_free(uniqueid);
11531 }
11532 }
11533
11534 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11535 {
11536 struct mwi_sub_task *mwist;
11537
11538 if (ast_event_get_type(event) != AST_EVENT_SUB)
11539 return;
11540
11541 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11542 return;
11543
11544 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11545 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11546 return;
11547 }
11548 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11549 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11550 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11551
11552 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11553 ast_free(mwist);
11554 }
11555 }
11556
11557 static void start_poll_thread(void)
11558 {
11559 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11560 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11561 AST_EVENT_IE_END);
11562
11563 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11564 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11565 AST_EVENT_IE_END);
11566
11567 if (mwi_sub_sub)
11568 ast_event_report_subs(mwi_sub_sub);
11569
11570 poll_thread_run = 1;
11571
11572 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11573 }
11574
11575 static void stop_poll_thread(void)
11576 {
11577 poll_thread_run = 0;
11578
11579 if (mwi_sub_sub) {
11580 ast_event_unsubscribe(mwi_sub_sub);
11581 mwi_sub_sub = NULL;
11582 }
11583
11584 if (mwi_unsub_sub) {
11585 ast_event_unsubscribe(mwi_unsub_sub);
11586 mwi_unsub_sub = NULL;
11587 }
11588
11589 ast_mutex_lock(&poll_lock);
11590 ast_cond_signal(&poll_cond);
11591 ast_mutex_unlock(&poll_lock);
11592
11593 pthread_join(poll_thread, NULL);
11594
11595 poll_thread = AST_PTHREADT_NULL;
11596 }
11597
11598
11599 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11600 {
11601 struct ast_vm_user *vmu = NULL;
11602 const char *id = astman_get_header(m, "ActionID");
11603 char actionid[128] = "";
11604
11605 if (!ast_strlen_zero(id))
11606 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11607
11608 AST_LIST_LOCK(&users);
11609
11610 if (AST_LIST_EMPTY(&users)) {
11611 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11612 AST_LIST_UNLOCK(&users);
11613 return RESULT_SUCCESS;
11614 }
11615
11616 astman_send_ack(s, m, "Voicemail user list will follow");
11617
11618 AST_LIST_TRAVERSE(&users, vmu, list) {
11619 char dirname[256];
11620
11621 #ifdef IMAP_STORAGE
11622 int new, old;
11623 inboxcount(vmu->mailbox, &new, &old);
11624 #endif
11625
11626 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11627 astman_append(s,
11628 "%s"
11629 "Event: VoicemailUserEntry\r\n"
11630 "VMContext: %s\r\n"
11631 "VoiceMailbox: %s\r\n"
11632 "Fullname: %s\r\n"
11633 "Email: %s\r\n"
11634 "Pager: %s\r\n"
11635 "ServerEmail: %s\r\n"
11636 "MailCommand: %s\r\n"
11637 "Language: %s\r\n"
11638 "TimeZone: %s\r\n"
11639 "Callback: %s\r\n"
11640 "Dialout: %s\r\n"
11641 "UniqueID: %s\r\n"
11642 "ExitContext: %s\r\n"
11643 "SayDurationMinimum: %d\r\n"
11644 "SayEnvelope: %s\r\n"
11645 "SayCID: %s\r\n"
11646 "AttachMessage: %s\r\n"
11647 "AttachmentFormat: %s\r\n"
11648 "DeleteMessage: %s\r\n"
11649 "VolumeGain: %.2f\r\n"
11650 "CanReview: %s\r\n"
11651 "CallOperator: %s\r\n"
11652 "MaxMessageCount: %d\r\n"
11653 "MaxMessageLength: %d\r\n"
11654 "NewMessageCount: %d\r\n"
11655 #ifdef IMAP_STORAGE
11656 "OldMessageCount: %d\r\n"
11657 "IMAPUser: %s\r\n"
11658 #endif
11659 "\r\n",
11660 actionid,
11661 vmu->context,
11662 vmu->mailbox,
11663 vmu->fullname,
11664 vmu->email,
11665 vmu->pager,
11666 vmu->serveremail,
11667 vmu->mailcmd,
11668 vmu->language,
11669 vmu->zonetag,
11670 vmu->callback,
11671 vmu->dialout,
11672 vmu->uniqueid,
11673 vmu->exit,
11674 vmu->saydurationm,
11675 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11676 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11677 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11678 vmu->attachfmt,
11679 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11680 vmu->volgain,
11681 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11682 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11683 vmu->maxmsg,
11684 vmu->maxsecs,
11685 #ifdef IMAP_STORAGE
11686 new, old, vmu->imapuser
11687 #else
11688 count_messages(vmu, dirname)
11689 #endif
11690 );
11691 }
11692 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11693
11694 AST_LIST_UNLOCK(&users);
11695
11696 return RESULT_SUCCESS;
11697 }
11698
11699
11700 static void free_vm_users(void)
11701 {
11702 struct ast_vm_user *current;
11703 AST_LIST_LOCK(&users);
11704 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11705 ast_set_flag(current, VM_ALLOCED);
11706 free_user(current);
11707 }
11708 AST_LIST_UNLOCK(&users);
11709 }
11710
11711
11712 static void free_vm_zones(void)
11713 {
11714 struct vm_zone *zcur;
11715 AST_LIST_LOCK(&zones);
11716 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11717 free_zone(zcur);
11718 AST_LIST_UNLOCK(&zones);
11719 }
11720
11721 static const char *substitute_escapes(const char *value)
11722 {
11723 char *current;
11724
11725
11726 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11727
11728 ast_str_reset(str);
11729
11730
11731 for (current = (char *) value; *current; current++) {
11732 if (*current == '\\') {
11733 current++;
11734 if (!*current) {
11735 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11736 break;
11737 }
11738 switch (*current) {
11739 case '\\':
11740 ast_str_append(&str, 0, "\\");
11741 break;
11742 case 'r':
11743 ast_str_append(&str, 0, "\r");
11744 break;
11745 case 'n':
11746 #ifdef IMAP_STORAGE
11747 if (!str->used || str->str[str->used - 1] != '\r') {
11748 ast_str_append(&str, 0, "\r");
11749 }
11750 #endif
11751 ast_str_append(&str, 0, "\n");
11752 break;
11753 case 't':
11754 ast_str_append(&str, 0, "\t");
11755 break;
11756 default:
11757 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11758 break;
11759 }
11760 } else {
11761 ast_str_append(&str, 0, "%c", *current);
11762 }
11763 }
11764
11765 return ast_str_buffer(str);
11766 }
11767
11768 static int load_config(int reload)
11769 {
11770 struct ast_vm_user *current;
11771 struct ast_config *cfg, *ucfg;
11772 char *cat;
11773 struct ast_variable *var;
11774 const char *val;
11775 char *q, *stringp, *tmp;
11776 int x;
11777 int tmpadsi[4];
11778 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11779 char secretfn[PATH_MAX] = "";
11780
11781 ast_unload_realtime("voicemail");
11782 ast_unload_realtime("voicemail_data");
11783
11784 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11785 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11786 return 0;
11787 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11788 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11789 ucfg = NULL;
11790 }
11791 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11792 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11793 ast_config_destroy(ucfg);
11794 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11795 return 0;
11796 }
11797 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11798 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11799 return 0;
11800 } else {
11801 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11802 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11803 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11804 ucfg = NULL;
11805 }
11806 }
11807 #ifdef IMAP_STORAGE
11808 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11809 #endif
11810
11811 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11812 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11813 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11814 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11815 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11816
11817
11818 free_vm_users();
11819
11820
11821 free_vm_zones();
11822
11823 AST_LIST_LOCK(&users);
11824
11825 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11826 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11827
11828 if (cfg) {
11829
11830
11831 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11832 val = "default";
11833 ast_copy_string(userscontext, val, sizeof(userscontext));
11834
11835 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11836 val = "yes";
11837 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11838
11839 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11840 val = "no";
11841 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11842
11843 volgain = 0.0;
11844 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11845 sscanf(val, "%30lf", &volgain);
11846
11847 #ifdef ODBC_STORAGE
11848 strcpy(odbc_database, "asterisk");
11849 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11850 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11851 }
11852 strcpy(odbc_table, "voicemessages");
11853 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11854 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11855 }
11856 #endif
11857
11858 strcpy(mailcmd, SENDMAIL);
11859 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11860 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11861
11862 maxsilence = 0;
11863 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11864 maxsilence = atoi(val);
11865 if (maxsilence > 0)
11866 maxsilence *= 1000;
11867 }
11868
11869 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11870 maxmsg = MAXMSG;
11871 } else {
11872 maxmsg = atoi(val);
11873 if (maxmsg < 0) {
11874 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11875 maxmsg = MAXMSG;
11876 } else if (maxmsg > MAXMSGLIMIT) {
11877 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11878 maxmsg = MAXMSGLIMIT;
11879 }
11880 }
11881
11882 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11883 maxdeletedmsg = 0;
11884 } else {
11885 if (sscanf(val, "%30d", &x) == 1)
11886 maxdeletedmsg = x;
11887 else if (ast_true(val))
11888 maxdeletedmsg = MAXMSG;
11889 else
11890 maxdeletedmsg = 0;
11891
11892 if (maxdeletedmsg < 0) {
11893 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11894 maxdeletedmsg = MAXMSG;
11895 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11896 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11897 maxdeletedmsg = MAXMSGLIMIT;
11898 }
11899 }
11900
11901
11902 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11903 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11904 }
11905
11906
11907 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11908 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11909 }
11910
11911
11912 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11913 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11914 pwdchange = PWDCHANGE_EXTERNAL;
11915 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11916 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11917 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11918 }
11919
11920
11921 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11922 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11923 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11924 }
11925
11926 #ifdef IMAP_STORAGE
11927
11928 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11929 ast_copy_string(imapserver, val, sizeof(imapserver));
11930 } else {
11931 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11932 }
11933
11934 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11935 ast_copy_string(imapport, val, sizeof(imapport));
11936 } else {
11937 ast_copy_string(imapport, "143", sizeof(imapport));
11938 }
11939
11940 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11941 ast_copy_string(imapflags, val, sizeof(imapflags));
11942 }
11943
11944 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11945 ast_copy_string(authuser, val, sizeof(authuser));
11946 }
11947
11948 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11949 ast_copy_string(authpassword, val, sizeof(authpassword));
11950 }
11951
11952 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11953 if (ast_false(val))
11954 expungeonhangup = 0;
11955 else
11956 expungeonhangup = 1;
11957 } else {
11958 expungeonhangup = 1;
11959 }
11960
11961 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11962 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11963 } else {
11964 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11965 }
11966 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11967 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11968 }
11969 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11970 imapgreetings = ast_true(val);
11971 } else {
11972 imapgreetings = 0;
11973 }
11974 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11975 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11976 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
11977
11978 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11979 } else {
11980 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
11981 }
11982
11983
11984
11985
11986
11987 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
11988 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
11989 } else {
11990 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
11991 }
11992
11993 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
11994 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
11995 } else {
11996 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
11997 }
11998
11999 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12000 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12001 } else {
12002 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12003 }
12004
12005 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12006 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12007 } else {
12008 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12009 }
12010
12011
12012 imapversion++;
12013 #endif
12014
12015 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12016 ast_copy_string(externnotify, val, sizeof(externnotify));
12017 ast_debug(1, "found externnotify: %s\n", externnotify);
12018 } else {
12019 externnotify[0] = '\0';
12020 }
12021
12022
12023 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12024 ast_debug(1, "Enabled SMDI voicemail notification\n");
12025 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12026 smdi_iface = ast_smdi_interface_find(val);
12027 } else {
12028 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12029 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12030 }
12031 if (!smdi_iface) {
12032 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12033 }
12034 }
12035
12036
12037 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12038 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12039 silencethreshold = atoi(val);
12040
12041 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12042 val = ASTERISK_USERNAME;
12043 ast_copy_string(serveremail, val, sizeof(serveremail));
12044
12045 vmmaxsecs = 0;
12046 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12047 if (sscanf(val, "%30d", &x) == 1) {
12048 vmmaxsecs = x;
12049 } else {
12050 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12051 }
12052 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12053 static int maxmessage_deprecate = 0;
12054 if (maxmessage_deprecate == 0) {
12055 maxmessage_deprecate = 1;
12056 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12057 }
12058 if (sscanf(val, "%30d", &x) == 1) {
12059 vmmaxsecs = x;
12060 } else {
12061 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12062 }
12063 }
12064
12065 vmminsecs = 0;
12066 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12067 if (sscanf(val, "%30d", &x) == 1) {
12068 vmminsecs = x;
12069 if (maxsilence / 1000 >= vmminsecs) {
12070 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12071 }
12072 } else {
12073 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12074 }
12075 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12076 static int maxmessage_deprecate = 0;
12077 if (maxmessage_deprecate == 0) {
12078 maxmessage_deprecate = 1;
12079 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12080 }
12081 if (sscanf(val, "%30d", &x) == 1) {
12082 vmminsecs = x;
12083 if (maxsilence / 1000 >= vmminsecs) {
12084 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12085 }
12086 } else {
12087 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12088 }
12089 }
12090
12091 val = ast_variable_retrieve(cfg, "general", "format");
12092 if (!val) {
12093 val = "wav";
12094 } else {
12095 tmp = ast_strdupa(val);
12096 val = ast_format_str_reduce(tmp);
12097 if (!val) {
12098 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12099 val = "wav";
12100 }
12101 }
12102 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12103
12104 skipms = 3000;
12105 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12106 if (sscanf(val, "%30d", &x) == 1) {
12107 maxgreet = x;
12108 } else {
12109 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12110 }
12111 }
12112
12113 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12114 if (sscanf(val, "%30d", &x) == 1) {
12115 skipms = x;
12116 } else {
12117 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12118 }
12119 }
12120
12121 maxlogins = 3;
12122 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12123 if (sscanf(val, "%30d", &x) == 1) {
12124 maxlogins = x;
12125 } else {
12126 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12127 }
12128 }
12129
12130 minpassword = MINPASSWORD;
12131 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12132 if (sscanf(val, "%30d", &x) == 1) {
12133 minpassword = x;
12134 } else {
12135 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12136 }
12137 }
12138
12139
12140 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12141 val = "no";
12142 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12143
12144
12145 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12146 val = "no";
12147 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12148
12149 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12150 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12151 stringp = ast_strdupa(val);
12152 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12153 if (!ast_strlen_zero(stringp)) {
12154 q = strsep(&stringp, ",");
12155 while ((*q == ' ')||(*q == '\t'))
12156 q++;
12157 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12158 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12159 } else {
12160 cidinternalcontexts[x][0] = '\0';
12161 }
12162 }
12163 }
12164 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12165 ast_debug(1, "VM Review Option disabled globally\n");
12166 val = "no";
12167 }
12168 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12169
12170
12171 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12172 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12173 val = "no";
12174 } else {
12175 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12176 }
12177 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12178 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12179 ast_debug(1, "VM next message wrap disabled globally\n");
12180 val = "no";
12181 }
12182 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12183
12184 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12185 ast_debug(1, "VM Operator break disabled globally\n");
12186 val = "no";
12187 }
12188 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12189
12190 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12191 ast_debug(1, "VM CID Info before msg disabled globally\n");
12192 val = "no";
12193 }
12194 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12195
12196 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12197 ast_debug(1, "Send Voicemail msg disabled globally\n");
12198 val = "no";
12199 }
12200 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12201
12202 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12203 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12204 val = "yes";
12205 }
12206 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12207
12208 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12209 ast_debug(1, "Move Heard enabled globally\n");
12210 val = "yes";
12211 }
12212 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12213
12214 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12215 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12216 val = "no";
12217 }
12218 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12219
12220 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12221 ast_debug(1, "Duration info before msg enabled globally\n");
12222 val = "yes";
12223 }
12224 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12225
12226 saydurationminfo = 2;
12227 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12228 if (sscanf(val, "%30d", &x) == 1) {
12229 saydurationminfo = x;
12230 } else {
12231 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12232 }
12233 }
12234
12235 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12236 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12237 val = "no";
12238 }
12239 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12240
12241 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12242 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12243 ast_debug(1, "found dialout context: %s\n", dialcontext);
12244 } else {
12245 dialcontext[0] = '\0';
12246 }
12247
12248 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12249 ast_copy_string(callcontext, val, sizeof(callcontext));
12250 ast_debug(1, "found callback context: %s\n", callcontext);
12251 } else {
12252 callcontext[0] = '\0';
12253 }
12254
12255 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12256 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12257 ast_debug(1, "found operator context: %s\n", exitcontext);
12258 } else {
12259 exitcontext[0] = '\0';
12260 }
12261
12262
12263 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12264 ast_copy_string(vm_password, val, sizeof(vm_password));
12265 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12266 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12267 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12268 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12269 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12270 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12271 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12272 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12273 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12274 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12275 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12276 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12277 }
12278 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12279 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12280 }
12281
12282 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12283 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12284 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12285 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12286 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12287 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12288 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12289 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12290 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12291 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12292
12293 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12294 val = "no";
12295 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12296
12297 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12298 val = "voicemail.conf";
12299 }
12300 if (!(strcmp(val, "spooldir"))) {
12301 passwordlocation = OPT_PWLOC_SPOOLDIR;
12302 } else {
12303 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12304 }
12305
12306 poll_freq = DEFAULT_POLL_FREQ;
12307 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12308 if (sscanf(val, "%30u", &poll_freq) != 1) {
12309 poll_freq = DEFAULT_POLL_FREQ;
12310 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12311 }
12312 }
12313
12314 poll_mailboxes = 0;
12315 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12316 poll_mailboxes = ast_true(val);
12317
12318 if (ucfg) {
12319 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12320 if (!strcasecmp(cat, "general")) {
12321 continue;
12322 }
12323 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12324 continue;
12325 if ((current = find_or_create(userscontext, cat))) {
12326 populate_defaults(current);
12327 apply_options_full(current, ast_variable_browse(ucfg, cat));
12328 ast_copy_string(current->context, userscontext, sizeof(current->context));
12329 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12330 current->passwordlocation = OPT_PWLOC_USERSCONF;
12331 }
12332
12333 switch (current->passwordlocation) {
12334 case OPT_PWLOC_SPOOLDIR:
12335 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12336 read_password_from_file(secretfn, current->password, sizeof(current->password));
12337 }
12338 }
12339 }
12340 ast_config_destroy(ucfg);
12341 }
12342 cat = ast_category_browse(cfg, NULL);
12343 while (cat) {
12344 if (strcasecmp(cat, "general")) {
12345 var = ast_variable_browse(cfg, cat);
12346 if (strcasecmp(cat, "zonemessages")) {
12347
12348 while (var) {
12349 append_mailbox(cat, var->name, var->value);
12350 var = var->next;
12351 }
12352 } else {
12353
12354 while (var) {
12355 struct vm_zone *z;
12356 if ((z = ast_malloc(sizeof(*z)))) {
12357 char *msg_format, *tzone;
12358 msg_format = ast_strdupa(var->value);
12359 tzone = strsep(&msg_format, "|,");
12360 if (msg_format) {
12361 ast_copy_string(z->name, var->name, sizeof(z->name));
12362 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12363 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12364 AST_LIST_LOCK(&zones);
12365 AST_LIST_INSERT_HEAD(&zones, z, list);
12366 AST_LIST_UNLOCK(&zones);
12367 } else {
12368 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12369 ast_free(z);
12370 }
12371 } else {
12372 AST_LIST_UNLOCK(&users);
12373 ast_config_destroy(cfg);
12374 return -1;
12375 }
12376 var = var->next;
12377 }
12378 }
12379 }
12380 cat = ast_category_browse(cfg, cat);
12381 }
12382 memset(fromstring, 0, sizeof(fromstring));
12383 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12384 strcpy(charset, "ISO-8859-1");
12385 if (emailbody) {
12386 ast_free(emailbody);
12387 emailbody = NULL;
12388 }
12389 if (emailsubject) {
12390 ast_free(emailsubject);
12391 emailsubject = NULL;
12392 }
12393 if (pagerbody) {
12394 ast_free(pagerbody);
12395 pagerbody = NULL;
12396 }
12397 if (pagersubject) {
12398 ast_free(pagersubject);
12399 pagersubject = NULL;
12400 }
12401 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12402 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12403 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12404 ast_copy_string(fromstring, val, sizeof(fromstring));
12405 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12406 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12407 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12408 ast_copy_string(charset, val, sizeof(charset));
12409 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12410 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12411 for (x = 0; x < 4; x++) {
12412 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12413 }
12414 }
12415 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12416 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12417 for (x = 0; x < 4; x++) {
12418 memcpy(&adsisec[x], &tmpadsi[x], 1);
12419 }
12420 }
12421 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12422 if (atoi(val)) {
12423 adsiver = atoi(val);
12424 }
12425 }
12426 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12427 ast_copy_string(zonetag, val, sizeof(zonetag));
12428 }
12429 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12430 ast_copy_string(locale, val, sizeof(locale));
12431 }
12432 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12433 emailsubject = ast_strdup(substitute_escapes(val));
12434 }
12435 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12436 emailbody = ast_strdup(substitute_escapes(val));
12437 }
12438 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12439 pagersubject = ast_strdup(substitute_escapes(val));
12440 }
12441 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12442 pagerbody = ast_strdup(substitute_escapes(val));
12443 }
12444 AST_LIST_UNLOCK(&users);
12445 ast_config_destroy(cfg);
12446
12447 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12448 start_poll_thread();
12449 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12450 stop_poll_thread();;
12451
12452 return 0;
12453 } else {
12454 AST_LIST_UNLOCK(&users);
12455 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12456 if (ucfg)
12457 ast_config_destroy(ucfg);
12458 return 0;
12459 }
12460 }
12461
12462 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12463 {
12464 int res = -1;
12465 char dir[PATH_MAX];
12466 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12467 ast_debug(2, "About to try retrieving name file %s\n", dir);
12468 RETRIEVE(dir, -1, mailbox, context);
12469 if (ast_fileexists(dir, NULL, NULL)) {
12470 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12471 }
12472 DISPOSE(dir, -1);
12473 return res;
12474 }
12475
12476 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12477 struct ast_config *pwconf;
12478 struct ast_flags config_flags = { 0 };
12479
12480 pwconf = ast_config_load(secretfn, config_flags);
12481 if (pwconf) {
12482 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12483 if (val) {
12484 ast_copy_string(password, val, passwordlen);
12485 return;
12486 }
12487 }
12488 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12489 }
12490
12491 static int write_password_to_file(const char *secretfn, const char *password) {
12492 struct ast_config *conf;
12493 struct ast_category *cat;
12494 struct ast_variable *var;
12495
12496 if (!(conf=ast_config_new())) {
12497 ast_log(LOG_ERROR, "Error creating new config structure\n");
12498 return -1;
12499 }
12500 if (!(cat=ast_category_new("general","",1))) {
12501 ast_log(LOG_ERROR, "Error creating new category structure\n");
12502 return -1;
12503 }
12504 if (!(var=ast_variable_new("password",password,""))) {
12505 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12506 return -1;
12507 }
12508 ast_category_append(conf,cat);
12509 ast_variable_append(cat,var);
12510 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12511 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12512 return -1;
12513 }
12514 return 0;
12515 }
12516
12517 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12518 {
12519 char *context;
12520 char *args_copy;
12521 int res;
12522
12523 if (ast_strlen_zero(data)) {
12524 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12525 return -1;
12526 }
12527
12528 args_copy = ast_strdupa(data);
12529 if ((context = strchr(args_copy, '@'))) {
12530 *context++ = '\0';
12531 } else {
12532 context = "default";
12533 }
12534
12535 if ((res = sayname(chan, args_copy, context) < 0)) {
12536 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12537 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12538 if (!res) {
12539 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12540 }
12541 }
12542
12543 return res;
12544 }
12545
12546 #ifdef TEST_FRAMEWORK
12547 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12548 {
12549 return 0;
12550 }
12551
12552 static struct ast_frame *fake_read(struct ast_channel *ast)
12553 {
12554 return &ast_null_frame;
12555 }
12556
12557 AST_TEST_DEFINE(test_voicemail_vmsayname)
12558 {
12559 char dir[PATH_MAX];
12560 char dir2[PATH_MAX];
12561 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12562 static const char TEST_EXTENSION[] = "1234";
12563
12564 struct ast_channel *test_channel1 = NULL;
12565 int res = -1;
12566
12567 static const struct ast_channel_tech fake_tech = {
12568 .write = fake_write,
12569 .read = fake_read,
12570 };
12571
12572 switch (cmd) {
12573 case TEST_INIT:
12574 info->name = "vmsayname_exec";
12575 info->category = "/apps/app_voicemail/";
12576 info->summary = "Vmsayname unit test";
12577 info->description =
12578 "This tests passing various parameters to vmsayname";
12579 return AST_TEST_NOT_RUN;
12580 case TEST_EXECUTE:
12581 break;
12582 }
12583
12584 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12585 NULL, NULL, 0, 0, "TestChannel1"))) {
12586 goto exit_vmsayname_test;
12587 }
12588
12589
12590 test_channel1->nativeformats = AST_FORMAT_GSM;
12591 test_channel1->writeformat = AST_FORMAT_GSM;
12592 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12593 test_channel1->readformat = AST_FORMAT_GSM;
12594 test_channel1->rawreadformat = AST_FORMAT_GSM;
12595 test_channel1->tech = &fake_tech;
12596
12597 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12598 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12599 if (!(res = vmsayname_exec(test_channel1, dir))) {
12600 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12601 if (ast_fileexists(dir, NULL, NULL)) {
12602 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12603 res = -1;
12604 goto exit_vmsayname_test;
12605 } else {
12606
12607 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12608 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12609 goto exit_vmsayname_test;
12610 }
12611 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12612 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12613
12614 if ((res = symlink(dir, dir2))) {
12615 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12616 goto exit_vmsayname_test;
12617 }
12618 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12619 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12620 res = vmsayname_exec(test_channel1, dir);
12621
12622
12623 unlink(dir2);
12624 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12625 rmdir(dir2);
12626 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12627 rmdir(dir2);
12628 }
12629 }
12630
12631 exit_vmsayname_test:
12632
12633 if (test_channel1) {
12634 ast_hangup(test_channel1);
12635 }
12636
12637 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12638 }
12639
12640 AST_TEST_DEFINE(test_voicemail_msgcount)
12641 {
12642 int i, j, res = AST_TEST_PASS, syserr;
12643 struct ast_vm_user *vmu;
12644 struct vm_state vms;
12645 #ifdef IMAP_STORAGE
12646 struct ast_channel *chan = NULL;
12647 #endif
12648 struct {
12649 char dir[256];
12650 char file[256];
12651 char txtfile[256];
12652 } tmp[3];
12653 char syscmd[256];
12654 const char origweasels[] = "tt-weasels";
12655 const char testcontext[] = "test";
12656 const char testmailbox[] = "00000000";
12657 const char testspec[] = "00000000@test";
12658 FILE *txt;
12659 int new, old, urgent;
12660 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12661 const int folder2mbox[3] = { 1, 11, 0 };
12662 const int expected_results[3][12] = {
12663
12664 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12665 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12666 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12667 };
12668
12669 switch (cmd) {
12670 case TEST_INIT:
12671 info->name = "test_voicemail_msgcount";
12672 info->category = "/apps/app_voicemail/";
12673 info->summary = "Test Voicemail status checks";
12674 info->description =
12675 "Verify that message counts are correct when retrieved through the public API";
12676 return AST_TEST_NOT_RUN;
12677 case TEST_EXECUTE:
12678 break;
12679 }
12680
12681
12682 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12683 if ((syserr = ast_safe_system(syscmd))) {
12684 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12685 syserr > 0 ? strerror(syserr) : "unable to fork()");
12686 return AST_TEST_FAIL;
12687 }
12688
12689 #ifdef IMAP_STORAGE
12690 if (!(chan = ast_dummy_channel_alloc())) {
12691 ast_test_status_update(test, "Unable to create dummy channel\n");
12692 return AST_TEST_FAIL;
12693 }
12694 #endif
12695
12696 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12697 !(vmu = find_or_create(testcontext, testmailbox))) {
12698 ast_test_status_update(test, "Cannot create vmu structure\n");
12699 ast_unreplace_sigchld();
12700 return AST_TEST_FAIL;
12701 }
12702
12703 populate_defaults(vmu);
12704 memset(&vms, 0, sizeof(vms));
12705
12706
12707 for (i = 0; i < 3; i++) {
12708 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12709 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12710 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12711
12712 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12713 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12714 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12715 if ((syserr = ast_safe_system(syscmd))) {
12716 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12717 syserr > 0 ? strerror(syserr) : "unable to fork()");
12718 ast_unreplace_sigchld();
12719 return AST_TEST_FAIL;
12720 }
12721 }
12722
12723 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12724 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12725 fclose(txt);
12726 } else {
12727 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12728 res = AST_TEST_FAIL;
12729 break;
12730 }
12731 open_mailbox(&vms, vmu, folder2mbox[i]);
12732 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12733
12734
12735 for (j = 0; j < 3; j++) {
12736
12737 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12738 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12739 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12740 res = AST_TEST_FAIL;
12741 }
12742 }
12743
12744 new = old = urgent = 0;
12745 if (ast_app_inboxcount(testspec, &new, &old)) {
12746 ast_test_status_update(test, "inboxcount returned failure\n");
12747 res = AST_TEST_FAIL;
12748 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12749 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12750 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12751 res = AST_TEST_FAIL;
12752 }
12753
12754 new = old = urgent = 0;
12755 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12756 ast_test_status_update(test, "inboxcount2 returned failure\n");
12757 res = AST_TEST_FAIL;
12758 } else if (old != expected_results[i][6 + 0] ||
12759 urgent != expected_results[i][6 + 1] ||
12760 new != expected_results[i][6 + 2] ) {
12761 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12762 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12763 res = AST_TEST_FAIL;
12764 }
12765
12766 new = old = urgent = 0;
12767 for (j = 0; j < 3; j++) {
12768 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12769 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12770 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12771 res = AST_TEST_FAIL;
12772 }
12773 }
12774 }
12775
12776 for (i = 0; i < 3; i++) {
12777
12778
12779
12780 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12781 DISPOSE(tmp[i].dir, 0);
12782 }
12783
12784 if (vms.deleted) {
12785 ast_free(vms.deleted);
12786 }
12787 if (vms.heard) {
12788 ast_free(vms.heard);
12789 }
12790
12791 #ifdef IMAP_STORAGE
12792 chan = ast_channel_release(chan);
12793 #endif
12794
12795
12796 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12797 if ((syserr = ast_safe_system(syscmd))) {
12798 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12799 syserr > 0 ? strerror(syserr) : "unable to fork()");
12800 }
12801
12802 return res;
12803 }
12804
12805 AST_TEST_DEFINE(test_voicemail_notify_endl)
12806 {
12807 int res = AST_TEST_PASS;
12808 char testcontext[] = "test";
12809 char testmailbox[] = "00000000";
12810 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12811 char attach[256], attach2[256];
12812 char buf[256] = "";
12813 struct ast_channel *chan = NULL;
12814 struct ast_vm_user *vmu, vmus = {
12815 .flags = 0,
12816 };
12817 FILE *file;
12818 struct {
12819 char *name;
12820 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12821 void *location;
12822 union {
12823 int intval;
12824 char *strval;
12825 } u;
12826 } test_items[] = {
12827 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12828 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12829 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12830 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12831 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12832 { "attach2", STRPTR, attach2, .u.strval = "" },
12833 { "attach", STRPTR, attach, .u.strval = "" },
12834 };
12835 int which;
12836
12837 switch (cmd) {
12838 case TEST_INIT:
12839 info->name = "test_voicemail_notify_endl";
12840 info->category = "/apps/app_voicemail/";
12841 info->summary = "Test Voicemail notification end-of-line";
12842 info->description =
12843 "Verify that notification emails use a consistent end-of-line character";
12844 return AST_TEST_NOT_RUN;
12845 case TEST_EXECUTE:
12846 break;
12847 }
12848
12849 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12850 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12851
12852 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12853 !(vmu = find_or_create(testcontext, testmailbox))) {
12854 ast_test_status_update(test, "Cannot create vmu structure\n");
12855 return AST_TEST_NOT_RUN;
12856 }
12857
12858 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12859 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12860 return AST_TEST_NOT_RUN;
12861 }
12862
12863 populate_defaults(vmu);
12864 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12865 #ifdef IMAP_STORAGE
12866
12867 #endif
12868
12869 file = tmpfile();
12870 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12871
12872 rewind(file);
12873 if (ftruncate(fileno(file), 0)) {
12874 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12875 res = AST_TEST_FAIL;
12876 break;
12877 }
12878
12879
12880 if (test_items[which].type == INT) {
12881 *((int *) test_items[which].location) = test_items[which].u.intval;
12882 } else if (test_items[which].type == FLAGVAL) {
12883 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12884 ast_clear_flag(vmu, test_items[which].u.intval);
12885 } else {
12886 ast_set_flag(vmu, test_items[which].u.intval);
12887 }
12888 } else if (test_items[which].type == STATIC) {
12889 strcpy(test_items[which].location, test_items[which].u.strval);
12890 } else if (test_items[which].type == STRPTR) {
12891 test_items[which].location = test_items[which].u.strval;
12892 }
12893
12894 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12895 rewind(file);
12896 while (fgets(buf, sizeof(buf), file)) {
12897 if (
12898 #ifdef IMAP_STORAGE
12899 buf[strlen(buf) - 2] != '\r'
12900 #else
12901 buf[strlen(buf) - 2] == '\r'
12902 #endif
12903 || buf[strlen(buf) - 1] != '\n') {
12904 res = AST_TEST_FAIL;
12905 }
12906 }
12907 }
12908 fclose(file);
12909 return res;
12910 }
12911 #endif
12912
12913 static int reload(void)
12914 {
12915 return load_config(1);
12916 }
12917
12918 static int unload_module(void)
12919 {
12920 int res;
12921
12922 res = ast_unregister_application(app);
12923 res |= ast_unregister_application(app2);
12924 res |= ast_unregister_application(app3);
12925 res |= ast_unregister_application(app4);
12926 res |= ast_unregister_application(sayname_app);
12927 res |= ast_custom_function_unregister(&mailbox_exists_acf);
12928 res |= ast_manager_unregister("VoicemailUsersList");
12929 res |= ast_data_unregister(NULL);
12930 #ifdef TEST_FRAMEWORK
12931 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
12932 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
12933 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
12934 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
12935 #endif
12936 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12937 ast_uninstall_vm_functions();
12938 ao2_ref(inprocess_container, -1);
12939
12940 if (poll_thread != AST_PTHREADT_NULL)
12941 stop_poll_thread();
12942
12943 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
12944 ast_unload_realtime("voicemail");
12945 ast_unload_realtime("voicemail_data");
12946
12947 free_vm_users();
12948 free_vm_zones();
12949 return res;
12950 }
12951
12952 static int load_module(void)
12953 {
12954 int res;
12955 my_umask = umask(0);
12956 umask(my_umask);
12957
12958 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
12959 return AST_MODULE_LOAD_DECLINE;
12960 }
12961
12962
12963 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
12964
12965 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
12966 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
12967 }
12968
12969 if ((res = load_config(0)))
12970 return res;
12971
12972 res = ast_register_application_xml(app, vm_exec);
12973 res |= ast_register_application_xml(app2, vm_execmain);
12974 res |= ast_register_application_xml(app3, vm_box_exists);
12975 res |= ast_register_application_xml(app4, vmauthenticate);
12976 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
12977 res |= ast_custom_function_register(&mailbox_exists_acf);
12978 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
12979 #ifdef TEST_FRAMEWORK
12980 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
12981 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
12982 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
12983 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
12984 #endif
12985
12986 if (res)
12987 return res;
12988
12989 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12990 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
12991
12992 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
12993 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
12994 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
12995
12996 return res;
12997 }
12998
12999 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13000 {
13001 int cmd = 0;
13002 char destination[80] = "";
13003 int retries = 0;
13004
13005 if (!num) {
13006 ast_verb(3, "Destination number will be entered manually\n");
13007 while (retries < 3 && cmd != 't') {
13008 destination[1] = '\0';
13009 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13010 if (!cmd)
13011 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13012 if (!cmd)
13013 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13014 if (!cmd) {
13015 cmd = ast_waitfordigit(chan, 6000);
13016 if (cmd)
13017 destination[0] = cmd;
13018 }
13019 if (!cmd) {
13020 retries++;
13021 } else {
13022
13023 if (cmd < 0)
13024 return 0;
13025 if (cmd == '*') {
13026 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13027 return 0;
13028 }
13029 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13030 retries++;
13031 else
13032 cmd = 't';
13033 }
13034 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13035 }
13036 if (retries >= 3) {
13037 return 0;
13038 }
13039
13040 } else {
13041 if (option_verbose > 2)
13042 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13043 ast_copy_string(destination, num, sizeof(destination));
13044 }
13045
13046 if (!ast_strlen_zero(destination)) {
13047 if (destination[strlen(destination) -1 ] == '*')
13048 return 0;
13049 if (option_verbose > 2)
13050 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13051 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13052 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13053 chan->priority = 0;
13054 return 9;
13055 }
13056 return 0;
13057 }
13058
13059
13060
13061
13062
13063
13064
13065
13066
13067
13068
13069
13070
13071
13072 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)
13073 {
13074 int res = 0;
13075 char filename[PATH_MAX];
13076 struct ast_config *msg_cfg = NULL;
13077 const char *origtime, *context;
13078 char *name, *num;
13079 int retries = 0;
13080 char *cid;
13081 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13082
13083 vms->starting = 0;
13084
13085 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13086
13087
13088 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13089 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13090 msg_cfg = ast_config_load(filename, config_flags);
13091 DISPOSE(vms->curdir, vms->curmsg);
13092 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13093 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13094 return 0;
13095 }
13096
13097 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13098 ast_config_destroy(msg_cfg);
13099 return 0;
13100 }
13101
13102 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13103
13104 context = ast_variable_retrieve(msg_cfg, "message", "context");
13105 if (!strncasecmp("macro", context, 5))
13106 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13107 switch (option) {
13108 case 3:
13109 if (!res)
13110 res = play_message_datetime(chan, vmu, origtime, filename);
13111 if (!res)
13112 res = play_message_callerid(chan, vms, cid, context, 0);
13113
13114 res = 't';
13115 break;
13116
13117 case 2:
13118
13119 if (ast_strlen_zero(cid))
13120 break;
13121
13122 ast_callerid_parse(cid, &name, &num);
13123 while ((res > -1) && (res != 't')) {
13124 switch (res) {
13125 case '1':
13126 if (num) {
13127
13128 res = dialout(chan, vmu, num, vmu->callback);
13129 if (res) {
13130 ast_config_destroy(msg_cfg);
13131 return 9;
13132 }
13133 } else {
13134 res = '2';
13135 }
13136 break;
13137
13138 case '2':
13139
13140 if (!ast_strlen_zero(vmu->dialout)) {
13141 res = dialout(chan, vmu, NULL, vmu->dialout);
13142 if (res) {
13143 ast_config_destroy(msg_cfg);
13144 return 9;
13145 }
13146 } else {
13147 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13148 res = ast_play_and_wait(chan, "vm-sorry");
13149 }
13150 ast_config_destroy(msg_cfg);
13151 return res;
13152 case '*':
13153 res = 't';
13154 break;
13155 case '3':
13156 case '4':
13157 case '5':
13158 case '6':
13159 case '7':
13160 case '8':
13161 case '9':
13162 case '0':
13163
13164 res = ast_play_and_wait(chan, "vm-sorry");
13165 retries++;
13166 break;
13167 default:
13168 if (num) {
13169 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13170 res = ast_play_and_wait(chan, "vm-num-i-have");
13171 if (!res)
13172 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13173 if (!res)
13174 res = ast_play_and_wait(chan, "vm-tocallnum");
13175
13176 if (!ast_strlen_zero(vmu->dialout)) {
13177 if (!res)
13178 res = ast_play_and_wait(chan, "vm-calldiffnum");
13179 }
13180 } else {
13181 res = ast_play_and_wait(chan, "vm-nonumber");
13182 if (!ast_strlen_zero(vmu->dialout)) {
13183 if (!res)
13184 res = ast_play_and_wait(chan, "vm-toenternumber");
13185 }
13186 }
13187 if (!res) {
13188 res = ast_play_and_wait(chan, "vm-star-cancel");
13189 }
13190 if (!res) {
13191 res = ast_waitfordigit(chan, 6000);
13192 }
13193 if (!res) {
13194 retries++;
13195 if (retries > 3) {
13196 res = 't';
13197 }
13198 }
13199 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13200 break;
13201
13202 }
13203 if (res == 't')
13204 res = 0;
13205 else if (res == '*')
13206 res = -1;
13207 }
13208 break;
13209
13210 case 1:
13211
13212 if (ast_strlen_zero(cid))
13213 break;
13214
13215 ast_callerid_parse(cid, &name, &num);
13216 if (!num) {
13217 ast_verb(3, "No CID number available, no reply sent\n");
13218 if (!res)
13219 res = ast_play_and_wait(chan, "vm-nonumber");
13220 ast_config_destroy(msg_cfg);
13221 return res;
13222 } else {
13223 struct ast_vm_user vmu2;
13224 if (find_user(&vmu2, vmu->context, num)) {
13225 struct leave_vm_options leave_options;
13226 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13227 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13228
13229 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13230
13231 memset(&leave_options, 0, sizeof(leave_options));
13232 leave_options.record_gain = record_gain;
13233 res = leave_voicemail(chan, mailbox, &leave_options);
13234 if (!res)
13235 res = 't';
13236 ast_config_destroy(msg_cfg);
13237 return res;
13238 } else {
13239
13240 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13241 ast_play_and_wait(chan, "vm-nobox");
13242 res = 't';
13243 ast_config_destroy(msg_cfg);
13244 return res;
13245 }
13246 }
13247 res = 0;
13248
13249 break;
13250 }
13251
13252 #ifndef IMAP_STORAGE
13253 ast_config_destroy(msg_cfg);
13254
13255 if (!res) {
13256 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13257 vms->heard[msg] = 1;
13258 res = wait_file(chan, vms, vms->fn);
13259 }
13260 #endif
13261 return res;
13262 }
13263
13264 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13265 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
13266 signed char record_gain, struct vm_state *vms, char *flag)
13267 {
13268
13269 int res = 0;
13270 int cmd = 0;
13271 int max_attempts = 3;
13272 int attempts = 0;
13273 int recorded = 0;
13274 int msg_exists = 0;
13275 signed char zero_gain = 0;
13276 char tempfile[PATH_MAX];
13277 char *acceptdtmf = "#";
13278 char *canceldtmf = "";
13279 int canceleddtmf = 0;
13280
13281
13282
13283
13284 if (duration == NULL) {
13285 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13286 return -1;
13287 }
13288
13289 if (!outsidecaller)
13290 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13291 else
13292 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13293
13294 cmd = '3';
13295
13296 while ((cmd >= 0) && (cmd != 't')) {
13297 switch (cmd) {
13298 case '1':
13299 if (!msg_exists) {
13300
13301 cmd = '3';
13302 break;
13303 } else {
13304
13305 ast_verb(3, "Saving message as is\n");
13306 if (!outsidecaller)
13307 ast_filerename(tempfile, recordfile, NULL);
13308 ast_stream_and_wait(chan, "vm-msgsaved", "");
13309 if (!outsidecaller) {
13310
13311 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13312 DISPOSE(recordfile, -1);
13313 }
13314 cmd = 't';
13315 return res;
13316 }
13317 case '2':
13318
13319 ast_verb(3, "Reviewing the message\n");
13320 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13321 break;
13322 case '3':
13323 msg_exists = 0;
13324
13325 if (recorded == 1)
13326 ast_verb(3, "Re-recording the message\n");
13327 else
13328 ast_verb(3, "Recording the message\n");
13329
13330 if (recorded && outsidecaller) {
13331 cmd = ast_play_and_wait(chan, INTRO);
13332 cmd = ast_play_and_wait(chan, "beep");
13333 }
13334 recorded = 1;
13335
13336 if (record_gain)
13337 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13338 if (ast_test_flag(vmu, VM_OPERATOR))
13339 canceldtmf = "0";
13340 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13341 if (strchr(canceldtmf, cmd)) {
13342
13343 canceleddtmf = 1;
13344 }
13345 if (record_gain)
13346 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13347 if (cmd == -1) {
13348
13349 if (!outsidecaller) {
13350
13351 ast_filedelete(tempfile, NULL);
13352 }
13353 return cmd;
13354 }
13355 if (cmd == '0') {
13356 break;
13357 } else if (cmd == '*') {
13358 break;
13359 #if 0
13360 } else if (vmu->review && (*duration < 5)) {
13361
13362 ast_verb(3, "Message too short\n");
13363 cmd = ast_play_and_wait(chan, "vm-tooshort");
13364 cmd = ast_filedelete(tempfile, NULL);
13365 break;
13366 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
13367
13368 ast_verb(3, "Nothing recorded\n");
13369 cmd = ast_filedelete(tempfile, NULL);
13370 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13371 if (!cmd)
13372 cmd = ast_play_and_wait(chan, "vm-speakup");
13373 break;
13374 #endif
13375 } else {
13376
13377 msg_exists = 1;
13378 cmd = 0;
13379 }
13380 break;
13381 case '4':
13382 if (outsidecaller) {
13383
13384 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13385 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13386 res = ast_play_and_wait(chan, "vm-marked-urgent");
13387 strcpy(flag, "Urgent");
13388 } else if (flag) {
13389 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13390 res = ast_play_and_wait(chan, "vm-urgent-removed");
13391 strcpy(flag, "");
13392 } else {
13393 ast_play_and_wait(chan, "vm-sorry");
13394 }
13395 cmd = 0;
13396 } else {
13397 cmd = ast_play_and_wait(chan, "vm-sorry");
13398 }
13399 break;
13400 case '5':
13401 case '6':
13402 case '7':
13403 case '8':
13404 case '9':
13405 case '*':
13406 case '#':
13407 cmd = ast_play_and_wait(chan, "vm-sorry");
13408 break;
13409 #if 0
13410
13411
13412 case '*':
13413
13414 cmd = ast_play_and_wait(chan, "vm-deleted");
13415 cmd = ast_filedelete(tempfile, NULL);
13416 if (outsidecaller) {
13417 res = vm_exec(chan, NULL);
13418 return res;
13419 }
13420 else
13421 return 1;
13422 #endif
13423 case '0':
13424 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13425 cmd = ast_play_and_wait(chan, "vm-sorry");
13426 break;
13427 }
13428 if (msg_exists || recorded) {
13429 cmd = ast_play_and_wait(chan, "vm-saveoper");
13430 if (!cmd)
13431 cmd = ast_waitfordigit(chan, 3000);
13432 if (cmd == '1') {
13433 ast_filerename(tempfile, recordfile, NULL);
13434 ast_play_and_wait(chan, "vm-msgsaved");
13435 cmd = '0';
13436 } else if (cmd == '4') {
13437 if (flag) {
13438 ast_play_and_wait(chan, "vm-marked-urgent");
13439 strcpy(flag, "Urgent");
13440 }
13441 ast_play_and_wait(chan, "vm-msgsaved");
13442 cmd = '0';
13443 } else {
13444 ast_play_and_wait(chan, "vm-deleted");
13445 DELETE(tempfile, -1, tempfile, vmu);
13446 cmd = '0';
13447 }
13448 }
13449 return cmd;
13450 default:
13451
13452
13453
13454 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13455 return cmd;
13456 if (msg_exists) {
13457 cmd = ast_play_and_wait(chan, "vm-review");
13458 if (!cmd && outsidecaller) {
13459 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13460 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13461 } else if (flag) {
13462 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13463 }
13464 }
13465 } else {
13466 cmd = ast_play_and_wait(chan, "vm-torerecord");
13467 if (!cmd)
13468 cmd = ast_waitfordigit(chan, 600);
13469 }
13470
13471 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13472 cmd = ast_play_and_wait(chan, "vm-reachoper");
13473 if (!cmd)
13474 cmd = ast_waitfordigit(chan, 600);
13475 }
13476 #if 0
13477 if (!cmd)
13478 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13479 #endif
13480 if (!cmd)
13481 cmd = ast_waitfordigit(chan, 6000);
13482 if (!cmd) {
13483 attempts++;
13484 }
13485 if (attempts > max_attempts) {
13486 cmd = 't';
13487 }
13488 }
13489 }
13490 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13491
13492 ast_filedelete(tempfile, NULL);
13493 }
13494
13495 if (cmd != 't' && outsidecaller)
13496 ast_play_and_wait(chan, "vm-goodbye");
13497
13498 return cmd;
13499 }
13500
13501
13502
13503
13504
13505 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13506 .load = load_module,
13507 .unload = unload_module,
13508 .reload = reload,
13509 .nonoptreq = "res_adsi,res_smdi",
13510 );