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 #include "asterisk.h"
00046
00047 #ifdef IMAP_STORAGE
00048 #include <ctype.h>
00049 #include <signal.h>
00050 #include <pwd.h>
00051 #ifdef USE_SYSTEM_IMAP
00052 #include <imap/c-client.h>
00053 #include <imap/imap4r1.h>
00054 #include <imap/linkage.h>
00055 #elif defined (USE_SYSTEM_CCLIENT)
00056 #include <c-client/c-client.h>
00057 #include <c-client/imap4r1.h>
00058 #include <c-client/linkage.h>
00059 #else
00060 #include "c-client.h"
00061 #include "imap4r1.h"
00062 #include "linkage.h"
00063 #endif
00064 #endif
00065
00066 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 301047 $")
00067
00068 #include "asterisk/paths.h"
00069 #include <sys/time.h>
00070 #include <sys/stat.h>
00071 #include <sys/mman.h>
00072 #include <time.h>
00073 #include <dirent.h>
00074 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00075 #include <sys/wait.h>
00076 #endif
00077
00078 #include "asterisk/logger.h"
00079 #include "asterisk/lock.h"
00080 #include "asterisk/file.h"
00081 #include "asterisk/channel.h"
00082 #include "asterisk/pbx.h"
00083 #include "asterisk/config.h"
00084 #include "asterisk/say.h"
00085 #include "asterisk/module.h"
00086 #include "asterisk/adsi.h"
00087 #include "asterisk/app.h"
00088 #include "asterisk/manager.h"
00089 #include "asterisk/dsp.h"
00090 #include "asterisk/localtime.h"
00091 #include "asterisk/cli.h"
00092 #include "asterisk/utils.h"
00093 #include "asterisk/stringfields.h"
00094 #include "asterisk/smdi.h"
00095 #include "asterisk/astobj2.h"
00096 #include "asterisk/event.h"
00097 #include "asterisk/taskprocessor.h"
00098 #include "asterisk/test.h"
00099
00100 #ifdef ODBC_STORAGE
00101 #include "asterisk/res_odbc.h"
00102 #endif
00103
00104 #ifdef IMAP_STORAGE
00105 #include "asterisk/threadstorage.h"
00106 #endif
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 #ifdef IMAP_STORAGE
00341 static char imapserver[48];
00342 static char imapport[8];
00343 static char imapflags[128];
00344 static char imapfolder[64];
00345 static char imapparentfolder[64] = "\0";
00346 static char greetingfolder[64];
00347 static char authuser[32];
00348 static char authpassword[42];
00349 static int imapversion = 1;
00350
00351 static int expungeonhangup = 1;
00352 static int imapgreetings = 0;
00353 static char delimiter = '\0';
00354
00355 struct vm_state;
00356 struct ast_vm_user;
00357
00358 AST_THREADSTORAGE(ts_vmstate);
00359
00360
00361 static int init_mailstream(struct vm_state *vms, int box);
00362 static void write_file(char *filename, char *buffer, unsigned long len);
00363 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00364 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00365 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00366 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00367 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00368 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00369 static void vmstate_insert(struct vm_state *vms);
00370 static void vmstate_delete(struct vm_state *vms);
00371 static void set_update(MAILSTREAM * stream);
00372 static void init_vm_state(struct vm_state *vms);
00373 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00374 static void get_mailbox_delimiter(MAILSTREAM *stream);
00375 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00376 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00377 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);
00378 static void update_messages_by_imapuser(const char *user, unsigned long number);
00379 static int vm_delete(char *file);
00380
00381 static int imap_remove_file (char *dir, int msgnum);
00382 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00383 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00384 static void check_quota(struct vm_state *vms, char *mailbox);
00385 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00386 struct vmstate {
00387 struct vm_state *vms;
00388 AST_LIST_ENTRY(vmstate) list;
00389 };
00390
00391 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00392
00393 #endif
00394
00395 #define SMDI_MWI_WAIT_TIMEOUT 1000
00396
00397 #define COMMAND_TIMEOUT 5000
00398
00399 #define VOICEMAIL_DIR_MODE 0777
00400 #define VOICEMAIL_FILE_MODE 0666
00401 #define CHUNKSIZE 65536
00402
00403 #define VOICEMAIL_CONFIG "voicemail.conf"
00404 #define ASTERISK_USERNAME "asterisk"
00405
00406
00407
00408
00409 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00410 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00411 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00412 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00413 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00414 #define VALID_DTMF "1234567890*#"
00415
00416
00417
00418 #define SENDMAIL "/usr/sbin/sendmail -t"
00419
00420 #define INTRO "vm-intro"
00421
00422 #define MAXMSG 100
00423 #define MAXMSGLIMIT 9999
00424
00425 #define MINPASSWORD 0
00426
00427 #define BASELINELEN 72
00428 #define BASEMAXINLINE 256
00429 #ifdef IMAP_STORAGE
00430 #define ENDL "\r\n"
00431 #else
00432 #define ENDL "\n"
00433 #endif
00434
00435 #define MAX_DATETIME_FORMAT 512
00436 #define MAX_NUM_CID_CONTEXTS 10
00437
00438 #define VM_REVIEW (1 << 0)
00439 #define VM_OPERATOR (1 << 1)
00440 #define VM_SAYCID (1 << 2)
00441 #define VM_SVMAIL (1 << 3)
00442 #define VM_ENVELOPE (1 << 4)
00443 #define VM_SAYDURATION (1 << 5)
00444 #define VM_SKIPAFTERCMD (1 << 6)
00445 #define VM_FORCENAME (1 << 7)
00446 #define VM_FORCEGREET (1 << 8)
00447 #define VM_PBXSKIP (1 << 9)
00448 #define VM_DIRECFORWARD (1 << 10)
00449 #define VM_ATTACH (1 << 11)
00450 #define VM_DELETE (1 << 12)
00451 #define VM_ALLOCED (1 << 13)
00452 #define VM_SEARCH (1 << 14)
00453 #define VM_TEMPGREETWARN (1 << 15)
00454 #define VM_MOVEHEARD (1 << 16)
00455 #define VM_MESSAGEWRAP (1 << 17)
00456 #define VM_FWDURGAUTO (1 << 18)
00457 #define ERROR_LOCK_PATH -100
00458 #define OPERATOR_EXIT 300
00459
00460
00461 enum vm_box {
00462 NEW_FOLDER,
00463 OLD_FOLDER,
00464 WORK_FOLDER,
00465 FAMILY_FOLDER,
00466 FRIENDS_FOLDER,
00467 GREETINGS_FOLDER
00468 };
00469
00470 enum vm_option_flags {
00471 OPT_SILENT = (1 << 0),
00472 OPT_BUSY_GREETING = (1 << 1),
00473 OPT_UNAVAIL_GREETING = (1 << 2),
00474 OPT_RECORDGAIN = (1 << 3),
00475 OPT_PREPEND_MAILBOX = (1 << 4),
00476 OPT_AUTOPLAY = (1 << 6),
00477 OPT_DTMFEXIT = (1 << 7),
00478 OPT_MESSAGE_Urgent = (1 << 8),
00479 OPT_MESSAGE_PRIORITY = (1 << 9)
00480 };
00481
00482 enum vm_option_args {
00483 OPT_ARG_RECORDGAIN = 0,
00484 OPT_ARG_PLAYFOLDER = 1,
00485 OPT_ARG_DTMFEXIT = 2,
00486
00487 OPT_ARG_ARRAY_SIZE = 3,
00488 };
00489
00490 enum vm_passwordlocation {
00491 OPT_PWLOC_VOICEMAILCONF = 0,
00492 OPT_PWLOC_SPOOLDIR = 1,
00493 OPT_PWLOC_USERSCONF = 2,
00494 };
00495
00496 AST_APP_OPTIONS(vm_app_options, {
00497 AST_APP_OPTION('s', OPT_SILENT),
00498 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00499 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00500 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00501 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00502 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00503 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00504 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00505 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00506 });
00507
00508 static int load_config(int reload);
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593 struct baseio {
00594 int iocp;
00595 int iolen;
00596 int linelength;
00597 int ateof;
00598 unsigned char iobuf[BASEMAXINLINE];
00599 };
00600
00601
00602
00603 struct ast_vm_user {
00604 char context[AST_MAX_CONTEXT];
00605 char mailbox[AST_MAX_EXTENSION];
00606 char password[80];
00607 char fullname[80];
00608 char email[80];
00609 char *emailsubject;
00610 char *emailbody;
00611 char pager[80];
00612 char serveremail[80];
00613 char mailcmd[160];
00614 char language[MAX_LANGUAGE];
00615 char zonetag[80];
00616 char locale[20];
00617 char callback[80];
00618 char dialout[80];
00619 char uniqueid[80];
00620 char exit[80];
00621 char attachfmt[20];
00622 unsigned int flags;
00623 int saydurationm;
00624 int minsecs;
00625 int maxmsg;
00626 int maxdeletedmsg;
00627 int maxsecs;
00628 int passwordlocation;
00629 #ifdef IMAP_STORAGE
00630 char imapuser[80];
00631 char imappassword[80];
00632 char imapfolder[64];
00633 char imapvmshareid[80];
00634 int imapversion;
00635 #endif
00636 double volgain;
00637 AST_LIST_ENTRY(ast_vm_user) list;
00638 };
00639
00640
00641 struct vm_zone {
00642 AST_LIST_ENTRY(vm_zone) list;
00643 char name[80];
00644 char timezone[80];
00645 char msg_format[512];
00646 };
00647
00648 #define VMSTATE_MAX_MSG_ARRAY 256
00649
00650
00651 struct vm_state {
00652 char curbox[80];
00653 char username[80];
00654 char context[80];
00655 char curdir[PATH_MAX];
00656 char vmbox[PATH_MAX];
00657 char fn[PATH_MAX];
00658 char intro[PATH_MAX];
00659 int *deleted;
00660 int *heard;
00661 int dh_arraysize;
00662 int curmsg;
00663 int lastmsg;
00664 int newmessages;
00665 int oldmessages;
00666 int urgentmessages;
00667 int starting;
00668 int repeats;
00669 #ifdef IMAP_STORAGE
00670 ast_mutex_t lock;
00671 int updated;
00672 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00673 MAILSTREAM *mailstream;
00674 int vmArrayIndex;
00675 char imapuser[80];
00676 char imapfolder[64];
00677 int imapversion;
00678 int interactive;
00679 char introfn[PATH_MAX];
00680 unsigned int quota_limit;
00681 unsigned int quota_usage;
00682 struct vm_state *persist_vms;
00683 #endif
00684 };
00685
00686 #ifdef ODBC_STORAGE
00687 static char odbc_database[80];
00688 static char odbc_table[80];
00689 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00690 #define DISPOSE(a,b) remove_file(a,b)
00691 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00692 #define EXISTS(a,b,c,d) (message_exists(a,b))
00693 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00694 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00695 #define DELETE(a,b,c,d) (delete_file(a,b))
00696 #else
00697 #ifdef IMAP_STORAGE
00698 #define DISPOSE(a,b) (imap_remove_file(a,b))
00699 #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))
00700 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00701 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00702 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00703 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00704 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00705 #else
00706 #define RETRIEVE(a,b,c,d)
00707 #define DISPOSE(a,b)
00708 #define STORE(a,b,c,d,e,f,g,h,i,j)
00709 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00710 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00711 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00712 #define DELETE(a,b,c,d) (vm_delete(c))
00713 #endif
00714 #endif
00715
00716 static char VM_SPOOL_DIR[PATH_MAX];
00717
00718 static char ext_pass_cmd[128];
00719 static char ext_pass_check_cmd[128];
00720
00721 static int my_umask;
00722
00723 #define PWDCHANGE_INTERNAL (1 << 1)
00724 #define PWDCHANGE_EXTERNAL (1 << 2)
00725 static int pwdchange = PWDCHANGE_INTERNAL;
00726
00727 #ifdef ODBC_STORAGE
00728 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00729 #else
00730 # ifdef IMAP_STORAGE
00731 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00732 # else
00733 # define tdesc "Comedian Mail (Voicemail System)"
00734 # endif
00735 #endif
00736
00737 static char userscontext[AST_MAX_EXTENSION] = "default";
00738
00739 static char *addesc = "Comedian Mail";
00740
00741
00742 static char *app = "VoiceMail";
00743
00744
00745 static char *app2 = "VoiceMailMain";
00746
00747 static char *app3 = "MailboxExists";
00748 static char *app4 = "VMAuthenticate";
00749
00750 static char *sayname_app = "VMSayName";
00751
00752 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00753 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00754 static char zonetag[80];
00755 static char locale[20];
00756 static int maxsilence;
00757 static int maxmsg;
00758 static int maxdeletedmsg;
00759 static int silencethreshold = 128;
00760 static char serveremail[80];
00761 static char mailcmd[160];
00762 static char externnotify[160];
00763 static struct ast_smdi_interface *smdi_iface = NULL;
00764 static char vmfmts[80];
00765 static double volgain;
00766 static int vmminsecs;
00767 static int vmmaxsecs;
00768 static int maxgreet;
00769 static int skipms;
00770 static int maxlogins;
00771 static int minpassword;
00772 static int passwordlocation;
00773
00774
00775
00776 static unsigned int poll_mailboxes;
00777
00778
00779 static unsigned int poll_freq;
00780
00781 #define DEFAULT_POLL_FREQ 30
00782
00783 AST_MUTEX_DEFINE_STATIC(poll_lock);
00784 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00785 static pthread_t poll_thread = AST_PTHREADT_NULL;
00786 static unsigned char poll_thread_run;
00787
00788
00789 static struct ast_event_sub *mwi_sub_sub;
00790
00791 static struct ast_event_sub *mwi_unsub_sub;
00792
00793
00794
00795
00796
00797
00798
00799
00800 struct mwi_sub {
00801 AST_RWLIST_ENTRY(mwi_sub) entry;
00802 int old_urgent;
00803 int old_new;
00804 int old_old;
00805 uint32_t uniqueid;
00806 char mailbox[1];
00807 };
00808
00809 struct mwi_sub_task {
00810 const char *mailbox;
00811 const char *context;
00812 uint32_t uniqueid;
00813 };
00814
00815 static struct ast_taskprocessor *mwi_subscription_tps;
00816
00817 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00818
00819
00820 static char listen_control_forward_key[12];
00821 static char listen_control_reverse_key[12];
00822 static char listen_control_pause_key[12];
00823 static char listen_control_restart_key[12];
00824 static char listen_control_stop_key[12];
00825
00826
00827 static char vm_password[80] = "vm-password";
00828 static char vm_newpassword[80] = "vm-newpassword";
00829 static char vm_passchanged[80] = "vm-passchanged";
00830 static char vm_reenterpassword[80] = "vm-reenterpassword";
00831 static char vm_mismatch[80] = "vm-mismatch";
00832 static char vm_invalid_password[80] = "vm-invalid-password";
00833 static char vm_pls_try_again[80] = "vm-pls-try-again";
00834
00835 static struct ast_flags globalflags = {0};
00836
00837 static int saydurationminfo;
00838
00839 static char dialcontext[AST_MAX_CONTEXT] = "";
00840 static char callcontext[AST_MAX_CONTEXT] = "";
00841 static char exitcontext[AST_MAX_CONTEXT] = "";
00842
00843 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00844
00845
00846 static char *emailbody = NULL;
00847 static char *emailsubject = NULL;
00848 static char *pagerbody = NULL;
00849 static char *pagersubject = NULL;
00850 static char fromstring[100];
00851 static char pagerfromstring[100];
00852 static char charset[32] = "ISO-8859-1";
00853
00854 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00855 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00856 static int adsiver = 1;
00857 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00858 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00859
00860
00861 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00862 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);
00863 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00864 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00865 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00866 signed char record_gain, struct vm_state *vms, char *flag);
00867 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00868 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00869 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);
00870 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);
00871 static void apply_options(struct ast_vm_user *vmu, const char *options);
00872 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);
00873 static int is_valid_dtmf(const char *key);
00874 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00875 static int write_password_to_file(const char *secretfn, const char *password);
00876
00877 struct ao2_container *inprocess_container;
00878
00879 struct inprocess {
00880 int count;
00881 char *context;
00882 char mailbox[0];
00883 };
00884
00885 static int inprocess_hash_fn(const void *obj, const int flags)
00886 {
00887 const struct inprocess *i = obj;
00888 return atoi(i->mailbox);
00889 }
00890
00891 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00892 {
00893 struct inprocess *i = obj, *j = arg;
00894 if (strcmp(i->mailbox, j->mailbox)) {
00895 return 0;
00896 }
00897 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00898 }
00899
00900 static int inprocess_count(const char *context, const char *mailbox, int delta)
00901 {
00902 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00903 arg->context = arg->mailbox + strlen(mailbox) + 1;
00904 strcpy(arg->mailbox, mailbox);
00905 strcpy(arg->context, context);
00906 ao2_lock(inprocess_container);
00907 if ((i = ao2_find(inprocess_container, arg, 0))) {
00908 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00909 ao2_unlock(inprocess_container);
00910 ao2_ref(i, -1);
00911 return ret;
00912 }
00913 if (delta < 0) {
00914 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00915 }
00916 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00917 ao2_unlock(inprocess_container);
00918 return 0;
00919 }
00920 i->context = i->mailbox + strlen(mailbox) + 1;
00921 strcpy(i->mailbox, mailbox);
00922 strcpy(i->context, context);
00923 i->count = delta;
00924 ao2_link(inprocess_container, i);
00925 ao2_unlock(inprocess_container);
00926 ao2_ref(i, -1);
00927 return 0;
00928 }
00929
00930 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00931 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00932 #endif
00933
00934
00935
00936
00937
00938
00939
00940 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00941 {
00942 char *bufptr = buf;
00943 for (; *input; input++) {
00944 if (*input < 32) {
00945 continue;
00946 }
00947 *bufptr++ = *input;
00948 if (bufptr == buf + buflen - 1) {
00949 break;
00950 }
00951 }
00952 *bufptr = '\0';
00953 return buf;
00954 }
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969 static void populate_defaults(struct ast_vm_user *vmu)
00970 {
00971 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00972 vmu->passwordlocation = passwordlocation;
00973 if (saydurationminfo) {
00974 vmu->saydurationm = saydurationminfo;
00975 }
00976 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00977 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00978 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00979 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00980 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
00981 if (vmminsecs) {
00982 vmu->minsecs = vmminsecs;
00983 }
00984 if (vmmaxsecs) {
00985 vmu->maxsecs = vmmaxsecs;
00986 }
00987 if (maxmsg) {
00988 vmu->maxmsg = maxmsg;
00989 }
00990 if (maxdeletedmsg) {
00991 vmu->maxdeletedmsg = maxdeletedmsg;
00992 }
00993 vmu->volgain = volgain;
00994 vmu->emailsubject = NULL;
00995 vmu->emailbody = NULL;
00996 #ifdef IMAP_STORAGE
00997 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
00998 #endif
00999 }
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01010 {
01011 int x;
01012 if (!strcasecmp(var, "attach")) {
01013 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01014 } else if (!strcasecmp(var, "attachfmt")) {
01015 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01016 } else if (!strcasecmp(var, "serveremail")) {
01017 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01018 } else if (!strcasecmp(var, "language")) {
01019 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01020 } else if (!strcasecmp(var, "tz")) {
01021 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01022 } else if (!strcasecmp(var, "locale")) {
01023 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01024 #ifdef IMAP_STORAGE
01025 } else if (!strcasecmp(var, "imapuser")) {
01026 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01027 vmu->imapversion = imapversion;
01028 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01029 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01030 vmu->imapversion = imapversion;
01031 } else if (!strcasecmp(var, "imapfolder")) {
01032 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01033 } else if (!strcasecmp(var, "imapvmshareid")) {
01034 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01035 vmu->imapversion = imapversion;
01036 #endif
01037 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01038 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01039 } else if (!strcasecmp(var, "saycid")){
01040 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01041 } else if (!strcasecmp(var, "sendvoicemail")){
01042 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01043 } else if (!strcasecmp(var, "review")){
01044 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01045 } else if (!strcasecmp(var, "tempgreetwarn")){
01046 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01047 } else if (!strcasecmp(var, "messagewrap")){
01048 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01049 } else if (!strcasecmp(var, "operator")) {
01050 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01051 } else if (!strcasecmp(var, "envelope")){
01052 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01053 } else if (!strcasecmp(var, "moveheard")){
01054 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01055 } else if (!strcasecmp(var, "sayduration")){
01056 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01057 } else if (!strcasecmp(var, "saydurationm")){
01058 if (sscanf(value, "%30d", &x) == 1) {
01059 vmu->saydurationm = x;
01060 } else {
01061 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01062 }
01063 } else if (!strcasecmp(var, "forcename")){
01064 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01065 } else if (!strcasecmp(var, "forcegreetings")){
01066 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01067 } else if (!strcasecmp(var, "callback")) {
01068 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01069 } else if (!strcasecmp(var, "dialout")) {
01070 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01071 } else if (!strcasecmp(var, "exitcontext")) {
01072 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01073 } else if (!strcasecmp(var, "minsecs")) {
01074 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01075 vmu->minsecs = x;
01076 } else {
01077 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01078 vmu->minsecs = vmminsecs;
01079 }
01080 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01081 vmu->maxsecs = atoi(value);
01082 if (vmu->maxsecs <= 0) {
01083 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01084 vmu->maxsecs = vmmaxsecs;
01085 } else {
01086 vmu->maxsecs = atoi(value);
01087 }
01088 if (!strcasecmp(var, "maxmessage"))
01089 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01090 } else if (!strcasecmp(var, "maxmsg")) {
01091 vmu->maxmsg = atoi(value);
01092
01093 if (vmu->maxmsg < 0) {
01094 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01095 vmu->maxmsg = MAXMSG;
01096 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01097 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01098 vmu->maxmsg = MAXMSGLIMIT;
01099 }
01100 } else if (!strcasecmp(var, "nextaftercmd")) {
01101 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01102 } else if (!strcasecmp(var, "backupdeleted")) {
01103 if (sscanf(value, "%30d", &x) == 1)
01104 vmu->maxdeletedmsg = x;
01105 else if (ast_true(value))
01106 vmu->maxdeletedmsg = MAXMSG;
01107 else
01108 vmu->maxdeletedmsg = 0;
01109
01110 if (vmu->maxdeletedmsg < 0) {
01111 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01112 vmu->maxdeletedmsg = MAXMSG;
01113 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01114 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01115 vmu->maxdeletedmsg = MAXMSGLIMIT;
01116 }
01117 } else if (!strcasecmp(var, "volgain")) {
01118 sscanf(value, "%30lf", &vmu->volgain);
01119 } else if (!strcasecmp(var, "passwordlocation")) {
01120 if (!strcasecmp(value, "spooldir")) {
01121 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01122 } else {
01123 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01124 }
01125 } else if (!strcasecmp(var, "options")) {
01126 apply_options(vmu, value);
01127 }
01128 }
01129
01130 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01131 {
01132 int fds[2], pid = 0;
01133
01134 memset(buf, 0, len);
01135
01136 if (pipe(fds)) {
01137 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01138 } else {
01139
01140 pid = ast_safe_fork(0);
01141
01142 if (pid < 0) {
01143
01144 close(fds[0]);
01145 close(fds[1]);
01146 snprintf(buf, len, "FAILURE: Fork failed");
01147 } else if (pid) {
01148
01149 close(fds[1]);
01150 if (read(fds[0], buf, len) < 0) {
01151 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01152 }
01153 close(fds[0]);
01154 } else {
01155
01156 AST_DECLARE_APP_ARGS(arg,
01157 AST_APP_ARG(v)[20];
01158 );
01159 char *mycmd = ast_strdupa(command);
01160
01161 close(fds[0]);
01162 dup2(fds[1], STDOUT_FILENO);
01163 close(fds[1]);
01164 ast_close_fds_above_n(STDOUT_FILENO);
01165
01166 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01167
01168 execv(arg.v[0], arg.v);
01169 printf("FAILURE: %s", strerror(errno));
01170 _exit(0);
01171 }
01172 }
01173 return buf;
01174 }
01175
01176
01177
01178
01179
01180
01181
01182
01183 static int check_password(struct ast_vm_user *vmu, char *password)
01184 {
01185
01186 if (strlen(password) < minpassword)
01187 return 1;
01188 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01189 char cmd[255], buf[255];
01190
01191 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01192
01193 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01194 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01195 ast_debug(5, "Result: %s\n", buf);
01196 if (!strncasecmp(buf, "VALID", 5)) {
01197 ast_debug(3, "Passed password check: '%s'\n", buf);
01198 return 0;
01199 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01200 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01201 return 0;
01202 } else {
01203 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01204 return 1;
01205 }
01206 }
01207 }
01208 return 0;
01209 }
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01222 {
01223 int res = -1;
01224 if (!strcmp(vmu->password, password)) {
01225
01226 return 0;
01227 }
01228
01229 if (strlen(password) > 10) {
01230 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01231 }
01232 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01233 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01234 res = 0;
01235 }
01236 return res;
01237 }
01238
01239
01240
01241
01242 static void apply_options(struct ast_vm_user *vmu, const char *options)
01243 {
01244 char *stringp;
01245 char *s;
01246 char *var, *value;
01247 stringp = ast_strdupa(options);
01248 while ((s = strsep(&stringp, "|"))) {
01249 value = s;
01250 if ((var = strsep(&value, "=")) && value) {
01251 apply_option(vmu, var, value);
01252 }
01253 }
01254 }
01255
01256
01257
01258
01259
01260
01261 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01262 {
01263 for (; var; var = var->next) {
01264 if (!strcasecmp(var->name, "vmsecret")) {
01265 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01266 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01267 if (ast_strlen_zero(retval->password))
01268 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01269 } else if (!strcasecmp(var->name, "uniqueid")) {
01270 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01271 } else if (!strcasecmp(var->name, "pager")) {
01272 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01273 } else if (!strcasecmp(var->name, "email")) {
01274 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01275 } else if (!strcasecmp(var->name, "fullname")) {
01276 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01277 } else if (!strcasecmp(var->name, "context")) {
01278 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01279 } else if (!strcasecmp(var->name, "emailsubject")) {
01280 retval->emailsubject = ast_strdup(var->value);
01281 } else if (!strcasecmp(var->name, "emailbody")) {
01282 retval->emailbody = ast_strdup(var->value);
01283 #ifdef IMAP_STORAGE
01284 } else if (!strcasecmp(var->name, "imapuser")) {
01285 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01286 retval->imapversion = imapversion;
01287 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01288 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01289 retval->imapversion = imapversion;
01290 } else if (!strcasecmp(var->name, "imapfolder")) {
01291 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01292 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01293 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01294 retval->imapversion = imapversion;
01295 #endif
01296 } else
01297 apply_option(retval, var->name, var->value);
01298 }
01299 }
01300
01301
01302
01303
01304
01305
01306
01307
01308 static int is_valid_dtmf(const char *key)
01309 {
01310 int i;
01311 char *local_key = ast_strdupa(key);
01312
01313 for (i = 0; i < strlen(key); ++i) {
01314 if (!strchr(VALID_DTMF, *local_key)) {
01315 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01316 return 0;
01317 }
01318 local_key++;
01319 }
01320 return 1;
01321 }
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01334 {
01335 struct ast_variable *var;
01336 struct ast_vm_user *retval;
01337
01338 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01339 if (!ivm)
01340 ast_set_flag(retval, VM_ALLOCED);
01341 else
01342 memset(retval, 0, sizeof(*retval));
01343 if (mailbox)
01344 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01345 populate_defaults(retval);
01346 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01347 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01348 else
01349 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01350 if (var) {
01351 apply_options_full(retval, var);
01352 ast_variables_destroy(var);
01353 } else {
01354 if (!ivm)
01355 ast_free(retval);
01356 retval = NULL;
01357 }
01358 }
01359 return retval;
01360 }
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01371 {
01372
01373 struct ast_vm_user *vmu = NULL, *cur;
01374 AST_LIST_LOCK(&users);
01375
01376 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01377 context = "default";
01378
01379 AST_LIST_TRAVERSE(&users, cur, list) {
01380 #ifdef IMAP_STORAGE
01381 if (cur->imapversion != imapversion) {
01382 continue;
01383 }
01384 #endif
01385 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01386 break;
01387 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01388 break;
01389 }
01390 if (cur) {
01391
01392 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01393 memcpy(vmu, cur, sizeof(*vmu));
01394 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01395 AST_LIST_NEXT(vmu, list) = NULL;
01396 }
01397 } else
01398 vmu = find_user_realtime(ivm, context, mailbox);
01399 AST_LIST_UNLOCK(&users);
01400 return vmu;
01401 }
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01414 {
01415
01416 struct ast_vm_user *cur;
01417 int res = -1;
01418 AST_LIST_LOCK(&users);
01419 AST_LIST_TRAVERSE(&users, cur, list) {
01420 if ((!context || !strcasecmp(context, cur->context)) &&
01421 (!strcasecmp(mailbox, cur->mailbox)))
01422 break;
01423 }
01424 if (cur) {
01425 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01426 res = 0;
01427 }
01428 AST_LIST_UNLOCK(&users);
01429 return res;
01430 }
01431
01432
01433
01434
01435
01436
01437
01438
01439 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01440 {
01441 struct ast_config *cfg = NULL;
01442 struct ast_variable *var = NULL;
01443 struct ast_category *cat = NULL;
01444 char *category = NULL, *value = NULL, *new = NULL;
01445 const char *tmp = NULL;
01446 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01447 char secretfn[PATH_MAX] = "";
01448 int found = 0;
01449
01450 if (!change_password_realtime(vmu, newpassword))
01451 return;
01452
01453
01454 switch (vmu->passwordlocation) {
01455 case OPT_PWLOC_SPOOLDIR:
01456 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01457 if (write_password_to_file(secretfn, newpassword) == 0) {
01458 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01459 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01460 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01461 break;
01462 } else {
01463 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01464 }
01465
01466 case OPT_PWLOC_VOICEMAILCONF:
01467 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01468 while ((category = ast_category_browse(cfg, category))) {
01469 if (!strcasecmp(category, vmu->context)) {
01470 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01471 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01472 break;
01473 }
01474 value = strstr(tmp, ",");
01475 if (!value) {
01476 new = alloca(strlen(newpassword)+1);
01477 sprintf(new, "%s", newpassword);
01478 } else {
01479 new = alloca((strlen(value) + strlen(newpassword) + 1));
01480 sprintf(new, "%s%s", newpassword, value);
01481 }
01482 if (!(cat = ast_category_get(cfg, category))) {
01483 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01484 break;
01485 }
01486 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01487 found = 1;
01488 }
01489 }
01490
01491 if (found) {
01492 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01493 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01494 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01495 break;
01496 }
01497 }
01498
01499 case OPT_PWLOC_USERSCONF:
01500
01501
01502 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01503 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01504 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01505 ast_debug(4, "users.conf: %s\n", category);
01506 if (!strcasecmp(category, vmu->mailbox)) {
01507 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01508 ast_debug(3, "looks like we need to make vmsecret!\n");
01509 var = ast_variable_new("vmsecret", newpassword, "");
01510 } else {
01511 var = NULL;
01512 }
01513 new = alloca(strlen(newpassword) + 1);
01514 sprintf(new, "%s", newpassword);
01515 if (!(cat = ast_category_get(cfg, category))) {
01516 ast_debug(4, "failed to get category!\n");
01517 ast_free(var);
01518 break;
01519 }
01520 if (!var) {
01521 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01522 } else {
01523 ast_variable_append(cat, var);
01524 }
01525 found = 1;
01526 break;
01527 }
01528 }
01529
01530 if (found) {
01531 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01532 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01533 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01534 }
01535 }
01536 }
01537 }
01538
01539 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01540 {
01541 char buf[255];
01542 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01543 if (!ast_safe_system(buf)) {
01544 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01545
01546 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01547 }
01548 }
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01564 {
01565 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01566 }
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580 static int make_file(char *dest, const int len, const char *dir, const int num)
01581 {
01582 return snprintf(dest, len, "%s/msg%04d", dir, num);
01583 }
01584
01585
01586 static FILE *vm_mkftemp(char *template)
01587 {
01588 FILE *p = NULL;
01589 int pfd = mkstemp(template);
01590 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01591 if (pfd > -1) {
01592 p = fdopen(pfd, "w+");
01593 if (!p) {
01594 close(pfd);
01595 pfd = -1;
01596 }
01597 }
01598 return p;
01599 }
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01610 {
01611 mode_t mode = VOICEMAIL_DIR_MODE;
01612 int res;
01613
01614 make_dir(dest, len, context, ext, folder);
01615 if ((res = ast_mkdir(dest, mode))) {
01616 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01617 return -1;
01618 }
01619 return 0;
01620 }
01621
01622 static const char * const mailbox_folders[] = {
01623 #ifdef IMAP_STORAGE
01624 imapfolder,
01625 #else
01626 "INBOX",
01627 #endif
01628 "Old",
01629 "Work",
01630 "Family",
01631 "Friends",
01632 "Cust1",
01633 "Cust2",
01634 "Cust3",
01635 "Cust4",
01636 "Cust5",
01637 "Deleted",
01638 "Urgent",
01639 };
01640
01641 static const char *mbox(struct ast_vm_user *vmu, int id)
01642 {
01643 #ifdef IMAP_STORAGE
01644 if (vmu && id == 0) {
01645 return vmu->imapfolder;
01646 }
01647 #endif
01648 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01649 }
01650
01651 static int get_folder_by_name(const char *name)
01652 {
01653 size_t i;
01654
01655 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01656 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01657 return i;
01658 }
01659 }
01660
01661 return -1;
01662 }
01663
01664 static void free_user(struct ast_vm_user *vmu)
01665 {
01666 if (ast_test_flag(vmu, VM_ALLOCED)) {
01667 if (vmu->emailbody != NULL) {
01668 ast_free(vmu->emailbody);
01669 vmu->emailbody = NULL;
01670 }
01671 if (vmu->emailsubject != NULL) {
01672 ast_free(vmu->emailsubject);
01673 vmu->emailsubject = NULL;
01674 }
01675 ast_free(vmu);
01676 }
01677 }
01678
01679 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01680
01681 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01682 if (!vms->dh_arraysize) {
01683
01684 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01685 return -1;
01686 }
01687 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01688 return -1;
01689 }
01690 vms->dh_arraysize = arraysize;
01691 } else if (vms->dh_arraysize < arraysize) {
01692 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01693 return -1;
01694 }
01695 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01696 return -1;
01697 }
01698 memset(vms->deleted, 0, arraysize * sizeof(int));
01699 memset(vms->heard, 0, arraysize * sizeof(int));
01700 vms->dh_arraysize = arraysize;
01701 }
01702
01703 return 0;
01704 }
01705
01706
01707
01708 #ifdef IMAP_STORAGE
01709 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01710 {
01711 char arg[10];
01712 struct vm_state *vms;
01713 unsigned long messageNum;
01714
01715
01716 if (msgnum < 0 && !imapgreetings) {
01717 ast_filedelete(file, NULL);
01718 return;
01719 }
01720
01721 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01722 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);
01723 return;
01724 }
01725
01726
01727
01728 messageNum = vms->msgArray[msgnum];
01729 if (messageNum == 0) {
01730 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01731 return;
01732 }
01733 if (option_debug > 2)
01734 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01735
01736 snprintf (arg, sizeof(arg), "%lu", messageNum);
01737 ast_mutex_lock(&vms->lock);
01738 mail_setflag (vms->mailstream, arg, "\\DELETED");
01739 mail_expunge(vms->mailstream);
01740 ast_mutex_unlock(&vms->lock);
01741 }
01742
01743 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01744 {
01745 struct vm_state *vms_p;
01746 char *file, *filename;
01747 char *attachment;
01748 int ret = 0, i;
01749 BODY *body;
01750
01751
01752
01753
01754 if (msgnum > -1 || !imapgreetings) {
01755 return 0;
01756 } else {
01757 file = strrchr(ast_strdupa(dir), '/');
01758 if (file)
01759 *file++ = '\0';
01760 else {
01761 ast_debug (1, "Failed to procure file name from directory passed.\n");
01762 return -1;
01763 }
01764 }
01765
01766
01767 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01768 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01769
01770
01771
01772
01773 if (!(vms_p = create_vm_state_from_user(vmu))) {
01774 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01775 return -1;
01776 }
01777 }
01778
01779
01780 *vms_p->introfn = '\0';
01781
01782 ast_mutex_lock(&vms_p->lock);
01783 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01784 if (!vms_p->mailstream) {
01785 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01786 ast_mutex_unlock(&vms_p->lock);
01787 return -1;
01788 }
01789
01790
01791 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01792 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01793
01794 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01795 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01796 } else {
01797 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01798 ast_mutex_unlock(&vms_p->lock);
01799 return -1;
01800 }
01801 filename = strsep(&attachment, ".");
01802 if (!strcmp(filename, file)) {
01803 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01804 vms_p->msgArray[vms_p->curmsg] = i + 1;
01805 save_body(body, vms_p, "2", attachment, 0);
01806 ast_mutex_unlock(&vms_p->lock);
01807 return 0;
01808 }
01809 }
01810 ast_mutex_unlock(&vms_p->lock);
01811
01812 return -1;
01813 }
01814
01815 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01816 {
01817 BODY *body;
01818 char *header_content;
01819 char *attachedfilefmt;
01820 char buf[80];
01821 struct vm_state *vms;
01822 char text_file[PATH_MAX];
01823 FILE *text_file_ptr;
01824 int res = 0;
01825 struct ast_vm_user *vmu;
01826
01827 if (!(vmu = find_user(NULL, context, mailbox))) {
01828 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01829 return -1;
01830 }
01831
01832 if (msgnum < 0) {
01833 if (imapgreetings) {
01834 res = imap_retrieve_greeting(dir, msgnum, vmu);
01835 goto exit;
01836 } else {
01837 res = 0;
01838 goto exit;
01839 }
01840 }
01841
01842
01843
01844
01845 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01846
01847
01848
01849
01850
01851
01852
01853 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01854 res = -1;
01855 goto exit;
01856 }
01857
01858 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01859 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01860
01861
01862 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01863 res = 0;
01864 goto exit;
01865 }
01866
01867 if (option_debug > 2)
01868 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01869 if (vms->msgArray[msgnum] == 0) {
01870 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01871 res = -1;
01872 goto exit;
01873 }
01874
01875
01876 ast_mutex_lock(&vms->lock);
01877 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01878 ast_mutex_unlock(&vms->lock);
01879
01880 if (ast_strlen_zero(header_content)) {
01881 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01882 res = -1;
01883 goto exit;
01884 }
01885
01886 ast_mutex_lock(&vms->lock);
01887 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01888 ast_mutex_unlock(&vms->lock);
01889
01890
01891 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01892 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01893 } else {
01894 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01895 res = -1;
01896 goto exit;
01897 }
01898
01899
01900
01901 strsep(&attachedfilefmt, ".");
01902 if (!attachedfilefmt) {
01903 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01904 res = -1;
01905 goto exit;
01906 }
01907
01908 save_body(body, vms, "2", attachedfilefmt, 0);
01909 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01910 *vms->introfn = '\0';
01911 }
01912
01913
01914 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01915
01916 if (!(text_file_ptr = fopen(text_file, "w"))) {
01917 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01918 }
01919
01920 fprintf(text_file_ptr, "%s\n", "[message]");
01921
01922 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01923 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01924 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01925 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01926 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01927 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01928 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01929 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01930 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01931 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01932 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01933 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01934 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01935 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01936 fclose(text_file_ptr);
01937
01938 exit:
01939 free_user(vmu);
01940 return res;
01941 }
01942
01943 static int folder_int(const char *folder)
01944 {
01945
01946 if (!folder) {
01947 return 0;
01948 }
01949 if (!strcasecmp(folder, imapfolder)) {
01950 return 0;
01951 } else if (!strcasecmp(folder, "Old")) {
01952 return 1;
01953 } else if (!strcasecmp(folder, "Work")) {
01954 return 2;
01955 } else if (!strcasecmp(folder, "Family")) {
01956 return 3;
01957 } else if (!strcasecmp(folder, "Friends")) {
01958 return 4;
01959 } else if (!strcasecmp(folder, "Cust1")) {
01960 return 5;
01961 } else if (!strcasecmp(folder, "Cust2")) {
01962 return 6;
01963 } else if (!strcasecmp(folder, "Cust3")) {
01964 return 7;
01965 } else if (!strcasecmp(folder, "Cust4")) {
01966 return 8;
01967 } else if (!strcasecmp(folder, "Cust5")) {
01968 return 9;
01969 } else if (!strcasecmp(folder, "Urgent")) {
01970 return 11;
01971 } else {
01972 return 0;
01973 }
01974 }
01975
01976 static int __messagecount(const char *context, const char *mailbox, const char *folder)
01977 {
01978 SEARCHPGM *pgm;
01979 SEARCHHEADER *hdr;
01980
01981 struct ast_vm_user *vmu, vmus;
01982 struct vm_state *vms_p;
01983 int ret = 0;
01984 int fold = folder_int(folder);
01985 int urgent = 0;
01986
01987
01988 if (fold == 11) {
01989 fold = NEW_FOLDER;
01990 urgent = 1;
01991 }
01992
01993 if (ast_strlen_zero(mailbox))
01994 return 0;
01995
01996
01997 vmu = find_user(&vmus, context, mailbox);
01998 if (!vmu) {
01999 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02000 return -1;
02001 } else {
02002
02003 if (vmu->imapuser[0] == '\0') {
02004 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02005 return -1;
02006 }
02007 }
02008
02009
02010 if (vmu->imapuser[0] == '\0') {
02011 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02012 free_user(vmu);
02013 return -1;
02014 }
02015
02016
02017 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02018 if (!vms_p) {
02019 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02020 }
02021 if (vms_p) {
02022 ast_debug(3, "Returning before search - user is logged in\n");
02023 if (fold == 0) {
02024 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02025 }
02026 if (fold == 1) {
02027 return vms_p->oldmessages;
02028 }
02029 }
02030
02031
02032 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02033 if (!vms_p) {
02034 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02035 }
02036
02037 if (!vms_p) {
02038 vms_p = create_vm_state_from_user(vmu);
02039 }
02040 ret = init_mailstream(vms_p, fold);
02041 if (!vms_p->mailstream) {
02042 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02043 return -1;
02044 }
02045 if (ret == 0) {
02046 ast_mutex_lock(&vms_p->lock);
02047 pgm = mail_newsearchpgm ();
02048 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02049 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02050 pgm->header = hdr;
02051 if (fold != OLD_FOLDER) {
02052 pgm->unseen = 1;
02053 pgm->seen = 0;
02054 }
02055
02056
02057
02058 else {
02059 pgm->unseen = 0;
02060 pgm->seen = 1;
02061 }
02062
02063 if (fold == NEW_FOLDER) {
02064 if (urgent) {
02065 pgm->flagged = 1;
02066 pgm->unflagged = 0;
02067 } else {
02068 pgm->flagged = 0;
02069 pgm->unflagged = 1;
02070 }
02071 }
02072 pgm->undeleted = 1;
02073 pgm->deleted = 0;
02074
02075 vms_p->vmArrayIndex = 0;
02076 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02077 if (fold == 0 && urgent == 0)
02078 vms_p->newmessages = vms_p->vmArrayIndex;
02079 if (fold == 1)
02080 vms_p->oldmessages = vms_p->vmArrayIndex;
02081 if (fold == 0 && urgent == 1)
02082 vms_p->urgentmessages = vms_p->vmArrayIndex;
02083
02084 mail_free_searchpgm(&pgm);
02085 ast_mutex_unlock(&vms_p->lock);
02086 vms_p->updated = 0;
02087 return vms_p->vmArrayIndex;
02088 } else {
02089 ast_mutex_lock(&vms_p->lock);
02090 mail_ping(vms_p->mailstream);
02091 ast_mutex_unlock(&vms_p->lock);
02092 }
02093 return 0;
02094 }
02095
02096 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02097 {
02098
02099 check_quota(vms, vmu->imapfolder);
02100 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02101 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02102 ast_play_and_wait(chan, "vm-mailboxfull");
02103 return -1;
02104 }
02105
02106
02107 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));
02108 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02109 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02110 ast_play_and_wait(chan, "vm-mailboxfull");
02111 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02112 return -1;
02113 }
02114
02115 return 0;
02116 }
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127 static int messagecount(const char *context, const char *mailbox, const char *folder)
02128 {
02129 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02130 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02131 } else {
02132 return __messagecount(context, mailbox, folder);
02133 }
02134 }
02135
02136 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)
02137 {
02138 char *myserveremail = serveremail;
02139 char fn[PATH_MAX];
02140 char introfn[PATH_MAX];
02141 char mailbox[256];
02142 char *stringp;
02143 FILE *p = NULL;
02144 char tmp[80] = "/tmp/astmail-XXXXXX";
02145 long len;
02146 void *buf;
02147 int tempcopy = 0;
02148 STRING str;
02149 int ret;
02150 char *imap_flags = NIL;
02151 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02152
02153
02154 if (msgnum < 0 && !imapgreetings) {
02155 return 0;
02156 }
02157
02158 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02159 return -1;
02160 }
02161
02162
02163 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02164 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02165 imap_flags = "\\FLAGGED";
02166 }
02167
02168
02169 fmt = ast_strdupa(fmt);
02170 stringp = fmt;
02171 strsep(&stringp, "|");
02172
02173 if (!ast_strlen_zero(vmu->serveremail))
02174 myserveremail = vmu->serveremail;
02175
02176 if (msgnum > -1)
02177 make_file(fn, sizeof(fn), dir, msgnum);
02178 else
02179 ast_copy_string (fn, dir, sizeof(fn));
02180
02181 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02182 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02183 *introfn = '\0';
02184 }
02185
02186 if (ast_strlen_zero(vmu->email)) {
02187
02188
02189
02190
02191
02192 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02193 tempcopy = 1;
02194 }
02195
02196 if (!strcmp(fmt, "wav49"))
02197 fmt = "WAV";
02198 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02199
02200
02201
02202 if (!(p = vm_mkftemp(tmp))) {
02203 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02204 if (tempcopy)
02205 *(vmu->email) = '\0';
02206 return -1;
02207 }
02208
02209 if (msgnum < 0 && imapgreetings) {
02210 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02211 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02212 return -1;
02213 }
02214 imap_delete_old_greeting(fn, vms);
02215 }
02216
02217 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02218 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02219 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02220 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02221
02222 len = ftell(p);
02223 rewind(p);
02224 if (!(buf = ast_malloc(len + 1))) {
02225 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02226 fclose(p);
02227 if (tempcopy)
02228 *(vmu->email) = '\0';
02229 return -1;
02230 }
02231 if (fread(buf, len, 1, p) < len) {
02232 if (ferror(p)) {
02233 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02234 return -1;
02235 }
02236 }
02237 ((char *) buf)[len] = '\0';
02238 INIT(&str, mail_string, buf, len);
02239 ret = init_mailstream(vms, NEW_FOLDER);
02240 if (ret == 0) {
02241 imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
02242 ast_mutex_lock(&vms->lock);
02243 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02244 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02245 ast_mutex_unlock(&vms->lock);
02246 fclose(p);
02247 unlink(tmp);
02248 ast_free(buf);
02249 } else {
02250 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02251 fclose(p);
02252 unlink(tmp);
02253 ast_free(buf);
02254 return -1;
02255 }
02256 ast_debug(3, "%s stored\n", fn);
02257
02258 if (tempcopy)
02259 *(vmu->email) = '\0';
02260 inprocess_count(vmu->mailbox, vmu->context, -1);
02261 return 0;
02262
02263 }
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02279 {
02280 char tmp[PATH_MAX] = "";
02281 char *mailboxnc;
02282 char *context;
02283 char *mb;
02284 char *cur;
02285 if (newmsgs)
02286 *newmsgs = 0;
02287 if (oldmsgs)
02288 *oldmsgs = 0;
02289 if (urgentmsgs)
02290 *urgentmsgs = 0;
02291
02292 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02293
02294 if (ast_strlen_zero(mailbox_context))
02295 return 0;
02296
02297 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02298 context = strchr(tmp, '@');
02299 if (strchr(mailbox_context, ',')) {
02300 int tmpnew, tmpold, tmpurgent;
02301 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02302 mb = tmp;
02303 while ((cur = strsep(&mb, ", "))) {
02304 if (!ast_strlen_zero(cur)) {
02305 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02306 return -1;
02307 else {
02308 if (newmsgs)
02309 *newmsgs += tmpnew;
02310 if (oldmsgs)
02311 *oldmsgs += tmpold;
02312 if (urgentmsgs)
02313 *urgentmsgs += tmpurgent;
02314 }
02315 }
02316 }
02317 return 0;
02318 }
02319 if (context) {
02320 *context = '\0';
02321 mailboxnc = tmp;
02322 context++;
02323 } else {
02324 context = "default";
02325 mailboxnc = (char *) mailbox_context;
02326 }
02327
02328 if (newmsgs) {
02329 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02330 if (!vmu) {
02331 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02332 return -1;
02333 }
02334 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02335 return -1;
02336 }
02337 }
02338 if (oldmsgs) {
02339 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02340 return -1;
02341 }
02342 }
02343 if (urgentmsgs) {
02344 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02345 return -1;
02346 }
02347 }
02348 return 0;
02349 }
02350
02351
02352
02353
02354
02355
02356
02357
02358
02359
02360
02361 static int has_voicemail(const char *mailbox, const char *folder)
02362 {
02363 char tmp[256], *tmp2, *box, *context;
02364 ast_copy_string(tmp, mailbox, sizeof(tmp));
02365 tmp2 = tmp;
02366 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02367 while ((box = strsep(&tmp2, ",&"))) {
02368 if (!ast_strlen_zero(box)) {
02369 if (has_voicemail(box, folder)) {
02370 return 1;
02371 }
02372 }
02373 }
02374 }
02375 if ((context = strchr(tmp, '@'))) {
02376 *context++ = '\0';
02377 } else {
02378 context = "default";
02379 }
02380 return __messagecount(context, tmp, folder) ? 1 : 0;
02381 }
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398 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)
02399 {
02400 struct vm_state *sendvms = NULL, *destvms = NULL;
02401 char messagestring[10];
02402 if (msgnum >= recip->maxmsg) {
02403 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02404 return -1;
02405 }
02406 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02407 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02408 return -1;
02409 }
02410 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02411 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02412 return -1;
02413 }
02414 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02415 ast_mutex_lock(&sendvms->lock);
02416 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02417 ast_mutex_unlock(&sendvms->lock);
02418 return 0;
02419 }
02420 ast_mutex_unlock(&sendvms->lock);
02421 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02422 return -1;
02423 }
02424
02425 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02426 {
02427 char tmp[256], *t = tmp;
02428 size_t left = sizeof(tmp);
02429
02430 if (box == OLD_FOLDER) {
02431 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02432 } else {
02433 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02434 }
02435
02436 if (box == NEW_FOLDER) {
02437 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02438 } else {
02439 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02440 }
02441
02442
02443 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02444
02445
02446 if (!ast_strlen_zero(authuser))
02447 ast_build_string(&t, &left, "/authuser=%s", authuser);
02448
02449
02450 if (!ast_strlen_zero(imapflags))
02451 ast_build_string(&t, &left, "/%s", imapflags);
02452
02453
02454 #if 1
02455 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02456 #else
02457 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02458 #endif
02459 if (box == NEW_FOLDER || box == OLD_FOLDER)
02460 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02461 else if (box == GREETINGS_FOLDER)
02462 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02463 else {
02464 if (!ast_strlen_zero(imapparentfolder)) {
02465
02466 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02467 } else {
02468 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02469 }
02470 }
02471 }
02472
02473 static int init_mailstream(struct vm_state *vms, int box)
02474 {
02475 MAILSTREAM *stream = NIL;
02476 long debug;
02477 char tmp[256];
02478
02479 if (!vms) {
02480 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02481 return -1;
02482 }
02483 if (option_debug > 2)
02484 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02485 if (vms->mailstream == NIL || !vms->mailstream) {
02486 if (option_debug)
02487 ast_log(LOG_DEBUG, "mailstream not set.\n");
02488 } else {
02489 stream = vms->mailstream;
02490 }
02491
02492 debug = NIL;
02493
02494 if (delimiter == '\0') {
02495 char *cp;
02496 #ifdef USE_SYSTEM_IMAP
02497 #include <imap/linkage.c>
02498 #elif defined(USE_SYSTEM_CCLIENT)
02499 #include <c-client/linkage.c>
02500 #else
02501 #include "linkage.c"
02502 #endif
02503
02504 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02505 ast_mutex_lock(&vms->lock);
02506 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02507 ast_mutex_unlock(&vms->lock);
02508 if (stream == NIL) {
02509 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02510 return -1;
02511 }
02512 get_mailbox_delimiter(stream);
02513
02514 for (cp = vms->imapfolder; *cp; cp++)
02515 if (*cp == '/')
02516 *cp = delimiter;
02517 }
02518
02519 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02520 if (option_debug > 2)
02521 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02522 ast_mutex_lock(&vms->lock);
02523 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02524 ast_mutex_unlock(&vms->lock);
02525 if (vms->mailstream == NIL) {
02526 return -1;
02527 } else {
02528 return 0;
02529 }
02530 }
02531
02532 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02533 {
02534 SEARCHPGM *pgm;
02535 SEARCHHEADER *hdr;
02536 int ret, urgent = 0;
02537
02538
02539 if (box == 11) {
02540 box = NEW_FOLDER;
02541 urgent = 1;
02542 }
02543
02544 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02545 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02546 vms->imapversion = vmu->imapversion;
02547 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02548
02549 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02550 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02551 return -1;
02552 }
02553
02554 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02555
02556
02557 if (box == 0) {
02558 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02559 check_quota(vms, (char *) mbox(vmu, box));
02560 }
02561
02562 ast_mutex_lock(&vms->lock);
02563 pgm = mail_newsearchpgm();
02564
02565
02566 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02567 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02568 pgm->header = hdr;
02569 pgm->deleted = 0;
02570 pgm->undeleted = 1;
02571
02572
02573 if (box == NEW_FOLDER && urgent == 1) {
02574 pgm->unseen = 1;
02575 pgm->seen = 0;
02576 pgm->flagged = 1;
02577 pgm->unflagged = 0;
02578 } else if (box == NEW_FOLDER && urgent == 0) {
02579 pgm->unseen = 1;
02580 pgm->seen = 0;
02581 pgm->flagged = 0;
02582 pgm->unflagged = 1;
02583 } else if (box == OLD_FOLDER) {
02584 pgm->seen = 1;
02585 pgm->unseen = 0;
02586 }
02587
02588 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02589
02590 vms->vmArrayIndex = 0;
02591 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02592 vms->lastmsg = vms->vmArrayIndex - 1;
02593 mail_free_searchpgm(&pgm);
02594
02595
02596
02597
02598 if (box == 0 && !vms->dh_arraysize) {
02599 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02600 }
02601 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02602 ast_mutex_unlock(&vms->lock);
02603 return -1;
02604 }
02605
02606 ast_mutex_unlock(&vms->lock);
02607 return 0;
02608 }
02609
02610 static void write_file(char *filename, char *buffer, unsigned long len)
02611 {
02612 FILE *output;
02613
02614 output = fopen (filename, "w");
02615 if (fwrite(buffer, len, 1, output) != 1) {
02616 if (ferror(output)) {
02617 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02618 }
02619 }
02620 fclose (output);
02621 }
02622
02623 static void update_messages_by_imapuser(const char *user, unsigned long number)
02624 {
02625 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02626
02627 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02628 return;
02629 }
02630
02631 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02632 vms->msgArray[vms->vmArrayIndex++] = number;
02633 }
02634
02635 void mm_searched(MAILSTREAM *stream, unsigned long number)
02636 {
02637 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02638
02639 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02640 return;
02641
02642 update_messages_by_imapuser(user, number);
02643 }
02644
02645 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02646 {
02647 struct ast_variable *var;
02648 struct ast_vm_user *vmu;
02649
02650 vmu = ast_calloc(1, sizeof *vmu);
02651 if (!vmu)
02652 return NULL;
02653 ast_set_flag(vmu, VM_ALLOCED);
02654 populate_defaults(vmu);
02655
02656 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02657 if (var) {
02658 apply_options_full(vmu, var);
02659 ast_variables_destroy(var);
02660 return vmu;
02661 } else {
02662 ast_free(vmu);
02663 return NULL;
02664 }
02665 }
02666
02667
02668
02669 void mm_exists(MAILSTREAM * stream, unsigned long number)
02670 {
02671
02672 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02673 if (number == 0) return;
02674 set_update(stream);
02675 }
02676
02677
02678 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02679 {
02680
02681 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02682 if (number == 0) return;
02683 set_update(stream);
02684 }
02685
02686
02687 void mm_flags(MAILSTREAM * stream, unsigned long number)
02688 {
02689
02690 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02691 if (number == 0) return;
02692 set_update(stream);
02693 }
02694
02695
02696 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02697 {
02698 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02699 mm_log (string, errflg);
02700 }
02701
02702
02703 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02704 {
02705 if (delimiter == '\0') {
02706 delimiter = delim;
02707 }
02708
02709 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02710 if (attributes & LATT_NOINFERIORS)
02711 ast_debug(5, "no inferiors\n");
02712 if (attributes & LATT_NOSELECT)
02713 ast_debug(5, "no select\n");
02714 if (attributes & LATT_MARKED)
02715 ast_debug(5, "marked\n");
02716 if (attributes & LATT_UNMARKED)
02717 ast_debug(5, "unmarked\n");
02718 }
02719
02720
02721 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02722 {
02723 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02724 if (attributes & LATT_NOINFERIORS)
02725 ast_debug(5, "no inferiors\n");
02726 if (attributes & LATT_NOSELECT)
02727 ast_debug(5, "no select\n");
02728 if (attributes & LATT_MARKED)
02729 ast_debug(5, "marked\n");
02730 if (attributes & LATT_UNMARKED)
02731 ast_debug(5, "unmarked\n");
02732 }
02733
02734
02735 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02736 {
02737 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02738 if (status->flags & SA_MESSAGES)
02739 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02740 if (status->flags & SA_RECENT)
02741 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02742 if (status->flags & SA_UNSEEN)
02743 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02744 if (status->flags & SA_UIDVALIDITY)
02745 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02746 if (status->flags & SA_UIDNEXT)
02747 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02748 ast_log(AST_LOG_NOTICE, "\n");
02749 }
02750
02751
02752 void mm_log(char *string, long errflg)
02753 {
02754 switch ((short) errflg) {
02755 case NIL:
02756 ast_debug(1, "IMAP Info: %s\n", string);
02757 break;
02758 case PARSE:
02759 case WARN:
02760 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02761 break;
02762 case ERROR:
02763 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02764 break;
02765 }
02766 }
02767
02768
02769 void mm_dlog(char *string)
02770 {
02771 ast_log(AST_LOG_NOTICE, "%s\n", string);
02772 }
02773
02774
02775 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02776 {
02777 struct ast_vm_user *vmu;
02778
02779 ast_debug(4, "Entering callback mm_login\n");
02780
02781 ast_copy_string(user, mb->user, MAILTMPLEN);
02782
02783
02784 if (!ast_strlen_zero(authpassword)) {
02785 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02786 } else {
02787 AST_LIST_TRAVERSE(&users, vmu, list) {
02788 if (!strcasecmp(mb->user, vmu->imapuser)) {
02789 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02790 break;
02791 }
02792 }
02793 if (!vmu) {
02794 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02795 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02796 free_user(vmu);
02797 }
02798 }
02799 }
02800 }
02801
02802
02803 void mm_critical(MAILSTREAM * stream)
02804 {
02805 }
02806
02807
02808 void mm_nocritical(MAILSTREAM * stream)
02809 {
02810 }
02811
02812
02813 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02814 {
02815 kill (getpid (), SIGSTOP);
02816 return NIL;
02817 }
02818
02819
02820 void mm_fatal(char *string)
02821 {
02822 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02823 }
02824
02825
02826 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02827 {
02828 struct vm_state *vms;
02829 char *mailbox = stream->mailbox, *user;
02830 char buf[1024] = "";
02831 unsigned long usage = 0, limit = 0;
02832
02833 while (pquota) {
02834 usage = pquota->usage;
02835 limit = pquota->limit;
02836 pquota = pquota->next;
02837 }
02838
02839 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)))) {
02840 ast_log(AST_LOG_ERROR, "No state found.\n");
02841 return;
02842 }
02843
02844 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02845
02846 vms->quota_usage = usage;
02847 vms->quota_limit = limit;
02848 }
02849
02850 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02851 {
02852 char *start, *eol_pnt;
02853 int taglen;
02854
02855 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02856 return NULL;
02857
02858 taglen = strlen(tag) + 1;
02859 if (taglen < 1)
02860 return NULL;
02861
02862 if (!(start = strstr(header, tag)))
02863 return NULL;
02864
02865
02866 memset(buf, 0, len);
02867
02868 ast_copy_string(buf, start+taglen, len);
02869 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02870 *eol_pnt = '\0';
02871 return buf;
02872 }
02873
02874 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02875 {
02876 char *start, *quote, *eol_pnt;
02877
02878 if (ast_strlen_zero(mailbox))
02879 return NULL;
02880
02881 if (!(start = strstr(mailbox, "/user=")))
02882 return NULL;
02883
02884 ast_copy_string(buf, start+6, len);
02885
02886 if (!(quote = strchr(buf, '\"'))) {
02887 if (!(eol_pnt = strchr(buf, '/')))
02888 eol_pnt = strchr(buf,'}');
02889 *eol_pnt = '\0';
02890 return buf;
02891 } else {
02892 eol_pnt = strchr(buf+1,'\"');
02893 *eol_pnt = '\0';
02894 return buf+1;
02895 }
02896 }
02897
02898 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02899 {
02900 struct vm_state *vms_p;
02901
02902 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02903 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02904 return vms_p;
02905 }
02906 if (option_debug > 4)
02907 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02908 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02909 return NULL;
02910 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02911 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02912 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02913 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02914 vms_p->mailstream = NIL;
02915 vms_p->imapversion = vmu->imapversion;
02916 if (option_debug > 4)
02917 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02918 vms_p->updated = 1;
02919
02920 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02921 init_vm_state(vms_p);
02922 vmstate_insert(vms_p);
02923 return vms_p;
02924 }
02925
02926 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02927 {
02928 struct vmstate *vlist = NULL;
02929
02930 if (interactive) {
02931 struct vm_state *vms;
02932 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02933 vms = pthread_getspecific(ts_vmstate.key);
02934 return vms;
02935 }
02936
02937 AST_LIST_LOCK(&vmstates);
02938 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02939 if (!vlist->vms) {
02940 ast_debug(3, "error: vms is NULL for %s\n", user);
02941 continue;
02942 }
02943 if (vlist->vms->imapversion != imapversion) {
02944 continue;
02945 }
02946 if (!vlist->vms->imapuser) {
02947 ast_debug(3, "error: imapuser is NULL for %s\n", user);
02948 continue;
02949 }
02950
02951 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
02952 AST_LIST_UNLOCK(&vmstates);
02953 return vlist->vms;
02954 }
02955 }
02956 AST_LIST_UNLOCK(&vmstates);
02957
02958 ast_debug(3, "%s not found in vmstates\n", user);
02959
02960 return NULL;
02961 }
02962
02963 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02964 {
02965
02966 struct vmstate *vlist = NULL;
02967 const char *local_context = S_OR(context, "default");
02968
02969 if (interactive) {
02970 struct vm_state *vms;
02971 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02972 vms = pthread_getspecific(ts_vmstate.key);
02973 return vms;
02974 }
02975
02976 AST_LIST_LOCK(&vmstates);
02977 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02978 if (!vlist->vms) {
02979 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
02980 continue;
02981 }
02982 if (vlist->vms->imapversion != imapversion) {
02983 continue;
02984 }
02985 if (!vlist->vms->username || !vlist->vms->context) {
02986 ast_debug(3, "error: username is NULL for %s\n", mailbox);
02987 continue;
02988 }
02989
02990 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);
02991
02992 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
02993 ast_debug(3, "Found it!\n");
02994 AST_LIST_UNLOCK(&vmstates);
02995 return vlist->vms;
02996 }
02997 }
02998 AST_LIST_UNLOCK(&vmstates);
02999
03000 ast_debug(3, "%s not found in vmstates\n", mailbox);
03001
03002 return NULL;
03003 }
03004
03005 static void vmstate_insert(struct vm_state *vms)
03006 {
03007 struct vmstate *v;
03008 struct vm_state *altvms;
03009
03010
03011
03012
03013 if (vms->interactive == 1) {
03014 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03015 if (altvms) {
03016 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03017 vms->newmessages = altvms->newmessages;
03018 vms->oldmessages = altvms->oldmessages;
03019 vms->vmArrayIndex = altvms->vmArrayIndex;
03020 vms->lastmsg = altvms->lastmsg;
03021 vms->curmsg = altvms->curmsg;
03022
03023 vms->persist_vms = altvms;
03024
03025 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03026 vms->mailstream = altvms->mailstream;
03027 #else
03028 vms->mailstream = NIL;
03029 #endif
03030 }
03031 return;
03032 }
03033
03034 if (!(v = ast_calloc(1, sizeof(*v))))
03035 return;
03036
03037 v->vms = vms;
03038
03039 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03040
03041 AST_LIST_LOCK(&vmstates);
03042 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03043 AST_LIST_UNLOCK(&vmstates);
03044 }
03045
03046 static void vmstate_delete(struct vm_state *vms)
03047 {
03048 struct vmstate *vc = NULL;
03049 struct vm_state *altvms = NULL;
03050
03051
03052
03053 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03054 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03055 altvms->newmessages = vms->newmessages;
03056 altvms->oldmessages = vms->oldmessages;
03057 altvms->updated = 1;
03058 vms->mailstream = mail_close(vms->mailstream);
03059
03060
03061 return;
03062 }
03063
03064 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03065
03066 AST_LIST_LOCK(&vmstates);
03067 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03068 if (vc->vms == vms) {
03069 AST_LIST_REMOVE_CURRENT(list);
03070 break;
03071 }
03072 }
03073 AST_LIST_TRAVERSE_SAFE_END
03074 AST_LIST_UNLOCK(&vmstates);
03075
03076 if (vc) {
03077 ast_mutex_destroy(&vc->vms->lock);
03078 ast_free(vc);
03079 }
03080 else
03081 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03082 }
03083
03084 static void set_update(MAILSTREAM * stream)
03085 {
03086 struct vm_state *vms;
03087 char *mailbox = stream->mailbox, *user;
03088 char buf[1024] = "";
03089
03090 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03091 if (user && option_debug > 2)
03092 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03093 return;
03094 }
03095
03096 ast_debug(3, "User %s mailbox set for update.\n", user);
03097
03098 vms->updated = 1;
03099 }
03100
03101 static void init_vm_state(struct vm_state *vms)
03102 {
03103 int x;
03104 vms->vmArrayIndex = 0;
03105 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03106 vms->msgArray[x] = 0;
03107 }
03108 ast_mutex_init(&vms->lock);
03109 }
03110
03111 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03112 {
03113 char *body_content;
03114 char *body_decoded;
03115 char *fn = is_intro ? vms->introfn : vms->fn;
03116 unsigned long len;
03117 unsigned long newlen;
03118 char filename[256];
03119
03120 if (!body || body == NIL)
03121 return -1;
03122
03123 ast_mutex_lock(&vms->lock);
03124 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03125 ast_mutex_unlock(&vms->lock);
03126 if (body_content != NIL) {
03127 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03128
03129 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03130
03131 if (!newlen) {
03132 return -1;
03133 }
03134 write_file(filename, (char *) body_decoded, newlen);
03135 } else {
03136 ast_debug(5, "Body of message is NULL.\n");
03137 return -1;
03138 }
03139 return 0;
03140 }
03141
03142
03143
03144
03145
03146
03147
03148
03149 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03150 char tmp[50];
03151 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03152 mail_list(stream, tmp, "*");
03153 }
03154
03155
03156
03157
03158
03159
03160
03161
03162 static void check_quota(struct vm_state *vms, char *mailbox) {
03163 ast_mutex_lock(&vms->lock);
03164 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03165 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03166 if (vms && vms->mailstream != NULL) {
03167 imap_getquotaroot(vms->mailstream, mailbox);
03168 } else {
03169 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03170 }
03171 ast_mutex_unlock(&vms->lock);
03172 }
03173
03174 #endif
03175
03176
03177
03178
03179
03180 static int vm_lock_path(const char *path)
03181 {
03182 switch (ast_lock_path(path)) {
03183 case AST_LOCK_TIMEOUT:
03184 return -1;
03185 default:
03186 return 0;
03187 }
03188 }
03189
03190
03191 #ifdef ODBC_STORAGE
03192 struct generic_prepare_struct {
03193 char *sql;
03194 int argc;
03195 char **argv;
03196 };
03197
03198 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03199 {
03200 struct generic_prepare_struct *gps = data;
03201 int res, i;
03202 SQLHSTMT stmt;
03203
03204 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03205 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03206 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03207 return NULL;
03208 }
03209 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03210 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03211 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03212 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03213 return NULL;
03214 }
03215 for (i = 0; i < gps->argc; i++)
03216 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03217
03218 return stmt;
03219 }
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235 static int retrieve_file(char *dir, int msgnum)
03236 {
03237 int x = 0;
03238 int res;
03239 int fd = -1;
03240 size_t fdlen = 0;
03241 void *fdm = MAP_FAILED;
03242 SQLSMALLINT colcount = 0;
03243 SQLHSTMT stmt;
03244 char sql[PATH_MAX];
03245 char fmt[80]="";
03246 char *c;
03247 char coltitle[256];
03248 SQLSMALLINT collen;
03249 SQLSMALLINT datatype;
03250 SQLSMALLINT decimaldigits;
03251 SQLSMALLINT nullable;
03252 SQLULEN colsize;
03253 SQLLEN colsize2;
03254 FILE *f = NULL;
03255 char rowdata[80];
03256 char fn[PATH_MAX];
03257 char full_fn[PATH_MAX];
03258 char msgnums[80];
03259 char *argv[] = { dir, msgnums };
03260 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03261
03262 struct odbc_obj *obj;
03263 obj = ast_odbc_request_obj(odbc_database, 0);
03264 if (obj) {
03265 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03266 c = strchr(fmt, '|');
03267 if (c)
03268 *c = '\0';
03269 if (!strcasecmp(fmt, "wav49"))
03270 strcpy(fmt, "WAV");
03271 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03272 if (msgnum > -1)
03273 make_file(fn, sizeof(fn), dir, msgnum);
03274 else
03275 ast_copy_string(fn, dir, sizeof(fn));
03276
03277
03278 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03279
03280 if (!(f = fopen(full_fn, "w+"))) {
03281 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03282 goto yuck;
03283 }
03284
03285 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03286 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03287 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03288 if (!stmt) {
03289 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03290 ast_odbc_release_obj(obj);
03291 goto yuck;
03292 }
03293 res = SQLFetch(stmt);
03294 if (res == SQL_NO_DATA) {
03295 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03296 ast_odbc_release_obj(obj);
03297 goto yuck;
03298 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03299 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03300 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03301 ast_odbc_release_obj(obj);
03302 goto yuck;
03303 }
03304 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03305 if (fd < 0) {
03306 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03307 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03308 ast_odbc_release_obj(obj);
03309 goto yuck;
03310 }
03311 res = SQLNumResultCols(stmt, &colcount);
03312 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03313 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03314 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03315 ast_odbc_release_obj(obj);
03316 goto yuck;
03317 }
03318 if (f)
03319 fprintf(f, "[message]\n");
03320 for (x = 0; x < colcount; x++) {
03321 rowdata[0] = '\0';
03322 collen = sizeof(coltitle);
03323 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03324 &datatype, &colsize, &decimaldigits, &nullable);
03325 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03326 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03327 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03328 ast_odbc_release_obj(obj);
03329 goto yuck;
03330 }
03331 if (!strcasecmp(coltitle, "recording")) {
03332 off_t offset;
03333 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03334 fdlen = colsize2;
03335 if (fd > -1) {
03336 char tmp[1]="";
03337 lseek(fd, fdlen - 1, SEEK_SET);
03338 if (write(fd, tmp, 1) != 1) {
03339 close(fd);
03340 fd = -1;
03341 continue;
03342 }
03343
03344 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03345 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03346 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03347 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03348 ast_odbc_release_obj(obj);
03349 goto yuck;
03350 } else {
03351 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03352 munmap(fdm, CHUNKSIZE);
03353 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03354 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03355 unlink(full_fn);
03356 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03357 ast_odbc_release_obj(obj);
03358 goto yuck;
03359 }
03360 }
03361 }
03362 if (truncate(full_fn, fdlen) < 0) {
03363 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03364 }
03365 }
03366 } else {
03367 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03368 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03369 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03370 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03371 ast_odbc_release_obj(obj);
03372 goto yuck;
03373 }
03374 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03375 fprintf(f, "%s=%s\n", coltitle, rowdata);
03376 }
03377 }
03378 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03379 ast_odbc_release_obj(obj);
03380 } else
03381 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03382 yuck:
03383 if (f)
03384 fclose(f);
03385 if (fd > -1)
03386 close(fd);
03387 return x - 1;
03388 }
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03401 {
03402 int x = 0;
03403 int res;
03404 SQLHSTMT stmt;
03405 char sql[PATH_MAX];
03406 char rowdata[20];
03407 char *argv[] = { dir };
03408 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03409
03410 struct odbc_obj *obj;
03411 obj = ast_odbc_request_obj(odbc_database, 0);
03412 if (obj) {
03413 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03414 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03415 if (!stmt) {
03416 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03417 ast_odbc_release_obj(obj);
03418 goto yuck;
03419 }
03420 res = SQLFetch(stmt);
03421 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03422 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03423 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03424 ast_odbc_release_obj(obj);
03425 goto yuck;
03426 }
03427 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03428 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03429 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03430 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03431 ast_odbc_release_obj(obj);
03432 goto yuck;
03433 }
03434 if (sscanf(rowdata, "%30d", &x) != 1)
03435 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03436 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03437 ast_odbc_release_obj(obj);
03438 } else
03439 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03440 yuck:
03441 return x - 1;
03442 }
03443
03444
03445
03446
03447
03448
03449
03450
03451
03452
03453 static int message_exists(char *dir, int msgnum)
03454 {
03455 int x = 0;
03456 int res;
03457 SQLHSTMT stmt;
03458 char sql[PATH_MAX];
03459 char rowdata[20];
03460 char msgnums[20];
03461 char *argv[] = { dir, msgnums };
03462 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03463
03464 struct odbc_obj *obj;
03465 obj = ast_odbc_request_obj(odbc_database, 0);
03466 if (obj) {
03467 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03468 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03469 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03470 if (!stmt) {
03471 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03472 ast_odbc_release_obj(obj);
03473 goto yuck;
03474 }
03475 res = SQLFetch(stmt);
03476 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03477 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03478 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03479 ast_odbc_release_obj(obj);
03480 goto yuck;
03481 }
03482 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03483 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03484 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03485 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03486 ast_odbc_release_obj(obj);
03487 goto yuck;
03488 }
03489 if (sscanf(rowdata, "%30d", &x) != 1)
03490 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03491 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03492 ast_odbc_release_obj(obj);
03493 } else
03494 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03495 yuck:
03496 return x;
03497 }
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511 static int count_messages(struct ast_vm_user *vmu, char *dir)
03512 {
03513 return last_message_index(vmu, dir) + 1;
03514 }
03515
03516
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526 static void delete_file(const char *sdir, int smsg)
03527 {
03528 SQLHSTMT stmt;
03529 char sql[PATH_MAX];
03530 char msgnums[20];
03531 char *argv[] = { NULL, msgnums };
03532 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03533 struct odbc_obj *obj;
03534
03535 argv[0] = ast_strdupa(sdir);
03536
03537 obj = ast_odbc_request_obj(odbc_database, 0);
03538 if (obj) {
03539 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03540 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03541 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03542 if (!stmt)
03543 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03544 else
03545 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03546 ast_odbc_release_obj(obj);
03547 } else
03548 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03549 return;
03550 }
03551
03552
03553
03554
03555
03556
03557
03558
03559
03560
03561
03562
03563 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03564 {
03565 SQLHSTMT stmt;
03566 char sql[512];
03567 char msgnums[20];
03568 char msgnumd[20];
03569 struct odbc_obj *obj;
03570 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03571 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03572
03573 delete_file(ddir, dmsg);
03574 obj = ast_odbc_request_obj(odbc_database, 0);
03575 if (obj) {
03576 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03577 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03578 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);
03579 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03580 if (!stmt)
03581 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03582 else
03583 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03584 ast_odbc_release_obj(obj);
03585 } else
03586 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03587 return;
03588 }
03589
03590 struct insert_data {
03591 char *sql;
03592 const char *dir;
03593 const char *msgnums;
03594 void *data;
03595 SQLLEN datalen;
03596 SQLLEN indlen;
03597 const char *context;
03598 const char *macrocontext;
03599 const char *callerid;
03600 const char *origtime;
03601 const char *duration;
03602 const char *mailboxuser;
03603 const char *mailboxcontext;
03604 const char *category;
03605 const char *flag;
03606 };
03607
03608 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03609 {
03610 struct insert_data *data = vdata;
03611 int res;
03612 SQLHSTMT stmt;
03613
03614 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03615 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03616 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03617 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03618 return NULL;
03619 }
03620
03621 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03622 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03623 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03624 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03625 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03626 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03627 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03628 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03629 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03630 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03631 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03632 if (!ast_strlen_zero(data->category)) {
03633 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03634 }
03635 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03636 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03637 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03638 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03639 return NULL;
03640 }
03641
03642 return stmt;
03643 }
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03659 {
03660 int res = 0;
03661 int fd = -1;
03662 void *fdm = MAP_FAILED;
03663 size_t fdlen = -1;
03664 SQLHSTMT stmt;
03665 char sql[PATH_MAX];
03666 char msgnums[20];
03667 char fn[PATH_MAX];
03668 char full_fn[PATH_MAX];
03669 char fmt[80]="";
03670 char *c;
03671 struct ast_config *cfg = NULL;
03672 struct odbc_obj *obj;
03673 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03674 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03675 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03676
03677 delete_file(dir, msgnum);
03678 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03679 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03680 return -1;
03681 }
03682
03683 do {
03684 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03685 c = strchr(fmt, '|');
03686 if (c)
03687 *c = '\0';
03688 if (!strcasecmp(fmt, "wav49"))
03689 strcpy(fmt, "WAV");
03690 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03691 if (msgnum > -1)
03692 make_file(fn, sizeof(fn), dir, msgnum);
03693 else
03694 ast_copy_string(fn, dir, sizeof(fn));
03695 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03696 cfg = ast_config_load(full_fn, config_flags);
03697 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03698 fd = open(full_fn, O_RDWR);
03699 if (fd < 0) {
03700 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03701 res = -1;
03702 break;
03703 }
03704 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03705 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03706 idata.context = "";
03707 }
03708 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03709 idata.macrocontext = "";
03710 }
03711 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03712 idata.callerid = "";
03713 }
03714 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03715 idata.origtime = "";
03716 }
03717 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03718 idata.duration = "";
03719 }
03720 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03721 idata.category = "";
03722 }
03723 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03724 idata.flag = "";
03725 }
03726 }
03727 fdlen = lseek(fd, 0, SEEK_END);
03728 lseek(fd, 0, SEEK_SET);
03729 printf("Length is %zd\n", fdlen);
03730 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03731 if (fdm == MAP_FAILED) {
03732 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03733 res = -1;
03734 break;
03735 }
03736 idata.data = fdm;
03737 idata.datalen = idata.indlen = fdlen;
03738
03739 if (!ast_strlen_zero(idata.category))
03740 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03741 else
03742 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03743
03744 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03745 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03746 } else {
03747 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03748 res = -1;
03749 }
03750 } while (0);
03751 if (obj) {
03752 ast_odbc_release_obj(obj);
03753 }
03754 if (cfg)
03755 ast_config_destroy(cfg);
03756 if (fdm != MAP_FAILED)
03757 munmap(fdm, fdlen);
03758 if (fd > -1)
03759 close(fd);
03760 return res;
03761 }
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03777 {
03778 SQLHSTMT stmt;
03779 char sql[PATH_MAX];
03780 char msgnums[20];
03781 char msgnumd[20];
03782 struct odbc_obj *obj;
03783 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03784 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03785
03786 delete_file(ddir, dmsg);
03787 obj = ast_odbc_request_obj(odbc_database, 0);
03788 if (obj) {
03789 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03790 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03791 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03792 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03793 if (!stmt)
03794 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03795 else
03796 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03797 ast_odbc_release_obj(obj);
03798 } else
03799 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03800 return;
03801 }
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814 static int remove_file(char *dir, int msgnum)
03815 {
03816 char fn[PATH_MAX];
03817 char full_fn[PATH_MAX];
03818 char msgnums[80];
03819
03820 if (msgnum > -1) {
03821 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03822 make_file(fn, sizeof(fn), dir, msgnum);
03823 } else
03824 ast_copy_string(fn, dir, sizeof(fn));
03825 ast_filedelete(fn, NULL);
03826 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03827 unlink(full_fn);
03828 return 0;
03829 }
03830 #else
03831 #ifndef IMAP_STORAGE
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841 static int count_messages(struct ast_vm_user *vmu, char *dir)
03842 {
03843
03844 int vmcount = 0;
03845 DIR *vmdir = NULL;
03846 struct dirent *vment = NULL;
03847
03848 if (vm_lock_path(dir))
03849 return ERROR_LOCK_PATH;
03850
03851 if ((vmdir = opendir(dir))) {
03852 while ((vment = readdir(vmdir))) {
03853 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03854 vmcount++;
03855 }
03856 }
03857 closedir(vmdir);
03858 }
03859 ast_unlock_path(dir);
03860
03861 return vmcount;
03862 }
03863
03864
03865
03866
03867
03868
03869
03870
03871 static void rename_file(char *sfn, char *dfn)
03872 {
03873 char stxt[PATH_MAX];
03874 char dtxt[PATH_MAX];
03875 ast_filerename(sfn, dfn, NULL);
03876 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03877 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03878 if (ast_check_realtime("voicemail_data")) {
03879 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03880 }
03881 rename(stxt, dtxt);
03882 }
03883
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03896 {
03897 int x;
03898 unsigned char map[MAXMSGLIMIT] = "";
03899 DIR *msgdir;
03900 struct dirent *msgdirent;
03901 int msgdirint;
03902
03903
03904
03905
03906
03907 if (!(msgdir = opendir(dir))) {
03908 return -1;
03909 }
03910
03911 while ((msgdirent = readdir(msgdir))) {
03912 if (sscanf(msgdirent->d_name, "msg%30d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03913 map[msgdirint] = 1;
03914 }
03915 closedir(msgdir);
03916
03917 for (x = 0; x < vmu->maxmsg; x++) {
03918 if (map[x] == 0)
03919 break;
03920 }
03921
03922 return x - 1;
03923 }
03924
03925 #endif
03926 #endif
03927 #ifndef IMAP_STORAGE
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938 static int copy(char *infile, char *outfile)
03939 {
03940 int ifd;
03941 int ofd;
03942 int res;
03943 int len;
03944 char buf[4096];
03945
03946 #ifdef HARDLINK_WHEN_POSSIBLE
03947
03948 if (link(infile, outfile)) {
03949 #endif
03950 if ((ifd = open(infile, O_RDONLY)) < 0) {
03951 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03952 return -1;
03953 }
03954 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03955 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03956 close(ifd);
03957 return -1;
03958 }
03959 do {
03960 len = read(ifd, buf, sizeof(buf));
03961 if (len < 0) {
03962 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03963 close(ifd);
03964 close(ofd);
03965 unlink(outfile);
03966 }
03967 if (len) {
03968 res = write(ofd, buf, len);
03969 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03970 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03971 close(ifd);
03972 close(ofd);
03973 unlink(outfile);
03974 }
03975 }
03976 } while (len);
03977 close(ifd);
03978 close(ofd);
03979 return 0;
03980 #ifdef HARDLINK_WHEN_POSSIBLE
03981 } else {
03982
03983 return 0;
03984 }
03985 #endif
03986 }
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997 static void copy_plain_file(char *frompath, char *topath)
03998 {
03999 char frompath2[PATH_MAX], topath2[PATH_MAX];
04000 struct ast_variable *tmp,*var = NULL;
04001 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04002 ast_filecopy(frompath, topath, NULL);
04003 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04004 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04005 if (ast_check_realtime("voicemail_data")) {
04006 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04007
04008 for (tmp = var; tmp; tmp = tmp->next) {
04009 if (!strcasecmp(tmp->name, "origmailbox")) {
04010 origmailbox = tmp->value;
04011 } else if (!strcasecmp(tmp->name, "context")) {
04012 context = tmp->value;
04013 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04014 macrocontext = tmp->value;
04015 } else if (!strcasecmp(tmp->name, "exten")) {
04016 exten = tmp->value;
04017 } else if (!strcasecmp(tmp->name, "priority")) {
04018 priority = tmp->value;
04019 } else if (!strcasecmp(tmp->name, "callerchan")) {
04020 callerchan = tmp->value;
04021 } else if (!strcasecmp(tmp->name, "callerid")) {
04022 callerid = tmp->value;
04023 } else if (!strcasecmp(tmp->name, "origdate")) {
04024 origdate = tmp->value;
04025 } else if (!strcasecmp(tmp->name, "origtime")) {
04026 origtime = tmp->value;
04027 } else if (!strcasecmp(tmp->name, "category")) {
04028 category = tmp->value;
04029 } else if (!strcasecmp(tmp->name, "duration")) {
04030 duration = tmp->value;
04031 }
04032 }
04033 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);
04034 }
04035 copy(frompath2, topath2);
04036 ast_variables_destroy(var);
04037 }
04038 #endif
04039
04040
04041
04042
04043
04044
04045
04046
04047
04048 static int vm_delete(char *file)
04049 {
04050 char *txt;
04051 int txtsize = 0;
04052
04053 txtsize = (strlen(file) + 5)*sizeof(char);
04054 txt = alloca(txtsize);
04055
04056
04057
04058 if (ast_check_realtime("voicemail_data")) {
04059 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04060 }
04061 snprintf(txt, txtsize, "%s.txt", file);
04062 unlink(txt);
04063 return ast_filedelete(file, NULL);
04064 }
04065
04066
04067
04068
04069 static int inbuf(struct baseio *bio, FILE *fi)
04070 {
04071 int l;
04072
04073 if (bio->ateof)
04074 return 0;
04075
04076 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04077 if (ferror(fi))
04078 return -1;
04079
04080 bio->ateof = 1;
04081 return 0;
04082 }
04083
04084 bio->iolen = l;
04085 bio->iocp = 0;
04086
04087 return 1;
04088 }
04089
04090
04091
04092
04093 static int inchar(struct baseio *bio, FILE *fi)
04094 {
04095 if (bio->iocp>=bio->iolen) {
04096 if (!inbuf(bio, fi))
04097 return EOF;
04098 }
04099
04100 return bio->iobuf[bio->iocp++];
04101 }
04102
04103
04104
04105
04106 static int ochar(struct baseio *bio, int c, FILE *so)
04107 {
04108 if (bio->linelength >= BASELINELEN) {
04109 if (fputs(ENDL, so) == EOF) {
04110 return -1;
04111 }
04112
04113 bio->linelength = 0;
04114 }
04115
04116 if (putc(((unsigned char) c), so) == EOF) {
04117 return -1;
04118 }
04119
04120 bio->linelength++;
04121
04122 return 1;
04123 }
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134 static int base_encode(char *filename, FILE *so)
04135 {
04136 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04137 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04138 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04139 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04140 int i, hiteof = 0;
04141 FILE *fi;
04142 struct baseio bio;
04143
04144 memset(&bio, 0, sizeof(bio));
04145 bio.iocp = BASEMAXINLINE;
04146
04147 if (!(fi = fopen(filename, "rb"))) {
04148 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04149 return -1;
04150 }
04151
04152 while (!hiteof){
04153 unsigned char igroup[3], ogroup[4];
04154 int c, n;
04155
04156 memset(igroup, 0, sizeof(igroup));
04157
04158 for (n = 0; n < 3; n++) {
04159 if ((c = inchar(&bio, fi)) == EOF) {
04160 hiteof = 1;
04161 break;
04162 }
04163
04164 igroup[n] = (unsigned char) c;
04165 }
04166
04167 if (n > 0) {
04168 ogroup[0]= dtable[igroup[0] >> 2];
04169 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04170 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04171 ogroup[3]= dtable[igroup[2] & 0x3F];
04172
04173 if (n < 3) {
04174 ogroup[3] = '=';
04175
04176 if (n < 2)
04177 ogroup[2] = '=';
04178 }
04179
04180 for (i = 0; i < 4; i++)
04181 ochar(&bio, ogroup[i], so);
04182 }
04183 }
04184
04185 fclose(fi);
04186
04187 if (fputs(ENDL, so) == EOF) {
04188 return 0;
04189 }
04190
04191 return 1;
04192 }
04193
04194 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)
04195 {
04196 char callerid[256];
04197 char num[12];
04198 char fromdir[256], fromfile[256];
04199 struct ast_config *msg_cfg;
04200 const char *origcallerid, *origtime;
04201 char origcidname[80], origcidnum[80], origdate[80];
04202 int inttime;
04203 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04204
04205
04206 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04207 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04208 snprintf(num, sizeof(num), "%d", msgnum);
04209 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04210 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04211 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04212 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04213 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04214 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04215 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04216 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04217 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04218 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04219
04220
04221 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04222 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04223 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04224 strcat(fromfile, ".txt");
04225 }
04226 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04227 if (option_debug > 0) {
04228 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04229 }
04230 return;
04231 }
04232
04233 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04234 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04235 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04236 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04237 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04238 }
04239
04240 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04241 struct timeval tv = { inttime, };
04242 struct ast_tm tm;
04243 ast_localtime(&tv, &tm, NULL);
04244 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04245 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04246 }
04247 ast_config_destroy(msg_cfg);
04248 }
04249
04250
04251
04252
04253
04254
04255
04256
04257
04258 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04259 {
04260 const char *ptr;
04261
04262
04263 ast_str_set(buf, maxlen, "\"");
04264 for (ptr = from; *ptr; ptr++) {
04265 if (*ptr == '"' || *ptr == '\\') {
04266 ast_str_append(buf, maxlen, "\\%c", *ptr);
04267 } else {
04268 ast_str_append(buf, maxlen, "%c", *ptr);
04269 }
04270 }
04271 ast_str_append(buf, maxlen, "\"");
04272
04273 return ast_str_buffer(*buf);
04274 }
04275
04276
04277
04278
04279
04280 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04281 {
04282 const struct vm_zone *z = NULL;
04283 struct timeval t = ast_tvnow();
04284
04285
04286 if (!ast_strlen_zero(vmu->zonetag)) {
04287
04288 AST_LIST_LOCK(&zones);
04289 AST_LIST_TRAVERSE(&zones, z, list) {
04290 if (!strcmp(z->name, vmu->zonetag))
04291 break;
04292 }
04293 AST_LIST_UNLOCK(&zones);
04294 }
04295 ast_localtime(&t, tm, z ? z->timezone : NULL);
04296 return tm;
04297 }
04298
04299
04300
04301
04302
04303 static int check_mime(const char *str)
04304 {
04305 for (; *str; str++) {
04306 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04307 return 1;
04308 }
04309 }
04310 return 0;
04311 }
04312
04313
04314
04315
04316
04317
04318
04319
04320
04321
04322
04323
04324
04325
04326
04327
04328
04329
04330 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04331 {
04332 struct ast_str *tmp = ast_str_alloca(80);
04333 int first_section = 1;
04334
04335 ast_str_reset(*end);
04336 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04337 for (; *start; start++) {
04338 int need_encoding = 0;
04339 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04340 need_encoding = 1;
04341 }
04342 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04343 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04344 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04345 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04346
04347 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04348 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04349 first_section = 0;
04350 }
04351 if (need_encoding && *start == ' ') {
04352 ast_str_append(&tmp, -1, "_");
04353 } else if (need_encoding) {
04354 ast_str_append(&tmp, -1, "=%hhX", *start);
04355 } else {
04356 ast_str_append(&tmp, -1, "%c", *start);
04357 }
04358 }
04359 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04360 return ast_str_buffer(*end);
04361 }
04362
04363
04364
04365
04366
04367
04368
04369
04370
04371
04372
04373
04374
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386 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)
04387 {
04388 char date[256];
04389 char host[MAXHOSTNAMELEN] = "";
04390 char who[256];
04391 char bound[256];
04392 char dur[256];
04393 struct ast_tm tm;
04394 char enc_cidnum[256] = "", enc_cidname[256] = "";
04395 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04396 char *greeting_attachment;
04397 char filename[256];
04398
04399 if (!str1 || !str2) {
04400 ast_free(str1);
04401 ast_free(str2);
04402 return;
04403 }
04404
04405 if (cidnum) {
04406 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04407 }
04408 if (cidname) {
04409 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04410 }
04411 gethostname(host, sizeof(host) - 1);
04412
04413 if (strchr(srcemail, '@')) {
04414 ast_copy_string(who, srcemail, sizeof(who));
04415 } else {
04416 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04417 }
04418
04419 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04420 if (greeting_attachment) {
04421 *greeting_attachment++ = '\0';
04422 }
04423
04424 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04425 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04426 fprintf(p, "Date: %s" ENDL, date);
04427
04428
04429 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04430
04431 if (!ast_strlen_zero(fromstring)) {
04432 struct ast_channel *ast;
04433 if ((ast = ast_dummy_channel_alloc())) {
04434 char *ptr;
04435 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04436 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04437
04438 if (check_mime(ast_str_buffer(str1))) {
04439 int first_line = 1;
04440 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04441 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04442 *ptr = '\0';
04443 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04444 first_line = 0;
04445
04446 ast_str_set(&str2, 0, "%s", ptr + 1);
04447 }
04448 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04449 } else {
04450 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04451 }
04452 ast = ast_channel_release(ast);
04453 } else {
04454 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04455 }
04456 } else {
04457 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04458 }
04459
04460 if (check_mime(vmu->fullname)) {
04461 int first_line = 1;
04462 char *ptr;
04463 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04464 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04465 *ptr = '\0';
04466 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04467 first_line = 0;
04468
04469 ast_str_set(&str2, 0, "%s", ptr + 1);
04470 }
04471 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04472 } else {
04473 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04474 }
04475
04476 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04477 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04478 struct ast_channel *ast;
04479 if ((ast = ast_dummy_channel_alloc())) {
04480 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04481 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04482 if (check_mime(ast_str_buffer(str1))) {
04483 int first_line = 1;
04484 char *ptr;
04485 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04486 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04487 *ptr = '\0';
04488 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04489 first_line = 0;
04490
04491 ast_str_set(&str2, 0, "%s", ptr + 1);
04492 }
04493 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04494 } else {
04495 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04496 }
04497 ast = ast_channel_release(ast);
04498 } else {
04499 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04500 }
04501 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04502 if (ast_strlen_zero(flag)) {
04503 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04504 } else {
04505 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04506 }
04507 } else {
04508 if (ast_strlen_zero(flag)) {
04509 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04510 } else {
04511 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04512 }
04513 }
04514
04515 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04516 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04517 if (imap) {
04518
04519 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04520
04521 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04522 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04523 #ifdef IMAP_STORAGE
04524 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04525 #else
04526 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04527 #endif
04528
04529 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04530 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04531 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04532 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04533 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04534 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04535 if (!ast_strlen_zero(category)) {
04536 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04537 } else {
04538 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04539 }
04540 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04541 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04542 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04543 }
04544 if (!ast_strlen_zero(cidnum)) {
04545 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04546 }
04547 if (!ast_strlen_zero(cidname)) {
04548 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04549 }
04550 fprintf(p, "MIME-Version: 1.0" ENDL);
04551 if (attach_user_voicemail) {
04552
04553 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04554 (int) getpid(), (unsigned int) ast_random());
04555
04556 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04557 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04558 fprintf(p, "--%s" ENDL, bound);
04559 }
04560 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04561 if (emailbody || vmu->emailbody) {
04562 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04563 struct ast_channel *ast;
04564 if ((ast = ast_dummy_channel_alloc())) {
04565 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04566 ast_str_substitute_variables(&str1, 0, ast, e_body);
04567 #ifdef IMAP_STORAGE
04568 {
04569
04570 char *line = ast_str_buffer(str1), *next;
04571 do {
04572
04573 if ((next = strchr(line, '\n'))) {
04574 *next++ = '\0';
04575 }
04576 fprintf(p, "%s" ENDL, line);
04577 line = next;
04578 } while (!ast_strlen_zero(line));
04579 }
04580 #else
04581 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04582 #endif
04583 ast = ast_channel_release(ast);
04584 } else {
04585 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04586 }
04587 } else if (msgnum > -1) {
04588 if (strcmp(vmu->mailbox, mailbox)) {
04589
04590 struct ast_config *msg_cfg;
04591 const char *v;
04592 int inttime;
04593 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04594 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04595
04596 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04597 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04598 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04599 strcat(fromfile, ".txt");
04600 }
04601 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04602 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04603 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04604 }
04605
04606
04607
04608 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04609 struct timeval tv = { inttime, };
04610 struct ast_tm tm;
04611 ast_localtime(&tv, &tm, NULL);
04612 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04613 }
04614 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04615 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04616 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04617 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04618 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04619 date, origcallerid, origdate);
04620 ast_config_destroy(msg_cfg);
04621 } else {
04622 goto plain_message;
04623 }
04624 } else {
04625 plain_message:
04626 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04627 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04628 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04629 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04630 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04631 }
04632 } else {
04633 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04634 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04635 }
04636
04637 if (imap || attach_user_voicemail) {
04638 if (!ast_strlen_zero(attach2)) {
04639 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04640 ast_debug(5, "creating second attachment filename %s\n", filename);
04641 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04642 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04643 ast_debug(5, "creating attachment filename %s\n", filename);
04644 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04645 } else {
04646 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04647 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04648 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04649 }
04650 }
04651 ast_free(str1);
04652 ast_free(str2);
04653 }
04654
04655 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)
04656 {
04657 char tmpdir[256], newtmp[256];
04658 char fname[256];
04659 char tmpcmd[256];
04660 int tmpfd = -1;
04661
04662
04663 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04664
04665 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04666 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04667 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04668 tmpfd = mkstemp(newtmp);
04669 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04670 ast_debug(3, "newtmp: %s\n", newtmp);
04671 if (tmpfd > -1) {
04672 int soxstatus;
04673 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04674 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04675 attach = newtmp;
04676 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04677 } else {
04678 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04679 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04680 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04681 }
04682 }
04683 }
04684 fprintf(p, "--%s" ENDL, bound);
04685 if (msgnum > -1)
04686 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04687 else
04688 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04689 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04690 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04691 if (msgnum > -1)
04692 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04693 else
04694 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04695 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04696 base_encode(fname, p);
04697 if (last)
04698 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04699 if (tmpfd > -1) {
04700 unlink(fname);
04701 close(tmpfd);
04702 unlink(newtmp);
04703 }
04704 return 0;
04705 }
04706
04707 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)
04708 {
04709 FILE *p = NULL;
04710 char tmp[80] = "/tmp/astmail-XXXXXX";
04711 char tmp2[256];
04712 char *stringp;
04713
04714 if (vmu && ast_strlen_zero(vmu->email)) {
04715 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04716 return(0);
04717 }
04718
04719
04720 format = ast_strdupa(format);
04721 stringp = format;
04722 strsep(&stringp, "|");
04723
04724 if (!strcmp(format, "wav49"))
04725 format = "WAV";
04726 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));
04727
04728
04729 if ((p = vm_mkftemp(tmp)) == NULL) {
04730 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04731 return -1;
04732 } else {
04733 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04734 fclose(p);
04735 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04736 ast_safe_system(tmp2);
04737 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04738 }
04739 return 0;
04740 }
04741
04742 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)
04743 {
04744 char enc_cidnum[256], enc_cidname[256];
04745 char date[256];
04746 char host[MAXHOSTNAMELEN] = "";
04747 char who[256];
04748 char dur[PATH_MAX];
04749 char tmp[80] = "/tmp/astmail-XXXXXX";
04750 char tmp2[PATH_MAX];
04751 struct ast_tm tm;
04752 FILE *p;
04753 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04754
04755 if (!str1 || !str2) {
04756 ast_free(str1);
04757 ast_free(str2);
04758 return -1;
04759 }
04760
04761 if (cidnum) {
04762 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04763 }
04764 if (cidname) {
04765 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04766 }
04767
04768 if ((p = vm_mkftemp(tmp)) == NULL) {
04769 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04770 ast_free(str1);
04771 ast_free(str2);
04772 return -1;
04773 }
04774 gethostname(host, sizeof(host)-1);
04775 if (strchr(srcemail, '@')) {
04776 ast_copy_string(who, srcemail, sizeof(who));
04777 } else {
04778 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04779 }
04780 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04781 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04782 fprintf(p, "Date: %s\n", date);
04783
04784
04785 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04786
04787 if (!ast_strlen_zero(pagerfromstring)) {
04788 struct ast_channel *ast;
04789 if ((ast = ast_dummy_channel_alloc())) {
04790 char *ptr;
04791 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04792 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04793
04794 if (check_mime(ast_str_buffer(str1))) {
04795 int first_line = 1;
04796 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04797 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04798 *ptr = '\0';
04799 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04800 first_line = 0;
04801
04802 ast_str_set(&str2, 0, "%s", ptr + 1);
04803 }
04804 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04805 } else {
04806 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04807 }
04808 ast = ast_channel_release(ast);
04809 } else {
04810 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04811 }
04812 } else {
04813 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04814 }
04815
04816 if (check_mime(vmu->fullname)) {
04817 int first_line = 1;
04818 char *ptr;
04819 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04820 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04821 *ptr = '\0';
04822 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04823 first_line = 0;
04824
04825 ast_str_set(&str2, 0, "%s", ptr + 1);
04826 }
04827 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04828 } else {
04829 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04830 }
04831
04832 if (!ast_strlen_zero(pagersubject)) {
04833 struct ast_channel *ast;
04834 if ((ast = ast_dummy_channel_alloc())) {
04835 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04836 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04837 if (check_mime(ast_str_buffer(str1))) {
04838 int first_line = 1;
04839 char *ptr;
04840 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04841 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04842 *ptr = '\0';
04843 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04844 first_line = 0;
04845
04846 ast_str_set(&str2, 0, "%s", ptr + 1);
04847 }
04848 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04849 } else {
04850 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04851 }
04852 ast = ast_channel_release(ast);
04853 } else {
04854 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04855 }
04856 } else {
04857 if (ast_strlen_zero(flag)) {
04858 fprintf(p, "Subject: New VM\n\n");
04859 } else {
04860 fprintf(p, "Subject: New %s VM\n\n", flag);
04861 }
04862 }
04863
04864 if (pagerbody) {
04865 struct ast_channel *ast;
04866 if ((ast = ast_dummy_channel_alloc())) {
04867 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04868 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
04869 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04870 ast = ast_channel_release(ast);
04871 } else {
04872 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04873 }
04874 } else {
04875 fprintf(p, "New %s long %s msg in box %s\n"
04876 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04877 }
04878
04879 fclose(p);
04880 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04881 ast_safe_system(tmp2);
04882 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04883 ast_free(str1);
04884 ast_free(str2);
04885 return 0;
04886 }
04887
04888
04889
04890
04891
04892
04893
04894
04895
04896
04897 static int get_date(char *s, int len)
04898 {
04899 struct ast_tm tm;
04900 struct timeval t = ast_tvnow();
04901
04902 ast_localtime(&t, &tm, "UTC");
04903
04904 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04905 }
04906
04907 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
04908 {
04909 int res;
04910 char fn[PATH_MAX];
04911 char dest[PATH_MAX];
04912
04913 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04914
04915 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04916 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04917 return -1;
04918 }
04919
04920 RETRIEVE(fn, -1, ext, context);
04921 if (ast_fileexists(fn, NULL, NULL) > 0) {
04922 res = ast_stream_and_wait(chan, fn, ecodes);
04923 if (res) {
04924 DISPOSE(fn, -1);
04925 return res;
04926 }
04927 } else {
04928
04929 DISPOSE(fn, -1);
04930 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04931 if (res)
04932 return res;
04933 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04934 if (res)
04935 return res;
04936 }
04937 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04938 return res;
04939 }
04940
04941 static void free_zone(struct vm_zone *z)
04942 {
04943 ast_free(z);
04944 }
04945
04946 #ifdef ODBC_STORAGE
04947 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04948 {
04949 int x = -1;
04950 int res;
04951 SQLHSTMT stmt = NULL;
04952 char sql[PATH_MAX];
04953 char rowdata[20];
04954 char tmp[PATH_MAX] = "";
04955 struct odbc_obj *obj = NULL;
04956 char *context;
04957 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04958
04959 if (newmsgs)
04960 *newmsgs = 0;
04961 if (oldmsgs)
04962 *oldmsgs = 0;
04963 if (urgentmsgs)
04964 *urgentmsgs = 0;
04965
04966
04967 if (ast_strlen_zero(mailbox))
04968 return 0;
04969
04970 ast_copy_string(tmp, mailbox, sizeof(tmp));
04971
04972 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
04973 int u, n, o;
04974 char *next, *remaining = tmp;
04975 while ((next = strsep(&remaining, " ,"))) {
04976 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
04977 return -1;
04978 }
04979 if (urgentmsgs) {
04980 *urgentmsgs += u;
04981 }
04982 if (newmsgs) {
04983 *newmsgs += n;
04984 }
04985 if (oldmsgs) {
04986 *oldmsgs += o;
04987 }
04988 }
04989 return 0;
04990 }
04991
04992 context = strchr(tmp, '@');
04993 if (context) {
04994 *context = '\0';
04995 context++;
04996 } else
04997 context = "default";
04998
04999 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05000 do {
05001 if (newmsgs) {
05002 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05003 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05004 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05005 break;
05006 }
05007 res = SQLFetch(stmt);
05008 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05009 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05010 break;
05011 }
05012 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05013 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05014 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05015 break;
05016 }
05017 *newmsgs = atoi(rowdata);
05018 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05019 }
05020
05021 if (oldmsgs) {
05022 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05023 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05024 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05025 break;
05026 }
05027 res = SQLFetch(stmt);
05028 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05029 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05030 break;
05031 }
05032 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05033 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05034 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05035 break;
05036 }
05037 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05038 *oldmsgs = atoi(rowdata);
05039 }
05040
05041 if (urgentmsgs) {
05042 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05043 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05044 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05045 break;
05046 }
05047 res = SQLFetch(stmt);
05048 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05049 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05050 break;
05051 }
05052 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05053 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05054 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05055 break;
05056 }
05057 *urgentmsgs = atoi(rowdata);
05058 }
05059
05060 x = 0;
05061 } while (0);
05062 } else {
05063 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05064 }
05065
05066 if (stmt) {
05067 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05068 }
05069 if (obj) {
05070 ast_odbc_release_obj(obj);
05071 }
05072
05073 return x;
05074 }
05075
05076
05077
05078
05079
05080
05081
05082
05083
05084
05085 static int messagecount(const char *context, const char *mailbox, const char *folder)
05086 {
05087 struct odbc_obj *obj = NULL;
05088 int nummsgs = 0;
05089 int res;
05090 SQLHSTMT stmt = NULL;
05091 char sql[PATH_MAX];
05092 char rowdata[20];
05093 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05094 if (!folder)
05095 folder = "INBOX";
05096
05097 if (ast_strlen_zero(mailbox))
05098 return 0;
05099
05100 obj = ast_odbc_request_obj(odbc_database, 0);
05101 if (obj) {
05102 if (!strcmp(folder, "INBOX")) {
05103 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);
05104 } else {
05105 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05106 }
05107 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05108 if (!stmt) {
05109 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05110 goto yuck;
05111 }
05112 res = SQLFetch(stmt);
05113 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05114 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05115 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05116 goto yuck;
05117 }
05118 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05119 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05120 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05121 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05122 goto yuck;
05123 }
05124 nummsgs = atoi(rowdata);
05125 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05126 } else
05127 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05128
05129 yuck:
05130 if (obj)
05131 ast_odbc_release_obj(obj);
05132 return nummsgs;
05133 }
05134
05135
05136
05137
05138
05139
05140
05141
05142
05143 static int has_voicemail(const char *mailbox, const char *folder)
05144 {
05145 char tmp[256], *tmp2 = tmp, *box, *context;
05146 ast_copy_string(tmp, mailbox, sizeof(tmp));
05147 while ((context = box = strsep(&tmp2, ",&"))) {
05148 strsep(&context, "@");
05149 if (ast_strlen_zero(context))
05150 context = "default";
05151 if (messagecount(context, box, folder))
05152 return 1;
05153 }
05154 return 0;
05155 }
05156 #endif
05157 #ifndef IMAP_STORAGE
05158
05159
05160
05161
05162
05163
05164
05165
05166
05167
05168
05169
05170
05171
05172
05173
05174 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)
05175 {
05176 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05177 const char *frombox = mbox(vmu, imbox);
05178 int recipmsgnum;
05179 int res = 0;
05180
05181 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05182
05183 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05184 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
05185 } else {
05186 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05187 }
05188
05189 if (!dir)
05190 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05191 else
05192 ast_copy_string(fromdir, dir, sizeof(fromdir));
05193
05194 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05195 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05196
05197 if (vm_lock_path(todir))
05198 return ERROR_LOCK_PATH;
05199
05200 recipmsgnum = last_message_index(recip, todir) + 1;
05201 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05202 make_file(topath, sizeof(topath), todir, recipmsgnum);
05203 #ifndef ODBC_STORAGE
05204 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05205 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05206 } else {
05207 #endif
05208
05209
05210
05211 copy_plain_file(frompath, topath);
05212 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05213 vm_delete(topath);
05214 #ifndef ODBC_STORAGE
05215 }
05216 #endif
05217 } else {
05218 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05219 res = -1;
05220 }
05221 ast_unlock_path(todir);
05222 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05223 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05224 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05225 flag);
05226
05227 return res;
05228 }
05229 #endif
05230 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05231
05232 static int messagecount(const char *context, const char *mailbox, const char *folder)
05233 {
05234 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05235 }
05236
05237 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05238 {
05239 DIR *dir;
05240 struct dirent *de;
05241 char fn[256];
05242 int ret = 0;
05243
05244
05245 if (ast_strlen_zero(mailbox))
05246 return 0;
05247
05248 if (ast_strlen_zero(folder))
05249 folder = "INBOX";
05250 if (ast_strlen_zero(context))
05251 context = "default";
05252
05253 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05254
05255 if (!(dir = opendir(fn)))
05256 return 0;
05257
05258 while ((de = readdir(dir))) {
05259 if (!strncasecmp(de->d_name, "msg", 3)) {
05260 if (shortcircuit) {
05261 ret = 1;
05262 break;
05263 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05264 ret++;
05265 }
05266 }
05267 }
05268
05269 closedir(dir);
05270
05271 return ret;
05272 }
05273
05274
05275
05276
05277
05278
05279
05280
05281
05282
05283 static int has_voicemail(const char *mailbox, const char *folder)
05284 {
05285 char tmp[256], *tmp2 = tmp, *box, *context;
05286 ast_copy_string(tmp, mailbox, sizeof(tmp));
05287 if (ast_strlen_zero(folder)) {
05288 folder = "INBOX";
05289 }
05290 while ((box = strsep(&tmp2, ",&"))) {
05291 if ((context = strchr(box, '@')))
05292 *context++ = '\0';
05293 else
05294 context = "default";
05295 if (__has_voicemail(context, box, folder, 1))
05296 return 1;
05297
05298 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05299 return 1;
05300 }
05301 }
05302 return 0;
05303 }
05304
05305
05306 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05307 {
05308 char tmp[256];
05309 char *context;
05310
05311
05312 if (ast_strlen_zero(mailbox))
05313 return 0;
05314
05315 if (newmsgs)
05316 *newmsgs = 0;
05317 if (oldmsgs)
05318 *oldmsgs = 0;
05319 if (urgentmsgs)
05320 *urgentmsgs = 0;
05321
05322 if (strchr(mailbox, ',')) {
05323 int tmpnew, tmpold, tmpurgent;
05324 char *mb, *cur;
05325
05326 ast_copy_string(tmp, mailbox, sizeof(tmp));
05327 mb = tmp;
05328 while ((cur = strsep(&mb, ", "))) {
05329 if (!ast_strlen_zero(cur)) {
05330 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05331 return -1;
05332 else {
05333 if (newmsgs)
05334 *newmsgs += tmpnew;
05335 if (oldmsgs)
05336 *oldmsgs += tmpold;
05337 if (urgentmsgs)
05338 *urgentmsgs += tmpurgent;
05339 }
05340 }
05341 }
05342 return 0;
05343 }
05344
05345 ast_copy_string(tmp, mailbox, sizeof(tmp));
05346
05347 if ((context = strchr(tmp, '@')))
05348 *context++ = '\0';
05349 else
05350 context = "default";
05351
05352 if (newmsgs)
05353 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05354 if (oldmsgs)
05355 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05356 if (urgentmsgs)
05357 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05358
05359 return 0;
05360 }
05361
05362 #endif
05363
05364
05365 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05366 {
05367 int urgentmsgs = 0;
05368 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05369 if (newmsgs) {
05370 *newmsgs += urgentmsgs;
05371 }
05372 return res;
05373 }
05374
05375 static void run_externnotify(char *context, char *extension, const char *flag)
05376 {
05377 char arguments[255];
05378 char ext_context[256] = "";
05379 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05380 struct ast_smdi_mwi_message *mwi_msg;
05381
05382 if (!ast_strlen_zero(context))
05383 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05384 else
05385 ast_copy_string(ext_context, extension, sizeof(ext_context));
05386
05387 if (smdi_iface) {
05388 if (ast_app_has_voicemail(ext_context, NULL))
05389 ast_smdi_mwi_set(smdi_iface, extension);
05390 else
05391 ast_smdi_mwi_unset(smdi_iface, extension);
05392
05393 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05394 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05395 if (!strncmp(mwi_msg->cause, "INV", 3))
05396 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05397 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05398 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05399 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05400 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05401 } else {
05402 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05403 }
05404 }
05405
05406 if (!ast_strlen_zero(externnotify)) {
05407 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05408 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05409 } else {
05410 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05411 ast_debug(1, "Executing %s\n", arguments);
05412 ast_safe_system(arguments);
05413 }
05414 }
05415 }
05416
05417
05418
05419
05420
05421
05422 struct leave_vm_options {
05423 unsigned int flags;
05424 signed char record_gain;
05425 char *exitcontext;
05426 };
05427
05428
05429
05430
05431
05432
05433
05434
05435
05436
05437
05438 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05439 {
05440 #ifdef IMAP_STORAGE
05441 int newmsgs, oldmsgs;
05442 #else
05443 char urgdir[PATH_MAX];
05444 #endif
05445 char txtfile[PATH_MAX];
05446 char tmptxtfile[PATH_MAX];
05447 struct vm_state *vms = NULL;
05448 char callerid[256];
05449 FILE *txt;
05450 char date[256];
05451 int txtdes;
05452 int res = 0;
05453 int msgnum;
05454 int duration = 0;
05455 int ausemacro = 0;
05456 int ousemacro = 0;
05457 int ouseexten = 0;
05458 char tmpdur[16];
05459 char priority[16];
05460 char origtime[16];
05461 char dir[PATH_MAX];
05462 char tmpdir[PATH_MAX];
05463 char fn[PATH_MAX];
05464 char prefile[PATH_MAX] = "";
05465 char tempfile[PATH_MAX] = "";
05466 char ext_context[256] = "";
05467 char fmt[80];
05468 char *context;
05469 char ecodes[17] = "#";
05470 struct ast_str *tmp = ast_str_create(16);
05471 char *tmpptr;
05472 struct ast_vm_user *vmu;
05473 struct ast_vm_user svm;
05474 const char *category = NULL;
05475 const char *code;
05476 const char *alldtmf = "0123456789ABCD*#";
05477 char flag[80];
05478
05479 if (!tmp) {
05480 return -1;
05481 }
05482
05483 ast_str_set(&tmp, 0, "%s", ext);
05484 ext = ast_str_buffer(tmp);
05485 if ((context = strchr(ext, '@'))) {
05486 *context++ = '\0';
05487 tmpptr = strchr(context, '&');
05488 } else {
05489 tmpptr = strchr(ext, '&');
05490 }
05491
05492 if (tmpptr)
05493 *tmpptr++ = '\0';
05494
05495 ast_channel_lock(chan);
05496 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05497 category = ast_strdupa(category);
05498 }
05499 ast_channel_unlock(chan);
05500
05501 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05502 ast_copy_string(flag, "Urgent", sizeof(flag));
05503 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05504 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05505 } else {
05506 flag[0] = '\0';
05507 }
05508
05509 ast_debug(3, "Before find_user\n");
05510 if (!(vmu = find_user(&svm, context, ext))) {
05511 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05512 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05513 ast_free(tmp);
05514 return res;
05515 }
05516
05517 if (strcmp(vmu->context, "default"))
05518 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05519 else
05520 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05521
05522
05523
05524
05525
05526
05527 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05528 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05529 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05530 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05531 }
05532
05533
05534
05535
05536 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05537 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05538 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05539 ast_free(tmp);
05540 return -1;
05541 }
05542 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05543 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05544 ast_copy_string(prefile, tempfile, sizeof(prefile));
05545
05546 DISPOSE(tempfile, -1);
05547
05548 #ifndef IMAP_STORAGE
05549 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05550 #else
05551 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05552 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05553 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05554 }
05555 #endif
05556
05557
05558 if (ast_test_flag(vmu, VM_OPERATOR)) {
05559 if (!ast_strlen_zero(vmu->exit)) {
05560 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05561 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05562 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05563 ouseexten = 1;
05564 }
05565 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05566 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05567 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05568 ouseexten = 1;
05569 } else if (!ast_strlen_zero(chan->macrocontext)
05570 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05571 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05572 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05573 ousemacro = 1;
05574 }
05575 }
05576
05577 if (!ast_strlen_zero(vmu->exit)) {
05578 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05579 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05580 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05581 }
05582 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05583 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05584 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05585 } else if (!ast_strlen_zero(chan->macrocontext)
05586 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05587 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05588 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05589 ausemacro = 1;
05590 }
05591
05592 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05593 for (code = alldtmf; *code; code++) {
05594 char e[2] = "";
05595 e[0] = *code;
05596 if (strchr(ecodes, e[0]) == NULL
05597 && ast_canmatch_extension(chan, chan->context, e, 1,
05598 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05599 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05600 }
05601 }
05602 }
05603
05604
05605 if (!ast_strlen_zero(prefile)) {
05606 #ifdef ODBC_STORAGE
05607 int success =
05608 #endif
05609 RETRIEVE(prefile, -1, ext, context);
05610 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05611 if (ast_streamfile(chan, prefile, chan->language) > -1)
05612 res = ast_waitstream(chan, ecodes);
05613 #ifdef ODBC_STORAGE
05614 if (success == -1) {
05615
05616 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05617 store_file(prefile, vmu->mailbox, vmu->context, -1);
05618 }
05619 #endif
05620 } else {
05621 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05622 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05623 }
05624 DISPOSE(prefile, -1);
05625 if (res < 0) {
05626 ast_debug(1, "Hang up during prefile playback\n");
05627 free_user(vmu);
05628 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05629 ast_free(tmp);
05630 return -1;
05631 }
05632 }
05633 if (res == '#') {
05634
05635 ast_set_flag(options, OPT_SILENT);
05636 res = 0;
05637 }
05638
05639 if (vmu->maxmsg == 0) {
05640 if (option_debug > 2)
05641 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05642 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05643 goto leave_vm_out;
05644 }
05645 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05646 res = ast_stream_and_wait(chan, INTRO, ecodes);
05647 if (res == '#') {
05648 ast_set_flag(options, OPT_SILENT);
05649 res = 0;
05650 }
05651 }
05652 if (res > 0)
05653 ast_stopstream(chan);
05654
05655
05656 if (res == '*') {
05657 chan->exten[0] = 'a';
05658 chan->exten[1] = '\0';
05659 if (!ast_strlen_zero(vmu->exit)) {
05660 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05661 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05662 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05663 }
05664 chan->priority = 0;
05665 free_user(vmu);
05666 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05667 ast_free(tmp);
05668 return 0;
05669 }
05670
05671
05672 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05673 transfer:
05674 if (ouseexten || ousemacro) {
05675 chan->exten[0] = 'o';
05676 chan->exten[1] = '\0';
05677 if (!ast_strlen_zero(vmu->exit)) {
05678 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05679 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05680 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05681 }
05682 ast_play_and_wait(chan, "transfer");
05683 chan->priority = 0;
05684 free_user(vmu);
05685 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05686 }
05687 ast_free(tmp);
05688 return OPERATOR_EXIT;
05689 }
05690
05691
05692 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05693 if (!ast_strlen_zero(options->exitcontext))
05694 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05695 free_user(vmu);
05696 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05697 ast_free(tmp);
05698 return res;
05699 }
05700
05701 if (res < 0) {
05702 free_user(vmu);
05703 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05704 ast_free(tmp);
05705 return -1;
05706 }
05707
05708 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05709 if (!ast_strlen_zero(fmt)) {
05710 msgnum = 0;
05711
05712 #ifdef IMAP_STORAGE
05713
05714
05715 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05716 if (res < 0) {
05717 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05718 ast_free(tmp);
05719 return -1;
05720 }
05721 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05722
05723
05724
05725
05726 if (!(vms = create_vm_state_from_user(vmu))) {
05727 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05728 ast_free(tmp);
05729 return -1;
05730 }
05731 }
05732 vms->newmessages++;
05733
05734
05735 msgnum = newmsgs + oldmsgs;
05736 ast_debug(3, "Messagecount set to %d\n", msgnum);
05737 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05738
05739 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05740
05741 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05742 goto leave_vm_out;
05743 }
05744 #else
05745 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05746 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05747 if (!res)
05748 res = ast_waitstream(chan, "");
05749 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05750 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05751 inprocess_count(vmu->mailbox, vmu->context, -1);
05752 goto leave_vm_out;
05753 }
05754
05755 #endif
05756 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05757 txtdes = mkstemp(tmptxtfile);
05758 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05759 if (txtdes < 0) {
05760 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05761 if (!res)
05762 res = ast_waitstream(chan, "");
05763 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05764 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05765 inprocess_count(vmu->mailbox, vmu->context, -1);
05766 goto leave_vm_out;
05767 }
05768
05769
05770 if (res >= 0) {
05771
05772 res = ast_stream_and_wait(chan, "beep", "");
05773 }
05774
05775
05776 if (ast_check_realtime("voicemail_data")) {
05777 snprintf(priority, sizeof(priority), "%d", chan->priority);
05778 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05779 get_date(date, sizeof(date));
05780 ast_callerid_merge(callerid, sizeof(callerid),
05781 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05782 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05783 "Unknown");
05784 ast_store_realtime("voicemail_data",
05785 "origmailbox", ext,
05786 "context", chan->context,
05787 "macrocontext", chan->macrocontext,
05788 "exten", chan->exten,
05789 "priority", priority,
05790 "callerchan", chan->name,
05791 "callerid", callerid,
05792 "origdate", date,
05793 "origtime", origtime,
05794 "category", S_OR(category, ""),
05795 "filename", tmptxtfile,
05796 SENTINEL);
05797 }
05798
05799
05800 txt = fdopen(txtdes, "w+");
05801 if (txt) {
05802 get_date(date, sizeof(date));
05803 ast_callerid_merge(callerid, sizeof(callerid),
05804 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05805 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05806 "Unknown");
05807 fprintf(txt,
05808 ";\n"
05809 "; Message Information file\n"
05810 ";\n"
05811 "[message]\n"
05812 "origmailbox=%s\n"
05813 "context=%s\n"
05814 "macrocontext=%s\n"
05815 "exten=%s\n"
05816 "rdnis=%s\n"
05817 "priority=%d\n"
05818 "callerchan=%s\n"
05819 "callerid=%s\n"
05820 "origdate=%s\n"
05821 "origtime=%ld\n"
05822 "category=%s\n",
05823 ext,
05824 chan->context,
05825 chan->macrocontext,
05826 chan->exten,
05827 S_COR(chan->redirecting.from.number.valid,
05828 chan->redirecting.from.number.str, "unknown"),
05829 chan->priority,
05830 chan->name,
05831 callerid,
05832 date, (long) time(NULL),
05833 category ? category : "");
05834 } else {
05835 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05836 inprocess_count(vmu->mailbox, vmu->context, -1);
05837 if (ast_check_realtime("voicemail_data")) {
05838 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05839 }
05840 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05841 goto leave_vm_out;
05842 }
05843 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05844
05845 if (txt) {
05846 fprintf(txt, "flag=%s\n", flag);
05847 if (duration < vmu->minsecs) {
05848 fclose(txt);
05849 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmu->minsecs);
05850 ast_filedelete(tmptxtfile, NULL);
05851 unlink(tmptxtfile);
05852 if (ast_check_realtime("voicemail_data")) {
05853 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05854 }
05855 inprocess_count(vmu->mailbox, vmu->context, -1);
05856 } else {
05857 fprintf(txt, "duration=%d\n", duration);
05858 fclose(txt);
05859 if (vm_lock_path(dir)) {
05860 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05861
05862 ast_filedelete(tmptxtfile, NULL);
05863 unlink(tmptxtfile);
05864 inprocess_count(vmu->mailbox, vmu->context, -1);
05865 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05866 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05867 unlink(tmptxtfile);
05868 ast_unlock_path(dir);
05869 inprocess_count(vmu->mailbox, vmu->context, -1);
05870 if (ast_check_realtime("voicemail_data")) {
05871 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05872 }
05873 } else {
05874 #ifndef IMAP_STORAGE
05875 msgnum = last_message_index(vmu, dir) + 1;
05876 #endif
05877 make_file(fn, sizeof(fn), dir, msgnum);
05878
05879
05880 #ifndef IMAP_STORAGE
05881 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05882 #else
05883 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05884 #endif
05885
05886 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05887 ast_filerename(tmptxtfile, fn, NULL);
05888 rename(tmptxtfile, txtfile);
05889 inprocess_count(vmu->mailbox, vmu->context, -1);
05890
05891
05892
05893 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05894 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05895
05896 ast_unlock_path(dir);
05897 if (ast_check_realtime("voicemail_data")) {
05898 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05899 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
05900 }
05901
05902
05903
05904 if (ast_fileexists(fn, NULL, NULL) > 0) {
05905 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05906 }
05907
05908
05909 while (tmpptr) {
05910 struct ast_vm_user recipu, *recip;
05911 char *exten, *cntx;
05912
05913 exten = strsep(&tmpptr, "&");
05914 cntx = strchr(exten, '@');
05915 if (cntx) {
05916 *cntx = '\0';
05917 cntx++;
05918 }
05919 if ((recip = find_user(&recipu, cntx, exten))) {
05920 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05921 free_user(recip);
05922 }
05923 }
05924 #ifndef IMAP_STORAGE
05925 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05926
05927 char sfn[PATH_MAX];
05928 char dfn[PATH_MAX];
05929 int x;
05930
05931 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05932 x = last_message_index(vmu, urgdir) + 1;
05933 make_file(sfn, sizeof(sfn), dir, msgnum);
05934 make_file(dfn, sizeof(dfn), urgdir, x);
05935 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
05936 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05937
05938 ast_copy_string(fn, dfn, sizeof(fn));
05939 msgnum = x;
05940 }
05941 #endif
05942
05943 if (ast_fileexists(fn, NULL, NULL)) {
05944 #ifdef IMAP_STORAGE
05945 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
05946 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05947 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05948 flag);
05949 #else
05950 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
05951 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05952 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05953 flag);
05954 #endif
05955 }
05956
05957
05958 if (ast_fileexists(fn, NULL, NULL)) {
05959 DISPOSE(dir, msgnum);
05960 }
05961 }
05962 }
05963 } else {
05964 inprocess_count(vmu->mailbox, vmu->context, -1);
05965 }
05966 if (res == '0') {
05967 goto transfer;
05968 } else if (res > 0 && res != 't')
05969 res = 0;
05970
05971 if (duration < vmu->minsecs)
05972
05973 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05974 else
05975 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05976 } else
05977 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
05978 leave_vm_out:
05979 free_user(vmu);
05980
05981 #ifdef IMAP_STORAGE
05982
05983 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
05984 if (expungeonhangup == 1) {
05985 ast_mutex_lock(&vms->lock);
05986 #ifdef HAVE_IMAP_TK2006
05987 if (LEVELUIDPLUS (vms->mailstream)) {
05988 mail_expunge_full(vms->mailstream, NIL, EX_UID);
05989 } else
05990 #endif
05991 mail_expunge(vms->mailstream);
05992 ast_mutex_unlock(&vms->lock);
05993 }
05994 #endif
05995
05996 ast_free(tmp);
05997 return res;
05998 }
05999
06000 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06001 {
06002 int d;
06003 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06004 return d;
06005 }
06006
06007 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06008 {
06009 #ifdef IMAP_STORAGE
06010
06011
06012 char sequence[10];
06013 char mailbox[256];
06014 int res;
06015
06016
06017 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06018
06019 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06020 ast_mutex_lock(&vms->lock);
06021
06022 if (box == OLD_FOLDER) {
06023 mail_setflag(vms->mailstream, sequence, "\\Seen");
06024 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06025 } else if (box == NEW_FOLDER) {
06026 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06027 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06028 }
06029 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06030 ast_mutex_unlock(&vms->lock);
06031 return 0;
06032 }
06033
06034 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06035 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06036 if (mail_create(vms->mailstream, mailbox) == NIL)
06037 ast_debug(5, "Folder exists.\n");
06038 else
06039 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06040 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06041 ast_mutex_unlock(&vms->lock);
06042 return res;
06043 #else
06044 char *dir = vms->curdir;
06045 char *username = vms->username;
06046 char *context = vmu->context;
06047 char sfn[PATH_MAX];
06048 char dfn[PATH_MAX];
06049 char ddir[PATH_MAX];
06050 const char *dbox = mbox(vmu, box);
06051 int x, i;
06052 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06053
06054 if (vm_lock_path(ddir))
06055 return ERROR_LOCK_PATH;
06056
06057 x = last_message_index(vmu, ddir) + 1;
06058
06059 if (box == 10 && x >= vmu->maxdeletedmsg) {
06060 x--;
06061 for (i = 1; i <= x; i++) {
06062
06063 make_file(sfn, sizeof(sfn), ddir, i);
06064 make_file(dfn, sizeof(dfn), ddir, i - 1);
06065 if (EXISTS(ddir, i, sfn, NULL)) {
06066 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06067 } else
06068 break;
06069 }
06070 } else {
06071 if (x >= vmu->maxmsg) {
06072 ast_unlock_path(ddir);
06073 return -1;
06074 }
06075 }
06076 make_file(sfn, sizeof(sfn), dir, msg);
06077 make_file(dfn, sizeof(dfn), ddir, x);
06078 if (strcmp(sfn, dfn)) {
06079 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06080 }
06081 ast_unlock_path(ddir);
06082 #endif
06083 return 0;
06084 }
06085
06086 static int adsi_logo(unsigned char *buf)
06087 {
06088 int bytes = 0;
06089 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06090 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06091 return bytes;
06092 }
06093
06094 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06095 {
06096 unsigned char buf[256];
06097 int bytes = 0;
06098 int x;
06099 char num[5];
06100
06101 *useadsi = 0;
06102 bytes += ast_adsi_data_mode(buf + bytes);
06103 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06104
06105 bytes = 0;
06106 bytes += adsi_logo(buf);
06107 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06108 #ifdef DISPLAY
06109 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06110 #endif
06111 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06112 bytes += ast_adsi_data_mode(buf + bytes);
06113 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06114
06115 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06116 bytes = 0;
06117 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06118 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06119 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06120 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06121 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06122 return 0;
06123 }
06124
06125 #ifdef DISPLAY
06126
06127 bytes = 0;
06128 bytes += ast_adsi_logo(buf);
06129 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06130 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06131 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06132 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06133 #endif
06134 bytes = 0;
06135 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06136 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06137 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06138 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06139 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06140 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06141 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06142
06143 #ifdef DISPLAY
06144
06145 bytes = 0;
06146 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06147 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06148
06149 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06150 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06151 #endif
06152
06153 bytes = 0;
06154
06155 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06156 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06157 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06158 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06159 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06160 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06161 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06162
06163 #ifdef DISPLAY
06164
06165 bytes = 0;
06166 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06167 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06168 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06169 #endif
06170
06171 bytes = 0;
06172 for (x = 0; x < 5; x++) {
06173 snprintf(num, sizeof(num), "%d", x);
06174 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06175 }
06176 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06177 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06178
06179 #ifdef DISPLAY
06180
06181 bytes = 0;
06182 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06183 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06184 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06185 #endif
06186
06187 if (ast_adsi_end_download(chan)) {
06188 bytes = 0;
06189 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06190 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06191 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06192 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06193 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06194 return 0;
06195 }
06196 bytes = 0;
06197 bytes += ast_adsi_download_disconnect(buf + bytes);
06198 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06199 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06200
06201 ast_debug(1, "Done downloading scripts...\n");
06202
06203 #ifdef DISPLAY
06204
06205 bytes = 0;
06206 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06207 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06208 #endif
06209 ast_debug(1, "Restarting session...\n");
06210
06211 bytes = 0;
06212
06213 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06214 *useadsi = 1;
06215 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06216 } else
06217 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06218
06219 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06220 return 0;
06221 }
06222
06223 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06224 {
06225 int x;
06226 if (!ast_adsi_available(chan))
06227 return;
06228 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06229 if (x < 0)
06230 return;
06231 if (!x) {
06232 if (adsi_load_vmail(chan, useadsi)) {
06233 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06234 return;
06235 }
06236 } else
06237 *useadsi = 1;
06238 }
06239
06240 static void adsi_login(struct ast_channel *chan)
06241 {
06242 unsigned char buf[256];
06243 int bytes = 0;
06244 unsigned char keys[8];
06245 int x;
06246 if (!ast_adsi_available(chan))
06247 return;
06248
06249 for (x = 0; x < 8; x++)
06250 keys[x] = 0;
06251
06252 keys[3] = ADSI_KEY_APPS + 3;
06253
06254 bytes += adsi_logo(buf + bytes);
06255 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06256 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06257 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06258 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06259 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06260 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06261 bytes += ast_adsi_set_keys(buf + bytes, keys);
06262 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06263 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06264 }
06265
06266 static void adsi_password(struct ast_channel *chan)
06267 {
06268 unsigned char buf[256];
06269 int bytes = 0;
06270 unsigned char keys[8];
06271 int x;
06272 if (!ast_adsi_available(chan))
06273 return;
06274
06275 for (x = 0; x < 8; x++)
06276 keys[x] = 0;
06277
06278 keys[3] = ADSI_KEY_APPS + 3;
06279
06280 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06281 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06282 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06283 bytes += ast_adsi_set_keys(buf + bytes, keys);
06284 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06285 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06286 }
06287
06288 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06289 {
06290 unsigned char buf[256];
06291 int bytes = 0;
06292 unsigned char keys[8];
06293 int x, y;
06294
06295 if (!ast_adsi_available(chan))
06296 return;
06297
06298 for (x = 0; x < 5; x++) {
06299 y = ADSI_KEY_APPS + 12 + start + x;
06300 if (y > ADSI_KEY_APPS + 12 + 4)
06301 y = 0;
06302 keys[x] = ADSI_KEY_SKT | y;
06303 }
06304 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06305 keys[6] = 0;
06306 keys[7] = 0;
06307
06308 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06309 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06310 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06311 bytes += ast_adsi_set_keys(buf + bytes, keys);
06312 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06313
06314 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06315 }
06316
06317 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06318 {
06319 int bytes = 0;
06320 unsigned char buf[256];
06321 char buf1[256], buf2[256];
06322 char fn2[PATH_MAX];
06323
06324 char cid[256] = "";
06325 char *val;
06326 char *name, *num;
06327 char datetime[21] = "";
06328 FILE *f;
06329
06330 unsigned char keys[8];
06331
06332 int x;
06333
06334 if (!ast_adsi_available(chan))
06335 return;
06336
06337
06338 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06339 f = fopen(fn2, "r");
06340 if (f) {
06341 while (!feof(f)) {
06342 if (!fgets((char *) buf, sizeof(buf), f)) {
06343 continue;
06344 }
06345 if (!feof(f)) {
06346 char *stringp = NULL;
06347 stringp = (char *) buf;
06348 strsep(&stringp, "=");
06349 val = strsep(&stringp, "=");
06350 if (!ast_strlen_zero(val)) {
06351 if (!strcmp((char *) buf, "callerid"))
06352 ast_copy_string(cid, val, sizeof(cid));
06353 if (!strcmp((char *) buf, "origdate"))
06354 ast_copy_string(datetime, val, sizeof(datetime));
06355 }
06356 }
06357 }
06358 fclose(f);
06359 }
06360
06361 for (x = 0; x < 5; x++)
06362 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06363 keys[6] = 0x0;
06364 keys[7] = 0x0;
06365
06366 if (!vms->curmsg) {
06367
06368 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06369 }
06370 if (vms->curmsg >= vms->lastmsg) {
06371
06372 if (vms->curmsg) {
06373
06374 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06375 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06376
06377 } else {
06378
06379 keys[3] = 1;
06380 }
06381 }
06382
06383 if (!ast_strlen_zero(cid)) {
06384 ast_callerid_parse(cid, &name, &num);
06385 if (!name)
06386 name = num;
06387 } else
06388 name = "Unknown Caller";
06389
06390
06391
06392 if (vms->deleted[vms->curmsg])
06393 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06394
06395
06396 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06397 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06398 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06399 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06400
06401 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06402 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06403 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06404 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06405 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06406 bytes += ast_adsi_set_keys(buf + bytes, keys);
06407 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06408
06409 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06410 }
06411
06412 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06413 {
06414 int bytes = 0;
06415 unsigned char buf[256];
06416 unsigned char keys[8];
06417
06418 int x;
06419
06420 if (!ast_adsi_available(chan))
06421 return;
06422
06423
06424 for (x = 0; x < 5; x++)
06425 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06426
06427 keys[6] = 0x0;
06428 keys[7] = 0x0;
06429
06430 if (!vms->curmsg) {
06431
06432 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06433 }
06434 if (vms->curmsg >= vms->lastmsg) {
06435
06436 if (vms->curmsg) {
06437
06438 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06439 } else {
06440
06441 keys[3] = 1;
06442 }
06443 }
06444
06445
06446 if (vms->deleted[vms->curmsg])
06447 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06448
06449
06450 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06451 bytes += ast_adsi_set_keys(buf + bytes, keys);
06452 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06453
06454 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06455 }
06456
06457 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06458 {
06459 unsigned char buf[256] = "";
06460 char buf1[256] = "", buf2[256] = "";
06461 int bytes = 0;
06462 unsigned char keys[8];
06463 int x;
06464
06465 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06466 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06467 if (!ast_adsi_available(chan))
06468 return;
06469 if (vms->newmessages) {
06470 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06471 if (vms->oldmessages) {
06472 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06473 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06474 } else {
06475 snprintf(buf2, sizeof(buf2), "%s.", newm);
06476 }
06477 } else if (vms->oldmessages) {
06478 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06479 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06480 } else {
06481 strcpy(buf1, "You have no messages.");
06482 buf2[0] = ' ';
06483 buf2[1] = '\0';
06484 }
06485 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06486 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06487 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06488
06489 for (x = 0; x < 6; x++)
06490 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06491 keys[6] = 0;
06492 keys[7] = 0;
06493
06494
06495 if (vms->lastmsg < 0)
06496 keys[0] = 1;
06497 bytes += ast_adsi_set_keys(buf + bytes, keys);
06498
06499 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06500
06501 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06502 }
06503
06504 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06505 {
06506 unsigned char buf[256] = "";
06507 char buf1[256] = "", buf2[256] = "";
06508 int bytes = 0;
06509 unsigned char keys[8];
06510 int x;
06511
06512 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06513
06514 if (!ast_adsi_available(chan))
06515 return;
06516
06517
06518 for (x = 0; x < 6; x++)
06519 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06520
06521 keys[6] = 0;
06522 keys[7] = 0;
06523
06524 if ((vms->lastmsg + 1) < 1)
06525 keys[0] = 0;
06526
06527 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06528 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06529
06530 if (vms->lastmsg + 1)
06531 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06532 else
06533 strcpy(buf2, "no messages.");
06534 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06535 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06536 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06537 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06538 bytes += ast_adsi_set_keys(buf + bytes, keys);
06539
06540 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06541
06542 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06543
06544 }
06545
06546
06547
06548
06549
06550
06551
06552
06553
06554
06555
06556
06557
06558
06559
06560 static void adsi_goodbye(struct ast_channel *chan)
06561 {
06562 unsigned char buf[256];
06563 int bytes = 0;
06564
06565 if (!ast_adsi_available(chan))
06566 return;
06567 bytes += adsi_logo(buf + bytes);
06568 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06569 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06570 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06571 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06572
06573 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06574 }
06575
06576
06577
06578
06579
06580 static int get_folder(struct ast_channel *chan, int start)
06581 {
06582 int x;
06583 int d;
06584 char fn[PATH_MAX];
06585 d = ast_play_and_wait(chan, "vm-press");
06586 if (d)
06587 return d;
06588 for (x = start; x < 5; x++) {
06589 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06590 return d;
06591 d = ast_play_and_wait(chan, "vm-for");
06592 if (d)
06593 return d;
06594 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06595 d = vm_play_folder_name(chan, fn);
06596 if (d)
06597 return d;
06598 d = ast_waitfordigit(chan, 500);
06599 if (d)
06600 return d;
06601 }
06602 d = ast_play_and_wait(chan, "vm-tocancel");
06603 if (d)
06604 return d;
06605 d = ast_waitfordigit(chan, 4000);
06606 return d;
06607 }
06608
06609
06610
06611
06612
06613
06614
06615
06616
06617
06618
06619
06620
06621 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06622 {
06623 int res = 0;
06624 int loops = 0;
06625 res = ast_play_and_wait(chan, fn);
06626 while (((res < '0') || (res > '9')) &&
06627 (res != '#') && (res >= 0) &&
06628 loops < 4) {
06629 res = get_folder(chan, 0);
06630 loops++;
06631 }
06632 if (loops == 4) {
06633 return '#';
06634 }
06635 return res;
06636 }
06637
06638
06639
06640
06641
06642
06643
06644
06645
06646
06647
06648
06649
06650
06651
06652
06653
06654
06655
06656 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06657 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06658 {
06659 #ifdef IMAP_STORAGE
06660 int res;
06661 #endif
06662 int cmd = 0;
06663 int retries = 0, prepend_duration = 0, already_recorded = 0;
06664 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06665 char textfile[PATH_MAX];
06666 struct ast_config *msg_cfg;
06667 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06668 #ifndef IMAP_STORAGE
06669 signed char zero_gain = 0;
06670 #endif
06671 const char *duration_str;
06672
06673
06674 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06675 strcpy(textfile, msgfile);
06676 strcpy(backup, msgfile);
06677 strcpy(backup_textfile, msgfile);
06678 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06679 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06680 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06681
06682 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06683 *duration = atoi(duration_str);
06684 } else {
06685 *duration = 0;
06686 }
06687
06688 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06689 if (cmd)
06690 retries = 0;
06691 switch (cmd) {
06692 case '1':
06693
06694 #ifdef IMAP_STORAGE
06695
06696 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06697 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06698 res = ast_play_and_wait(chan, INTRO);
06699 res = ast_play_and_wait(chan, "beep");
06700 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, record_gain, vms, flag);
06701 cmd = 't';
06702 #else
06703
06704
06705
06706 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06707 strcpy(textfile, msgfile);
06708 strncat(textfile, ".txt", sizeof(textfile) - 1);
06709 *duration = 0;
06710
06711
06712 if (!msg_cfg) {
06713 cmd = 0;
06714 break;
06715 }
06716
06717
06718 if (already_recorded) {
06719 ast_filecopy(backup, msgfile, NULL);
06720 copy(backup_textfile, textfile);
06721 }
06722 else {
06723 ast_filecopy(msgfile, backup, NULL);
06724 copy(textfile,backup_textfile);
06725 }
06726 already_recorded = 1;
06727
06728 if (record_gain)
06729 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06730
06731 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06732 if (cmd == 'S') {
06733 ast_filerename(backup, msgfile, NULL);
06734 }
06735
06736 if (record_gain)
06737 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06738
06739
06740 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06741 *duration = atoi(duration_str);
06742
06743 if (prepend_duration) {
06744 struct ast_category *msg_cat;
06745
06746 char duration_buf[12];
06747
06748 *duration += prepend_duration;
06749 msg_cat = ast_category_get(msg_cfg, "message");
06750 snprintf(duration_buf, 11, "%ld", *duration);
06751 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06752 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06753 }
06754 }
06755
06756 #endif
06757 break;
06758 case '2':
06759
06760 #ifdef IMAP_STORAGE
06761 *vms->introfn = '\0';
06762 #endif
06763 cmd = 't';
06764 break;
06765 case '*':
06766 cmd = '*';
06767 break;
06768 default:
06769 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06770
06771 if (!cmd)
06772 cmd = ast_play_and_wait(chan, "vm-starmain");
06773
06774 if (!cmd)
06775 cmd = ast_waitfordigit(chan, 6000);
06776 if (!cmd)
06777 retries++;
06778 if (retries > 3)
06779 cmd = 't';
06780 }
06781 }
06782
06783 if (msg_cfg)
06784 ast_config_destroy(msg_cfg);
06785 if (prepend_duration)
06786 *duration = prepend_duration;
06787
06788 if (already_recorded && cmd == -1) {
06789
06790 ast_filerename(backup, msgfile, NULL);
06791 rename(backup_textfile, textfile);
06792 }
06793
06794 if (cmd == 't' || cmd == 'S')
06795 cmd = 0;
06796 return cmd;
06797 }
06798
06799 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06800 {
06801 struct ast_event *event;
06802 char *mailbox, *context;
06803
06804
06805 context = mailbox = ast_strdupa(box);
06806 strsep(&context, "@");
06807 if (ast_strlen_zero(context))
06808 context = "default";
06809
06810 if (!(event = ast_event_new(AST_EVENT_MWI,
06811 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06812 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06813 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06814 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06815 AST_EVENT_IE_END))) {
06816 return;
06817 }
06818
06819 ast_event_queue_and_cache(event);
06820 }
06821
06822
06823
06824
06825
06826
06827
06828
06829
06830
06831
06832
06833
06834
06835
06836 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)
06837 {
06838 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06839 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06840 const char *category;
06841 char *myserveremail = serveremail;
06842
06843 ast_channel_lock(chan);
06844 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06845 category = ast_strdupa(category);
06846 }
06847 ast_channel_unlock(chan);
06848
06849 #ifndef IMAP_STORAGE
06850 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
06851 #else
06852 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
06853 #endif
06854 make_file(fn, sizeof(fn), todir, msgnum);
06855 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06856
06857 if (!ast_strlen_zero(vmu->attachfmt)) {
06858 if (strstr(fmt, vmu->attachfmt))
06859 fmt = vmu->attachfmt;
06860 else
06861 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);
06862 }
06863
06864
06865 fmt = ast_strdupa(fmt);
06866 stringp = fmt;
06867 strsep(&stringp, "|");
06868
06869 if (!ast_strlen_zero(vmu->serveremail))
06870 myserveremail = vmu->serveremail;
06871
06872 if (!ast_strlen_zero(vmu->email)) {
06873 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
06874
06875 if (attach_user_voicemail)
06876 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
06877
06878
06879 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
06880
06881 if (attach_user_voicemail)
06882 DISPOSE(todir, msgnum);
06883 }
06884
06885 if (!ast_strlen_zero(vmu->pager)) {
06886 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
06887 }
06888
06889 if (ast_test_flag(vmu, VM_DELETE))
06890 DELETE(todir, msgnum, fn, vmu);
06891
06892
06893 if (ast_app_has_voicemail(ext_context, NULL))
06894 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
06895
06896 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
06897
06898 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);
06899 run_externnotify(vmu->context, vmu->mailbox, flag);
06900
06901 #ifdef IMAP_STORAGE
06902 vm_delete(fn);
06903 if (ast_test_flag(vmu, VM_DELETE)) {
06904 vm_imap_delete(NULL, vms->curmsg, vmu);
06905 vms->newmessages--;
06906 }
06907 #endif
06908
06909 return 0;
06910 }
06911
06912
06913
06914
06915
06916
06917
06918
06919
06920
06921
06922
06923
06924
06925
06926
06927
06928
06929
06930
06931
06932
06933
06934
06935
06936
06937
06938
06939 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)
06940 {
06941 #ifdef IMAP_STORAGE
06942 int todircount = 0;
06943 struct vm_state *dstvms;
06944 #endif
06945 char username[70]="";
06946 char fn[PATH_MAX];
06947 char ecodes[16] = "#";
06948 int res = 0, cmd = 0;
06949 struct ast_vm_user *receiver = NULL, *vmtmp;
06950 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06951 char *stringp;
06952 const char *s;
06953 int saved_messages = 0;
06954 int valid_extensions = 0;
06955 char *dir;
06956 int curmsg;
06957 char urgent_str[7] = "";
06958 char tmptxtfile[PATH_MAX];
06959 int prompt_played = 0;
06960 #ifndef IMAP_STORAGE
06961 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06962 #endif
06963 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
06964 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
06965 }
06966
06967 if (vms == NULL) return -1;
06968 dir = vms->curdir;
06969 curmsg = vms->curmsg;
06970
06971 tmptxtfile[0] = '\0';
06972 while (!res && !valid_extensions) {
06973 int use_directory = 0;
06974 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
06975 int done = 0;
06976 int retries = 0;
06977 cmd = 0;
06978 while ((cmd >= 0) && !done ){
06979 if (cmd)
06980 retries = 0;
06981 switch (cmd) {
06982 case '1':
06983 use_directory = 0;
06984 done = 1;
06985 break;
06986 case '2':
06987 use_directory = 1;
06988 done = 1;
06989 break;
06990 case '*':
06991 cmd = 't';
06992 done = 1;
06993 break;
06994 default:
06995
06996 cmd = ast_play_and_wait(chan, "vm-forward");
06997 if (!cmd)
06998 cmd = ast_waitfordigit(chan, 3000);
06999 if (!cmd)
07000 retries++;
07001 if (retries > 3) {
07002 cmd = 't';
07003 done = 1;
07004 }
07005
07006 }
07007 }
07008 if (cmd < 0 || cmd == 't')
07009 break;
07010 }
07011
07012 if (use_directory) {
07013
07014
07015 char old_context[sizeof(chan->context)];
07016 char old_exten[sizeof(chan->exten)];
07017 int old_priority;
07018 struct ast_app* directory_app;
07019
07020 directory_app = pbx_findapp("Directory");
07021 if (directory_app) {
07022 char vmcontext[256];
07023
07024 memcpy(old_context, chan->context, sizeof(chan->context));
07025 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07026 old_priority = chan->priority;
07027
07028
07029 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07030 res = pbx_exec(chan, directory_app, vmcontext);
07031
07032 ast_copy_string(username, chan->exten, sizeof(username));
07033
07034
07035 memcpy(chan->context, old_context, sizeof(chan->context));
07036 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07037 chan->priority = old_priority;
07038 } else {
07039 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07040 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07041 }
07042 } else {
07043
07044 res = ast_streamfile(chan, "vm-extension", chan->language);
07045 prompt_played++;
07046 if (res || prompt_played > 4)
07047 break;
07048 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07049 break;
07050 }
07051
07052
07053 if (ast_strlen_zero(username))
07054 continue;
07055 stringp = username;
07056 s = strsep(&stringp, "*");
07057
07058 valid_extensions = 1;
07059 while (s) {
07060 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07061 int oldmsgs;
07062 int newmsgs;
07063 int capacity;
07064 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07065 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07066
07067 res = ast_play_and_wait(chan, "pbx-invalid");
07068 valid_extensions = 0;
07069 break;
07070 }
07071 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07072 if ((newmsgs + oldmsgs) >= capacity) {
07073 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07074 res = ast_play_and_wait(chan, "vm-mailboxfull");
07075 valid_extensions = 0;
07076 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07077 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07078 free_user(vmtmp);
07079 }
07080 inprocess_count(receiver->mailbox, receiver->context, -1);
07081 break;
07082 }
07083 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07084 } else {
07085
07086
07087
07088
07089
07090 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07091 free_user(receiver);
07092 }
07093 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07094
07095 res = ast_play_and_wait(chan, "pbx-invalid");
07096 valid_extensions = 0;
07097 break;
07098 }
07099
07100
07101 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07102 RETRIEVE(fn, -1, s, receiver->context);
07103 if (ast_fileexists(fn, NULL, NULL) > 0) {
07104 res = ast_stream_and_wait(chan, fn, ecodes);
07105 if (res) {
07106 DISPOSE(fn, -1);
07107 return res;
07108 }
07109 } else {
07110 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07111 }
07112 DISPOSE(fn, -1);
07113
07114 s = strsep(&stringp, "*");
07115 }
07116
07117 if (valid_extensions)
07118 break;
07119 }
07120
07121 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07122 return res;
07123 if (is_new_message == 1) {
07124 struct leave_vm_options leave_options;
07125 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07126 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07127
07128
07129 memset(&leave_options, 0, sizeof(leave_options));
07130 leave_options.record_gain = record_gain;
07131 cmd = leave_voicemail(chan, mailbox, &leave_options);
07132 } else {
07133
07134 long duration = 0;
07135 struct vm_state vmstmp;
07136 int copy_msg_result = 0;
07137 memcpy(&vmstmp, vms, sizeof(vmstmp));
07138
07139 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07140
07141 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07142 if (!cmd) {
07143 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07144 #ifdef IMAP_STORAGE
07145 int attach_user_voicemail;
07146 char *myserveremail = serveremail;
07147
07148
07149 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07150 if (!dstvms) {
07151 dstvms = create_vm_state_from_user(vmtmp);
07152 }
07153 if (dstvms) {
07154 init_mailstream(dstvms, 0);
07155 if (!dstvms->mailstream) {
07156 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07157 } else {
07158 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07159 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07160 }
07161 } else {
07162 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07163 }
07164 if (!ast_strlen_zero(vmtmp->serveremail))
07165 myserveremail = vmtmp->serveremail;
07166 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07167
07168 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07169 dstvms->curbox,
07170 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07171 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07172 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07173 NULL, urgent_str);
07174 #else
07175 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07176 #endif
07177 saved_messages++;
07178 AST_LIST_REMOVE_CURRENT(list);
07179 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07180 free_user(vmtmp);
07181 if (res)
07182 break;
07183 }
07184 AST_LIST_TRAVERSE_SAFE_END;
07185 if (saved_messages > 0 && !copy_msg_result) {
07186
07187
07188
07189
07190
07191
07192
07193
07194 #ifdef IMAP_STORAGE
07195
07196 if (ast_strlen_zero(vmstmp.introfn))
07197 #endif
07198 res = ast_play_and_wait(chan, "vm-msgsaved");
07199 }
07200 #ifndef IMAP_STORAGE
07201 else {
07202
07203 res = ast_play_and_wait(chan, "vm-mailboxfull");
07204 }
07205
07206 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07207 strcpy(textfile, msgfile);
07208 strcpy(backup, msgfile);
07209 strcpy(backup_textfile, msgfile);
07210 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07211 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07212 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07213 if (ast_fileexists(backup, NULL, NULL) > 0) {
07214 ast_filerename(backup, msgfile, NULL);
07215 rename(backup_textfile, textfile);
07216 }
07217 #endif
07218 }
07219 DISPOSE(dir, curmsg);
07220 #ifndef IMAP_STORAGE
07221 if (cmd) {
07222 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07223 strcpy(textfile, msgfile);
07224 strcpy(backup_textfile, msgfile);
07225 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07226 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07227 rename(backup_textfile, textfile);
07228 }
07229 #endif
07230 }
07231
07232
07233 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07234 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07235 free_user(vmtmp);
07236 }
07237 return res ? res : cmd;
07238 }
07239
07240 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07241 {
07242 int res;
07243 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07244 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07245 return res;
07246 }
07247
07248 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07249 {
07250 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);
07251 }
07252
07253 static int play_message_category(struct ast_channel *chan, const char *category)
07254 {
07255 int res = 0;
07256
07257 if (!ast_strlen_zero(category))
07258 res = ast_play_and_wait(chan, category);
07259
07260 if (res) {
07261 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07262 res = 0;
07263 }
07264
07265 return res;
07266 }
07267
07268 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07269 {
07270 int res = 0;
07271 struct vm_zone *the_zone = NULL;
07272 time_t t;
07273
07274 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07275 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07276 return 0;
07277 }
07278
07279
07280 if (!ast_strlen_zero(vmu->zonetag)) {
07281
07282 struct vm_zone *z;
07283 AST_LIST_LOCK(&zones);
07284 AST_LIST_TRAVERSE(&zones, z, list) {
07285 if (!strcmp(z->name, vmu->zonetag)) {
07286 the_zone = z;
07287 break;
07288 }
07289 }
07290 AST_LIST_UNLOCK(&zones);
07291 }
07292
07293
07294 #if 0
07295
07296 ast_localtime(&t, &time_now, NULL);
07297 tv_now = ast_tvnow();
07298 ast_localtime(&tv_now, &time_then, NULL);
07299
07300
07301 if (time_now.tm_year == time_then.tm_year)
07302 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07303 else
07304 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07305 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07306
07307
07308 #endif
07309 if (the_zone) {
07310 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07311 } else if (!strncasecmp(chan->language, "de", 2)) {
07312 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07313 } else if (!strncasecmp(chan->language, "gr", 2)) {
07314 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07315 } else if (!strncasecmp(chan->language, "it", 2)) {
07316 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);
07317 } else if (!strncasecmp(chan->language, "nl", 2)) {
07318 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07319 } else if (!strncasecmp(chan->language, "no", 2)) {
07320 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07321 } else if (!strncasecmp(chan->language, "pl", 2)) {
07322 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07323 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07324 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);
07325 } else if (!strncasecmp(chan->language, "se", 2)) {
07326 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07327 } else if (!strncasecmp(chan->language, "zh", 2)) {
07328 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07329 } else if (!strncasecmp(chan->language, "vi", 2)) {
07330 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);
07331 } else {
07332 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07333 }
07334 #if 0
07335 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07336 #endif
07337 return res;
07338 }
07339
07340
07341
07342 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07343 {
07344 int res = 0;
07345 int i;
07346 char *callerid, *name;
07347 char prefile[PATH_MAX] = "";
07348
07349
07350
07351
07352
07353
07354
07355
07356
07357 if ((cid == NULL)||(context == NULL))
07358 return res;
07359
07360
07361 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07362 ast_callerid_parse(cid, &name, &callerid);
07363 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07364
07365
07366 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07367 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07368 if ((strcmp(cidinternalcontexts[i], context) == 0))
07369 break;
07370 }
07371 if (i != MAX_NUM_CID_CONTEXTS){
07372 if (!res) {
07373 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07374 if (!ast_strlen_zero(prefile)) {
07375
07376 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07377 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07378 if (!callback)
07379 res = wait_file2(chan, vms, "vm-from");
07380 res = ast_stream_and_wait(chan, prefile, "");
07381 } else {
07382 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07383
07384 if (!callback)
07385 res = wait_file2(chan, vms, "vm-from-extension");
07386 res = ast_say_digit_str(chan, callerid, "", chan->language);
07387 }
07388 }
07389 }
07390 } else if (!res) {
07391 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07392
07393 if (!callback)
07394 res = wait_file2(chan, vms, "vm-from-phonenumber");
07395 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07396 }
07397 } else {
07398
07399 ast_debug(1, "VM-CID: From an unknown number\n");
07400
07401 res = wait_file2(chan, vms, "vm-unknown-caller");
07402 }
07403 return res;
07404 }
07405
07406 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07407 {
07408 int res = 0;
07409 int durationm;
07410 int durations;
07411
07412 if (duration == NULL)
07413 return res;
07414
07415
07416 durations = atoi(duration);
07417 durationm = (durations / 60);
07418
07419 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07420
07421 if ((!res) && (durationm >= minduration)) {
07422 res = wait_file2(chan, vms, "vm-duration");
07423
07424
07425 if (!strncasecmp(chan->language, "pl", 2)) {
07426 div_t num = div(durationm, 10);
07427
07428 if (durationm == 1) {
07429 res = ast_play_and_wait(chan, "digits/1z");
07430 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07431 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07432 if (num.rem == 2) {
07433 if (!num.quot) {
07434 res = ast_play_and_wait(chan, "digits/2-ie");
07435 } else {
07436 res = say_and_wait(chan, durationm - 2 , chan->language);
07437 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07438 }
07439 } else {
07440 res = say_and_wait(chan, durationm, chan->language);
07441 }
07442 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07443 } else {
07444 res = say_and_wait(chan, durationm, chan->language);
07445 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07446 }
07447
07448 } else {
07449 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07450 res = wait_file2(chan, vms, "vm-minutes");
07451 }
07452 }
07453 return res;
07454 }
07455
07456 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07457 {
07458 int res = 0;
07459 char filename[256], *cid;
07460 const char *origtime, *context, *category, *duration, *flag;
07461 struct ast_config *msg_cfg;
07462 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07463
07464 vms->starting = 0;
07465 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07466 adsi_message(chan, vms);
07467 if (!vms->curmsg)
07468 res = wait_file2(chan, vms, "vm-first");
07469 else if (vms->curmsg == vms->lastmsg)
07470 res = wait_file2(chan, vms, "vm-last");
07471
07472 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07473 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07474 msg_cfg = ast_config_load(filename, config_flags);
07475 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07476 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07477 return 0;
07478 }
07479 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07480
07481
07482 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07483 res = wait_file2(chan, vms, "vm-Urgent");
07484 }
07485
07486 if (!res) {
07487
07488
07489 if (!strncasecmp(chan->language, "pl", 2)) {
07490 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07491 int ten, one;
07492 char nextmsg[256];
07493 ten = (vms->curmsg + 1) / 10;
07494 one = (vms->curmsg + 1) % 10;
07495
07496 if (vms->curmsg < 20) {
07497 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07498 res = wait_file2(chan, vms, nextmsg);
07499 } else {
07500 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07501 res = wait_file2(chan, vms, nextmsg);
07502 if (one > 0) {
07503 if (!res) {
07504 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07505 res = wait_file2(chan, vms, nextmsg);
07506 }
07507 }
07508 }
07509 }
07510 if (!res)
07511 res = wait_file2(chan, vms, "vm-message");
07512
07513 } else if (!strncasecmp(chan->language, "he", 2)) {
07514 if (!vms->curmsg) {
07515 res = wait_file2(chan, vms, "vm-message");
07516 res = wait_file2(chan, vms, "vm-first");
07517 } else if (vms->curmsg == vms->lastmsg) {
07518 res = wait_file2(chan, vms, "vm-message");
07519 res = wait_file2(chan, vms, "vm-last");
07520 } else {
07521 res = wait_file2(chan, vms, "vm-message");
07522 res = wait_file2(chan, vms, "vm-number");
07523 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07524 }
07525
07526 } else if (!strncasecmp(chan->language, "vi", 2)) {
07527 if (!vms->curmsg) {
07528 res = wait_file2(chan, vms, "vm-message");
07529 res = wait_file2(chan, vms, "vm-first");
07530 } else if (vms->curmsg == vms->lastmsg) {
07531 res = wait_file2(chan, vms, "vm-message");
07532 res = wait_file2(chan, vms, "vm-last");
07533 } else {
07534 res = wait_file2(chan, vms, "vm-message");
07535 res = wait_file2(chan, vms, "vm-number");
07536 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07537 }
07538 } else {
07539 if (!strncasecmp(chan->language, "se", 2)) {
07540 res = wait_file2(chan, vms, "vm-meddelandet");
07541 } else {
07542 res = wait_file2(chan, vms, "vm-message");
07543 }
07544 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07545 if (!res) {
07546 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07547 }
07548 }
07549 }
07550 }
07551
07552 if (!msg_cfg) {
07553 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07554 return 0;
07555 }
07556
07557 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07558 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07559 DISPOSE(vms->curdir, vms->curmsg);
07560 ast_config_destroy(msg_cfg);
07561 return 0;
07562 }
07563
07564 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07565 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07566 category = ast_variable_retrieve(msg_cfg, "message", "category");
07567
07568 context = ast_variable_retrieve(msg_cfg, "message", "context");
07569 if (!strncasecmp("macro", context, 5))
07570 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07571 if (!res) {
07572 res = play_message_category(chan, category);
07573 }
07574 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
07575 res = play_message_datetime(chan, vmu, origtime, filename);
07576 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
07577 res = play_message_callerid(chan, vms, cid, context, 0);
07578 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
07579 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07580
07581 if (res == '1')
07582 res = 0;
07583 ast_config_destroy(msg_cfg);
07584
07585 if (!res) {
07586 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07587 vms->heard[vms->curmsg] = 1;
07588 #ifdef IMAP_STORAGE
07589
07590
07591
07592 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07593 wait_file(chan, vms, vms->introfn);
07594 }
07595 #endif
07596 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07597 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07598 res = 0;
07599 }
07600 }
07601 DISPOSE(vms->curdir, vms->curmsg);
07602 return res;
07603 }
07604
07605 #ifdef IMAP_STORAGE
07606 static int imap_remove_file(char *dir, int msgnum)
07607 {
07608 char fn[PATH_MAX];
07609 char full_fn[PATH_MAX];
07610 char intro[PATH_MAX] = {0,};
07611
07612 if (msgnum > -1) {
07613 make_file(fn, sizeof(fn), dir, msgnum);
07614 snprintf(intro, sizeof(intro), "%sintro", fn);
07615 } else
07616 ast_copy_string(fn, dir, sizeof(fn));
07617
07618 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07619 ast_filedelete(fn, NULL);
07620 if (!ast_strlen_zero(intro)) {
07621 ast_filedelete(intro, NULL);
07622 }
07623 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07624 unlink(full_fn);
07625 }
07626 return 0;
07627 }
07628
07629
07630
07631 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07632 {
07633 char *file, *filename;
07634 char *attachment;
07635 char arg[10];
07636 int i;
07637 BODY* body;
07638
07639 file = strrchr(ast_strdupa(dir), '/');
07640 if (file) {
07641 *file++ = '\0';
07642 } else {
07643 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07644 return -1;
07645 }
07646
07647 ast_mutex_lock(&vms->lock);
07648 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07649 mail_fetchstructure(vms->mailstream, i + 1, &body);
07650
07651 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07652 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07653 } else {
07654 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07655 ast_mutex_unlock(&vms->lock);
07656 return -1;
07657 }
07658 filename = strsep(&attachment, ".");
07659 if (!strcmp(filename, file)) {
07660 sprintf(arg, "%d", i + 1);
07661 mail_setflag(vms->mailstream, arg, "\\DELETED");
07662 }
07663 }
07664 mail_expunge(vms->mailstream);
07665 ast_mutex_unlock(&vms->lock);
07666 return 0;
07667 }
07668
07669 #elif !defined(IMAP_STORAGE)
07670 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07671 {
07672 int count_msg, last_msg;
07673
07674 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07675
07676
07677
07678
07679 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07680
07681
07682 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07683
07684
07685 count_msg = count_messages(vmu, vms->curdir);
07686 if (count_msg < 0) {
07687 return count_msg;
07688 } else {
07689 vms->lastmsg = count_msg - 1;
07690 }
07691
07692 if (vm_allocate_dh(vms, vmu, count_msg)) {
07693 return -1;
07694 }
07695
07696
07697
07698
07699
07700
07701
07702
07703 if (vm_lock_path(vms->curdir)) {
07704 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07705 return ERROR_LOCK_PATH;
07706 }
07707
07708
07709 last_msg = last_message_index(vmu, vms->curdir);
07710 ast_unlock_path(vms->curdir);
07711
07712 if (last_msg < -1) {
07713 return last_msg;
07714 } else if (vms->lastmsg != last_msg) {
07715 ast_log(LOG_NOTICE, "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);
07716 }
07717
07718 return 0;
07719 }
07720 #endif
07721
07722 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07723 {
07724 int x = 0;
07725 #ifndef IMAP_STORAGE
07726 int res = 0, nummsg;
07727 char fn2[PATH_MAX];
07728 #endif
07729
07730 if (vms->lastmsg <= -1) {
07731 goto done;
07732 }
07733
07734 vms->curmsg = -1;
07735 #ifndef IMAP_STORAGE
07736
07737 if (vm_lock_path(vms->curdir)) {
07738 return ERROR_LOCK_PATH;
07739 }
07740
07741
07742 for (x = 0; x < vms->lastmsg + 1; x++) {
07743 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07744
07745 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07746 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07747 break;
07748 }
07749 vms->curmsg++;
07750 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07751 if (strcmp(vms->fn, fn2)) {
07752 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07753 }
07754 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07755
07756 res = save_to_folder(vmu, vms, x, 1);
07757 if (res == ERROR_LOCK_PATH) {
07758
07759 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07760 vms->deleted[x] = 0;
07761 vms->heard[x] = 0;
07762 --x;
07763 }
07764 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07765
07766 res = save_to_folder(vmu, vms, x, 10);
07767 if (res == ERROR_LOCK_PATH) {
07768
07769 vms->deleted[x] = 0;
07770 vms->heard[x] = 0;
07771 --x;
07772 }
07773 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07774
07775
07776 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07777 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07778 DELETE(vms->curdir, x, vms->fn, vmu);
07779 }
07780 }
07781 }
07782
07783
07784 nummsg = x - 1;
07785 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07786 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07787 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07788 DELETE(vms->curdir, x, vms->fn, vmu);
07789 }
07790 }
07791 ast_unlock_path(vms->curdir);
07792 #else
07793 if (vms->deleted) {
07794
07795
07796 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
07797 if (vms->deleted[x]) {
07798 ast_debug(3, "IMAP delete of %d\n", x);
07799 DELETE(vms->curdir, x, vms->fn, vmu);
07800 }
07801 }
07802 }
07803 #endif
07804
07805 done:
07806 if (vms->deleted && vmu->maxmsg) {
07807 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
07808 }
07809 if (vms->heard && vmu->maxmsg) {
07810 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
07811 }
07812
07813 return 0;
07814 }
07815
07816
07817
07818
07819
07820
07821
07822 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
07823 {
07824 int cmd;
07825 char *buf;
07826
07827 buf = alloca(strlen(box) + 2);
07828 strcpy(buf, box);
07829 strcat(buf, "s");
07830
07831 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
07832 cmd = ast_play_and_wait(chan, buf);
07833 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07834 } else {
07835 cmd = ast_play_and_wait(chan, "vm-messages");
07836 return cmd ? cmd : ast_play_and_wait(chan, box);
07837 }
07838 }
07839
07840 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
07841 {
07842 int cmd;
07843
07844 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
07845 if (!strcasecmp(box, "vm-INBOX"))
07846 cmd = ast_play_and_wait(chan, "vm-new-e");
07847 else
07848 cmd = ast_play_and_wait(chan, "vm-old-e");
07849 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07850 } else {
07851 cmd = ast_play_and_wait(chan, "vm-messages");
07852 return cmd ? cmd : ast_play_and_wait(chan, box);
07853 }
07854 }
07855
07856 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
07857 {
07858 int cmd;
07859
07860 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
07861 cmd = ast_play_and_wait(chan, "vm-messages");
07862 return cmd ? cmd : ast_play_and_wait(chan, box);
07863 } else {
07864 cmd = ast_play_and_wait(chan, box);
07865 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07866 }
07867 }
07868
07869 static int vm_play_folder_name(struct ast_channel *chan, char *box)
07870 {
07871 int cmd;
07872
07873 if ( !strncasecmp(chan->language, "it", 2) ||
07874 !strncasecmp(chan->language, "es", 2) ||
07875 !strncasecmp(chan->language, "pt", 2)) {
07876 cmd = ast_play_and_wait(chan, "vm-messages");
07877 return cmd ? cmd : ast_play_and_wait(chan, box);
07878 } else if (!strncasecmp(chan->language, "gr", 2)) {
07879 return vm_play_folder_name_gr(chan, box);
07880 } else if (!strncasecmp(chan->language, "he", 2)) {
07881 return ast_play_and_wait(chan, box);
07882 } else if (!strncasecmp(chan->language, "pl", 2)) {
07883 return vm_play_folder_name_pl(chan, box);
07884 } else if (!strncasecmp(chan->language, "ua", 2)) {
07885 return vm_play_folder_name_ua(chan, box);
07886 } else if (!strncasecmp(chan->language, "vi", 2)) {
07887 return ast_play_and_wait(chan, box);
07888 } else {
07889 cmd = ast_play_and_wait(chan, box);
07890 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07891 }
07892 }
07893
07894
07895
07896
07897
07898
07899
07900
07901
07902
07903
07904
07905
07906 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
07907 {
07908 int res = 0;
07909
07910 if (vms->newmessages) {
07911 res = ast_play_and_wait(chan, "vm-youhave");
07912 if (!res)
07913 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
07914 if (!res) {
07915 if ((vms->newmessages == 1)) {
07916 res = ast_play_and_wait(chan, "vm-INBOX");
07917 if (!res)
07918 res = ast_play_and_wait(chan, "vm-message");
07919 } else {
07920 res = ast_play_and_wait(chan, "vm-INBOXs");
07921 if (!res)
07922 res = ast_play_and_wait(chan, "vm-messages");
07923 }
07924 }
07925 } else if (vms->oldmessages){
07926 res = ast_play_and_wait(chan, "vm-youhave");
07927 if (!res)
07928 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
07929 if ((vms->oldmessages == 1)){
07930 res = ast_play_and_wait(chan, "vm-Old");
07931 if (!res)
07932 res = ast_play_and_wait(chan, "vm-message");
07933 } else {
07934 res = ast_play_and_wait(chan, "vm-Olds");
07935 if (!res)
07936 res = ast_play_and_wait(chan, "vm-messages");
07937 }
07938 } else if (!vms->oldmessages && !vms->newmessages)
07939 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
07940 return res;
07941 }
07942
07943
07944
07945
07946
07947
07948
07949
07950
07951
07952
07953
07954
07955
07956
07957
07958
07959
07960
07961
07962
07963
07964
07965
07966
07967
07968
07969
07970
07971
07972
07973
07974
07975
07976
07977
07978
07979
07980
07981
07982
07983
07984
07985
07986
07987
07988
07989
07990
07991
07992
07993
07994
07995
07996
07997
07998
07999
08000 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08001 {
08002 int res;
08003 int lastnum = 0;
08004
08005 res = ast_play_and_wait(chan, "vm-youhave");
08006
08007 if (!res && vms->newmessages) {
08008 lastnum = vms->newmessages;
08009
08010 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08011 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08012 }
08013
08014 if (!res && vms->oldmessages) {
08015 res = ast_play_and_wait(chan, "vm-and");
08016 }
08017 }
08018
08019 if (!res && vms->oldmessages) {
08020 lastnum = vms->oldmessages;
08021
08022 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08023 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08024 }
08025 }
08026
08027 if (!res) {
08028 if (lastnum == 0) {
08029 res = ast_play_and_wait(chan, "vm-no");
08030 }
08031 if (!res) {
08032 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08033 }
08034 }
08035
08036 return res;
08037 }
08038
08039
08040 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08041 {
08042 int res = 0;
08043
08044
08045 if (!res) {
08046 if ((vms->newmessages) || (vms->oldmessages)) {
08047 res = ast_play_and_wait(chan, "vm-youhave");
08048 }
08049
08050
08051
08052
08053
08054 if (vms->newmessages) {
08055 if (!res) {
08056 if (vms->newmessages == 1) {
08057 res = ast_play_and_wait(chan, "vm-INBOX1");
08058 } else {
08059 if (vms->newmessages == 2) {
08060 res = ast_play_and_wait(chan, "vm-shtei");
08061 } else {
08062 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08063 }
08064 res = ast_play_and_wait(chan, "vm-INBOX");
08065 }
08066 }
08067 if (vms->oldmessages && !res) {
08068 res = ast_play_and_wait(chan, "vm-and");
08069 if (vms->oldmessages == 1) {
08070 res = ast_play_and_wait(chan, "vm-Old1");
08071 } else {
08072 if (vms->oldmessages == 2) {
08073 res = ast_play_and_wait(chan, "vm-shtei");
08074 } else {
08075 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08076 }
08077 res = ast_play_and_wait(chan, "vm-Old");
08078 }
08079 }
08080 }
08081 if (!res && vms->oldmessages && !vms->newmessages) {
08082 if (!res) {
08083 if (vms->oldmessages == 1) {
08084 res = ast_play_and_wait(chan, "vm-Old1");
08085 } else {
08086 if (vms->oldmessages == 2) {
08087 res = ast_play_and_wait(chan, "vm-shtei");
08088 } else {
08089 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08090 }
08091 res = ast_play_and_wait(chan, "vm-Old");
08092 }
08093 }
08094 }
08095 if (!res) {
08096 if (!vms->oldmessages && !vms->newmessages) {
08097 if (!res) {
08098 res = ast_play_and_wait(chan, "vm-nomessages");
08099 }
08100 }
08101 }
08102 }
08103 return res;
08104 }
08105
08106
08107 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08108 {
08109 int res;
08110
08111
08112 res = ast_play_and_wait(chan, "vm-youhave");
08113 if (!res) {
08114 if (vms->urgentmessages) {
08115 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08116 if (!res)
08117 res = ast_play_and_wait(chan, "vm-Urgent");
08118 if ((vms->oldmessages || vms->newmessages) && !res) {
08119 res = ast_play_and_wait(chan, "vm-and");
08120 } else if (!res) {
08121 if ((vms->urgentmessages == 1))
08122 res = ast_play_and_wait(chan, "vm-message");
08123 else
08124 res = ast_play_and_wait(chan, "vm-messages");
08125 }
08126 }
08127 if (vms->newmessages) {
08128 res = say_and_wait(chan, vms->newmessages, chan->language);
08129 if (!res)
08130 res = ast_play_and_wait(chan, "vm-INBOX");
08131 if (vms->oldmessages && !res)
08132 res = ast_play_and_wait(chan, "vm-and");
08133 else if (!res) {
08134 if ((vms->newmessages == 1))
08135 res = ast_play_and_wait(chan, "vm-message");
08136 else
08137 res = ast_play_and_wait(chan, "vm-messages");
08138 }
08139
08140 }
08141 if (!res && vms->oldmessages) {
08142 res = say_and_wait(chan, vms->oldmessages, chan->language);
08143 if (!res)
08144 res = ast_play_and_wait(chan, "vm-Old");
08145 if (!res) {
08146 if (vms->oldmessages == 1)
08147 res = ast_play_and_wait(chan, "vm-message");
08148 else
08149 res = ast_play_and_wait(chan, "vm-messages");
08150 }
08151 }
08152 if (!res) {
08153 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08154 res = ast_play_and_wait(chan, "vm-no");
08155 if (!res)
08156 res = ast_play_and_wait(chan, "vm-messages");
08157 }
08158 }
08159 }
08160 return res;
08161 }
08162
08163
08164 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08165 {
08166
08167 int res;
08168 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08169 res = ast_play_and_wait(chan, "vm-no") ||
08170 ast_play_and_wait(chan, "vm-message");
08171 else
08172 res = ast_play_and_wait(chan, "vm-youhave");
08173 if (!res && vms->newmessages) {
08174 res = (vms->newmessages == 1) ?
08175 ast_play_and_wait(chan, "digits/un") ||
08176 ast_play_and_wait(chan, "vm-nuovo") ||
08177 ast_play_and_wait(chan, "vm-message") :
08178
08179 say_and_wait(chan, vms->newmessages, chan->language) ||
08180 ast_play_and_wait(chan, "vm-nuovi") ||
08181 ast_play_and_wait(chan, "vm-messages");
08182 if (!res && vms->oldmessages)
08183 res = ast_play_and_wait(chan, "vm-and");
08184 }
08185 if (!res && vms->oldmessages) {
08186 res = (vms->oldmessages == 1) ?
08187 ast_play_and_wait(chan, "digits/un") ||
08188 ast_play_and_wait(chan, "vm-vecchio") ||
08189 ast_play_and_wait(chan, "vm-message") :
08190
08191 say_and_wait(chan, vms->oldmessages, chan->language) ||
08192 ast_play_and_wait(chan, "vm-vecchi") ||
08193 ast_play_and_wait(chan, "vm-messages");
08194 }
08195 return res;
08196 }
08197
08198
08199 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08200 {
08201
08202 int res;
08203 div_t num;
08204
08205 if (!vms->oldmessages && !vms->newmessages) {
08206 res = ast_play_and_wait(chan, "vm-no");
08207 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08208 return res;
08209 } else {
08210 res = ast_play_and_wait(chan, "vm-youhave");
08211 }
08212
08213 if (vms->newmessages) {
08214 num = div(vms->newmessages, 10);
08215 if (vms->newmessages == 1) {
08216 res = ast_play_and_wait(chan, "digits/1-a");
08217 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08218 res = res ? res : ast_play_and_wait(chan, "vm-message");
08219 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08220 if (num.rem == 2) {
08221 if (!num.quot) {
08222 res = ast_play_and_wait(chan, "digits/2-ie");
08223 } else {
08224 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08225 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08226 }
08227 } else {
08228 res = say_and_wait(chan, vms->newmessages, chan->language);
08229 }
08230 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08231 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08232 } else {
08233 res = say_and_wait(chan, vms->newmessages, chan->language);
08234 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08235 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08236 }
08237 if (!res && vms->oldmessages)
08238 res = ast_play_and_wait(chan, "vm-and");
08239 }
08240 if (!res && vms->oldmessages) {
08241 num = div(vms->oldmessages, 10);
08242 if (vms->oldmessages == 1) {
08243 res = ast_play_and_wait(chan, "digits/1-a");
08244 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08245 res = res ? res : ast_play_and_wait(chan, "vm-message");
08246 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08247 if (num.rem == 2) {
08248 if (!num.quot) {
08249 res = ast_play_and_wait(chan, "digits/2-ie");
08250 } else {
08251 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08252 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08253 }
08254 } else {
08255 res = say_and_wait(chan, vms->oldmessages, chan->language);
08256 }
08257 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08258 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08259 } else {
08260 res = say_and_wait(chan, vms->oldmessages, chan->language);
08261 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08262 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08263 }
08264 }
08265
08266 return res;
08267 }
08268
08269
08270 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08271 {
08272
08273 int res;
08274
08275 res = ast_play_and_wait(chan, "vm-youhave");
08276 if (res)
08277 return res;
08278
08279 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08280 res = ast_play_and_wait(chan, "vm-no");
08281 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08282 return res;
08283 }
08284
08285 if (vms->newmessages) {
08286 if ((vms->newmessages == 1)) {
08287 res = ast_play_and_wait(chan, "digits/ett");
08288 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08289 res = res ? res : ast_play_and_wait(chan, "vm-message");
08290 } else {
08291 res = say_and_wait(chan, vms->newmessages, chan->language);
08292 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08293 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08294 }
08295 if (!res && vms->oldmessages)
08296 res = ast_play_and_wait(chan, "vm-and");
08297 }
08298 if (!res && vms->oldmessages) {
08299 if (vms->oldmessages == 1) {
08300 res = ast_play_and_wait(chan, "digits/ett");
08301 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08302 res = res ? res : ast_play_and_wait(chan, "vm-message");
08303 } else {
08304 res = say_and_wait(chan, vms->oldmessages, chan->language);
08305 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08306 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08307 }
08308 }
08309
08310 return res;
08311 }
08312
08313
08314 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08315 {
08316
08317 int res;
08318
08319 res = ast_play_and_wait(chan, "vm-youhave");
08320 if (res)
08321 return res;
08322
08323 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08324 res = ast_play_and_wait(chan, "vm-no");
08325 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08326 return res;
08327 }
08328
08329 if (vms->newmessages) {
08330 if ((vms->newmessages == 1)) {
08331 res = ast_play_and_wait(chan, "digits/1");
08332 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08333 res = res ? res : ast_play_and_wait(chan, "vm-message");
08334 } else {
08335 res = say_and_wait(chan, vms->newmessages, chan->language);
08336 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08337 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08338 }
08339 if (!res && vms->oldmessages)
08340 res = ast_play_and_wait(chan, "vm-and");
08341 }
08342 if (!res && vms->oldmessages) {
08343 if (vms->oldmessages == 1) {
08344 res = ast_play_and_wait(chan, "digits/1");
08345 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08346 res = res ? res : ast_play_and_wait(chan, "vm-message");
08347 } else {
08348 res = say_and_wait(chan, vms->oldmessages, chan->language);
08349 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08350 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08351 }
08352 }
08353
08354 return res;
08355 }
08356
08357
08358 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08359 {
08360
08361 int res;
08362 res = ast_play_and_wait(chan, "vm-youhave");
08363 if (!res) {
08364 if (vms->newmessages) {
08365 if ((vms->newmessages == 1))
08366 res = ast_play_and_wait(chan, "digits/1F");
08367 else
08368 res = say_and_wait(chan, vms->newmessages, chan->language);
08369 if (!res)
08370 res = ast_play_and_wait(chan, "vm-INBOX");
08371 if (vms->oldmessages && !res)
08372 res = ast_play_and_wait(chan, "vm-and");
08373 else if (!res) {
08374 if ((vms->newmessages == 1))
08375 res = ast_play_and_wait(chan, "vm-message");
08376 else
08377 res = ast_play_and_wait(chan, "vm-messages");
08378 }
08379
08380 }
08381 if (!res && vms->oldmessages) {
08382 if (vms->oldmessages == 1)
08383 res = ast_play_and_wait(chan, "digits/1F");
08384 else
08385 res = say_and_wait(chan, vms->oldmessages, chan->language);
08386 if (!res)
08387 res = ast_play_and_wait(chan, "vm-Old");
08388 if (!res) {
08389 if (vms->oldmessages == 1)
08390 res = ast_play_and_wait(chan, "vm-message");
08391 else
08392 res = ast_play_and_wait(chan, "vm-messages");
08393 }
08394 }
08395 if (!res) {
08396 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08397 res = ast_play_and_wait(chan, "vm-no");
08398 if (!res)
08399 res = ast_play_and_wait(chan, "vm-messages");
08400 }
08401 }
08402 }
08403 return res;
08404 }
08405
08406
08407 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08408 {
08409
08410 int res;
08411 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08412 res = ast_play_and_wait(chan, "vm-youhaveno");
08413 if (!res)
08414 res = ast_play_and_wait(chan, "vm-messages");
08415 } else {
08416 res = ast_play_and_wait(chan, "vm-youhave");
08417 }
08418 if (!res) {
08419 if (vms->newmessages) {
08420 if (!res) {
08421 if ((vms->newmessages == 1)) {
08422 res = ast_play_and_wait(chan, "digits/1M");
08423 if (!res)
08424 res = ast_play_and_wait(chan, "vm-message");
08425 if (!res)
08426 res = ast_play_and_wait(chan, "vm-INBOXs");
08427 } else {
08428 res = say_and_wait(chan, vms->newmessages, chan->language);
08429 if (!res)
08430 res = ast_play_and_wait(chan, "vm-messages");
08431 if (!res)
08432 res = ast_play_and_wait(chan, "vm-INBOX");
08433 }
08434 }
08435 if (vms->oldmessages && !res)
08436 res = ast_play_and_wait(chan, "vm-and");
08437 }
08438 if (vms->oldmessages) {
08439 if (!res) {
08440 if (vms->oldmessages == 1) {
08441 res = ast_play_and_wait(chan, "digits/1M");
08442 if (!res)
08443 res = ast_play_and_wait(chan, "vm-message");
08444 if (!res)
08445 res = ast_play_and_wait(chan, "vm-Olds");
08446 } else {
08447 res = say_and_wait(chan, vms->oldmessages, chan->language);
08448 if (!res)
08449 res = ast_play_and_wait(chan, "vm-messages");
08450 if (!res)
08451 res = ast_play_and_wait(chan, "vm-Old");
08452 }
08453 }
08454 }
08455 }
08456 return res;
08457 }
08458
08459
08460 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08461
08462 int res;
08463 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08464 res = ast_play_and_wait(chan, "vm-nomessages");
08465 return res;
08466 } else {
08467 res = ast_play_and_wait(chan, "vm-youhave");
08468 }
08469 if (vms->newmessages) {
08470 if (!res)
08471 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08472 if ((vms->newmessages == 1)) {
08473 if (!res)
08474 res = ast_play_and_wait(chan, "vm-message");
08475 if (!res)
08476 res = ast_play_and_wait(chan, "vm-INBOXs");
08477 } else {
08478 if (!res)
08479 res = ast_play_and_wait(chan, "vm-messages");
08480 if (!res)
08481 res = ast_play_and_wait(chan, "vm-INBOX");
08482 }
08483 if (vms->oldmessages && !res)
08484 res = ast_play_and_wait(chan, "vm-and");
08485 }
08486 if (vms->oldmessages) {
08487 if (!res)
08488 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08489 if (vms->oldmessages == 1) {
08490 if (!res)
08491 res = ast_play_and_wait(chan, "vm-message");
08492 if (!res)
08493 res = ast_play_and_wait(chan, "vm-Olds");
08494 } else {
08495 if (!res)
08496 res = ast_play_and_wait(chan, "vm-messages");
08497 if (!res)
08498 res = ast_play_and_wait(chan, "vm-Old");
08499 }
08500 }
08501 return res;
08502 }
08503
08504
08505 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08506 {
08507
08508 int res;
08509 res = ast_play_and_wait(chan, "vm-youhave");
08510 if (!res) {
08511 if (vms->newmessages) {
08512 res = say_and_wait(chan, vms->newmessages, chan->language);
08513 if (!res)
08514 res = ast_play_and_wait(chan, "vm-INBOX");
08515 if (vms->oldmessages && !res)
08516 res = ast_play_and_wait(chan, "vm-and");
08517 else if (!res) {
08518 if ((vms->newmessages == 1))
08519 res = ast_play_and_wait(chan, "vm-message");
08520 else
08521 res = ast_play_and_wait(chan, "vm-messages");
08522 }
08523
08524 }
08525 if (!res && vms->oldmessages) {
08526 res = say_and_wait(chan, vms->oldmessages, chan->language);
08527 if (!res)
08528 res = ast_play_and_wait(chan, "vm-Old");
08529 if (!res) {
08530 if (vms->oldmessages == 1)
08531 res = ast_play_and_wait(chan, "vm-message");
08532 else
08533 res = ast_play_and_wait(chan, "vm-messages");
08534 }
08535 }
08536 if (!res) {
08537 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08538 res = ast_play_and_wait(chan, "vm-no");
08539 if (!res)
08540 res = ast_play_and_wait(chan, "vm-messages");
08541 }
08542 }
08543 }
08544 return res;
08545 }
08546
08547
08548 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08549 {
08550
08551 int res;
08552 res = ast_play_and_wait(chan, "vm-youhave");
08553 if (!res) {
08554 if (vms->newmessages) {
08555 res = say_and_wait(chan, vms->newmessages, chan->language);
08556 if (!res) {
08557 if (vms->newmessages == 1)
08558 res = ast_play_and_wait(chan, "vm-INBOXs");
08559 else
08560 res = ast_play_and_wait(chan, "vm-INBOX");
08561 }
08562 if (vms->oldmessages && !res)
08563 res = ast_play_and_wait(chan, "vm-and");
08564 else if (!res) {
08565 if ((vms->newmessages == 1))
08566 res = ast_play_and_wait(chan, "vm-message");
08567 else
08568 res = ast_play_and_wait(chan, "vm-messages");
08569 }
08570
08571 }
08572 if (!res && vms->oldmessages) {
08573 res = say_and_wait(chan, vms->oldmessages, chan->language);
08574 if (!res) {
08575 if (vms->oldmessages == 1)
08576 res = ast_play_and_wait(chan, "vm-Olds");
08577 else
08578 res = ast_play_and_wait(chan, "vm-Old");
08579 }
08580 if (!res) {
08581 if (vms->oldmessages == 1)
08582 res = ast_play_and_wait(chan, "vm-message");
08583 else
08584 res = ast_play_and_wait(chan, "vm-messages");
08585 }
08586 }
08587 if (!res) {
08588 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08589 res = ast_play_and_wait(chan, "vm-no");
08590 if (!res)
08591 res = ast_play_and_wait(chan, "vm-messages");
08592 }
08593 }
08594 }
08595 return res;
08596 }
08597
08598
08599 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08600 {
08601
08602 int res;
08603 res = ast_play_and_wait(chan, "vm-youhave");
08604 if (!res) {
08605 if (vms->newmessages) {
08606 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08607 if (!res) {
08608 if ((vms->newmessages == 1)) {
08609 res = ast_play_and_wait(chan, "vm-message");
08610 if (!res)
08611 res = ast_play_and_wait(chan, "vm-INBOXs");
08612 } else {
08613 res = ast_play_and_wait(chan, "vm-messages");
08614 if (!res)
08615 res = ast_play_and_wait(chan, "vm-INBOX");
08616 }
08617 }
08618 if (vms->oldmessages && !res)
08619 res = ast_play_and_wait(chan, "vm-and");
08620 }
08621 if (!res && vms->oldmessages) {
08622 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08623 if (!res) {
08624 if (vms->oldmessages == 1) {
08625 res = ast_play_and_wait(chan, "vm-message");
08626 if (!res)
08627 res = ast_play_and_wait(chan, "vm-Olds");
08628 } else {
08629 res = ast_play_and_wait(chan, "vm-messages");
08630 if (!res)
08631 res = ast_play_and_wait(chan, "vm-Old");
08632 }
08633 }
08634 }
08635 if (!res) {
08636 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08637 res = ast_play_and_wait(chan, "vm-no");
08638 if (!res)
08639 res = ast_play_and_wait(chan, "vm-messages");
08640 }
08641 }
08642 }
08643 return res;
08644 }
08645
08646
08647
08648
08649
08650
08651
08652
08653
08654
08655
08656
08657
08658
08659
08660
08661
08662 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08663 {
08664 int res;
08665 res = ast_play_and_wait(chan, "vm-youhave");
08666 if (!res) {
08667 if (vms->newmessages) {
08668 if (vms->newmessages == 1) {
08669 res = ast_play_and_wait(chan, "digits/jednu");
08670 } else {
08671 res = say_and_wait(chan, vms->newmessages, chan->language);
08672 }
08673 if (!res) {
08674 if ((vms->newmessages == 1))
08675 res = ast_play_and_wait(chan, "vm-novou");
08676 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08677 res = ast_play_and_wait(chan, "vm-nove");
08678 if (vms->newmessages > 4)
08679 res = ast_play_and_wait(chan, "vm-novych");
08680 }
08681 if (vms->oldmessages && !res)
08682 res = ast_play_and_wait(chan, "vm-and");
08683 else if (!res) {
08684 if ((vms->newmessages == 1))
08685 res = ast_play_and_wait(chan, "vm-zpravu");
08686 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08687 res = ast_play_and_wait(chan, "vm-zpravy");
08688 if (vms->newmessages > 4)
08689 res = ast_play_and_wait(chan, "vm-zprav");
08690 }
08691 }
08692 if (!res && vms->oldmessages) {
08693 res = say_and_wait(chan, vms->oldmessages, chan->language);
08694 if (!res) {
08695 if ((vms->oldmessages == 1))
08696 res = ast_play_and_wait(chan, "vm-starou");
08697 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08698 res = ast_play_and_wait(chan, "vm-stare");
08699 if (vms->oldmessages > 4)
08700 res = ast_play_and_wait(chan, "vm-starych");
08701 }
08702 if (!res) {
08703 if ((vms->oldmessages == 1))
08704 res = ast_play_and_wait(chan, "vm-zpravu");
08705 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08706 res = ast_play_and_wait(chan, "vm-zpravy");
08707 if (vms->oldmessages > 4)
08708 res = ast_play_and_wait(chan, "vm-zprav");
08709 }
08710 }
08711 if (!res) {
08712 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08713 res = ast_play_and_wait(chan, "vm-no");
08714 if (!res)
08715 res = ast_play_and_wait(chan, "vm-zpravy");
08716 }
08717 }
08718 }
08719 return res;
08720 }
08721
08722
08723 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08724 {
08725 int res;
08726
08727 res = ast_play_and_wait(chan, "vm-you");
08728
08729 if (!res && vms->newmessages) {
08730 res = ast_play_and_wait(chan, "vm-have");
08731 if (!res)
08732 res = say_and_wait(chan, vms->newmessages, chan->language);
08733 if (!res)
08734 res = ast_play_and_wait(chan, "vm-tong");
08735 if (!res)
08736 res = ast_play_and_wait(chan, "vm-INBOX");
08737 if (vms->oldmessages && !res)
08738 res = ast_play_and_wait(chan, "vm-and");
08739 else if (!res)
08740 res = ast_play_and_wait(chan, "vm-messages");
08741 }
08742 if (!res && vms->oldmessages) {
08743 res = ast_play_and_wait(chan, "vm-have");
08744 if (!res)
08745 res = say_and_wait(chan, vms->oldmessages, chan->language);
08746 if (!res)
08747 res = ast_play_and_wait(chan, "vm-tong");
08748 if (!res)
08749 res = ast_play_and_wait(chan, "vm-Old");
08750 if (!res)
08751 res = ast_play_and_wait(chan, "vm-messages");
08752 }
08753 if (!res && !vms->oldmessages && !vms->newmessages) {
08754 res = ast_play_and_wait(chan, "vm-haveno");
08755 if (!res)
08756 res = ast_play_and_wait(chan, "vm-messages");
08757 }
08758 return res;
08759 }
08760
08761
08762 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08763 {
08764 int res;
08765
08766
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 res = ast_play_and_wait(chan, "vm-INBOX");
08773 if (vms->oldmessages && !res)
08774 res = ast_play_and_wait(chan, "vm-and");
08775 }
08776 if (!res && vms->oldmessages) {
08777 res = say_and_wait(chan, vms->oldmessages, chan->language);
08778 if (!res)
08779 res = ast_play_and_wait(chan, "vm-Old");
08780 }
08781 if (!res) {
08782 if (!vms->oldmessages && !vms->newmessages) {
08783 res = ast_play_and_wait(chan, "vm-no");
08784 if (!res)
08785 res = ast_play_and_wait(chan, "vm-message");
08786 }
08787 }
08788 }
08789 return res;
08790 }
08791
08792 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08793 {
08794 char prefile[256];
08795
08796
08797 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08798 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08799 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08800 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08801 ast_play_and_wait(chan, "vm-tempgreetactive");
08802 }
08803 DISPOSE(prefile, -1);
08804 }
08805
08806
08807 if (0) {
08808 return 0;
08809 } else if (!strncasecmp(chan->language, "cs", 2)) {
08810 return vm_intro_cs(chan, vms);
08811 } else if (!strncasecmp(chan->language, "cz", 2)) {
08812 static int deprecation_warning = 0;
08813 if (deprecation_warning++ % 10 == 0) {
08814 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
08815 }
08816 return vm_intro_cs(chan, vms);
08817 } else if (!strncasecmp(chan->language, "de", 2)) {
08818 return vm_intro_de(chan, vms);
08819 } else if (!strncasecmp(chan->language, "es", 2)) {
08820 return vm_intro_es(chan, vms);
08821 } else if (!strncasecmp(chan->language, "fr", 2)) {
08822 return vm_intro_fr(chan, vms);
08823 } else if (!strncasecmp(chan->language, "gr", 2)) {
08824 return vm_intro_gr(chan, vms);
08825 } else if (!strncasecmp(chan->language, "he", 2)) {
08826 return vm_intro_he(chan, vms);
08827 } else if (!strncasecmp(chan->language, "it", 2)) {
08828 return vm_intro_it(chan, vms);
08829 } else if (!strncasecmp(chan->language, "nl", 2)) {
08830 return vm_intro_nl(chan, vms);
08831 } else if (!strncasecmp(chan->language, "no", 2)) {
08832 return vm_intro_no(chan, vms);
08833 } else if (!strncasecmp(chan->language, "pl", 2)) {
08834 return vm_intro_pl(chan, vms);
08835 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
08836 return vm_intro_pt_BR(chan, vms);
08837 } else if (!strncasecmp(chan->language, "pt", 2)) {
08838 return vm_intro_pt(chan, vms);
08839 } else if (!strncasecmp(chan->language, "ru", 2)) {
08840 return vm_intro_multilang(chan, vms, "n");
08841 } else if (!strncasecmp(chan->language, "se", 2)) {
08842 return vm_intro_se(chan, vms);
08843 } else if (!strncasecmp(chan->language, "ua", 2)) {
08844 return vm_intro_multilang(chan, vms, "n");
08845 } else if (!strncasecmp(chan->language, "vi", 2)) {
08846 return vm_intro_vi(chan, vms);
08847 } else if (!strncasecmp(chan->language, "zh", 2)) {
08848 return vm_intro_zh(chan, vms);
08849 } else {
08850 return vm_intro_en(chan, vms);
08851 }
08852 }
08853
08854 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08855 {
08856 int res = 0;
08857
08858 while (!res) {
08859 if (vms->starting) {
08860 if (vms->lastmsg > -1) {
08861 if (skipadvanced)
08862 res = ast_play_and_wait(chan, "vm-onefor-full");
08863 else
08864 res = ast_play_and_wait(chan, "vm-onefor");
08865 if (!res)
08866 res = vm_play_folder_name(chan, vms->vmbox);
08867 }
08868 if (!res) {
08869 if (skipadvanced)
08870 res = ast_play_and_wait(chan, "vm-opts-full");
08871 else
08872 res = ast_play_and_wait(chan, "vm-opts");
08873 }
08874 } else {
08875
08876 if (skipadvanced) {
08877 res = ast_play_and_wait(chan, "vm-onefor-full");
08878 if (!res)
08879 res = vm_play_folder_name(chan, vms->vmbox);
08880 res = ast_play_and_wait(chan, "vm-opts-full");
08881 }
08882
08883
08884
08885
08886
08887
08888 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
08889 res = ast_play_and_wait(chan, "vm-prev");
08890 }
08891 if (!res && !skipadvanced)
08892 res = ast_play_and_wait(chan, "vm-advopts");
08893 if (!res)
08894 res = ast_play_and_wait(chan, "vm-repeat");
08895
08896
08897
08898
08899
08900
08901 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
08902 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
08903 res = ast_play_and_wait(chan, "vm-next");
08904 }
08905 if (!res) {
08906 if (!vms->deleted[vms->curmsg])
08907 res = ast_play_and_wait(chan, "vm-delete");
08908 else
08909 res = ast_play_and_wait(chan, "vm-undelete");
08910 if (!res)
08911 res = ast_play_and_wait(chan, "vm-toforward");
08912 if (!res)
08913 res = ast_play_and_wait(chan, "vm-savemessage");
08914 }
08915 }
08916 if (!res) {
08917 res = ast_play_and_wait(chan, "vm-helpexit");
08918 }
08919 if (!res)
08920 res = ast_waitfordigit(chan, 6000);
08921 if (!res) {
08922 vms->repeats++;
08923 if (vms->repeats > 2) {
08924 res = 't';
08925 }
08926 }
08927 }
08928 return res;
08929 }
08930
08931 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08932 {
08933 int res = 0;
08934
08935 while (!res) {
08936 if (vms->lastmsg > -1) {
08937 res = ast_play_and_wait(chan, "vm-listen");
08938 if (!res)
08939 res = vm_play_folder_name(chan, vms->vmbox);
08940 if (!res)
08941 res = ast_play_and_wait(chan, "press");
08942 if (!res)
08943 res = ast_play_and_wait(chan, "digits/1");
08944 }
08945 if (!res)
08946 res = ast_play_and_wait(chan, "vm-opts");
08947 if (!res) {
08948 vms->starting = 0;
08949 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08950 }
08951 }
08952 return res;
08953 }
08954
08955 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08956 {
08957 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
08958 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
08959 } else {
08960 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08961 }
08962 }
08963
08964
08965 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08966 {
08967 int cmd = 0;
08968 int duration = 0;
08969 int tries = 0;
08970 char newpassword[80] = "";
08971 char newpassword2[80] = "";
08972 char prefile[PATH_MAX] = "";
08973 unsigned char buf[256];
08974 int bytes = 0;
08975
08976 if (ast_adsi_available(chan)) {
08977 bytes += adsi_logo(buf + bytes);
08978 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
08979 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08980 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08981 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08982 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08983 }
08984
08985
08986
08987 for (;;) {
08988 newpassword[1] = '\0';
08989 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
08990 if (cmd == '#')
08991 newpassword[0] = '\0';
08992 if (cmd < 0 || cmd == 't' || cmd == '#')
08993 return cmd;
08994 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
08995 if (cmd < 0 || cmd == 't' || cmd == '#')
08996 return cmd;
08997 cmd = check_password(vmu, newpassword);
08998 if (cmd != 0) {
08999 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09000 cmd = ast_play_and_wait(chan, vm_invalid_password);
09001 } else {
09002 newpassword2[1] = '\0';
09003 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09004 if (cmd == '#')
09005 newpassword2[0] = '\0';
09006 if (cmd < 0 || cmd == 't' || cmd == '#')
09007 return cmd;
09008 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09009 if (cmd < 0 || cmd == 't' || cmd == '#')
09010 return cmd;
09011 if (!strcmp(newpassword, newpassword2))
09012 break;
09013 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09014 cmd = ast_play_and_wait(chan, vm_mismatch);
09015 }
09016 if (++tries == 3)
09017 return -1;
09018 if (cmd != 0) {
09019 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09020 }
09021 }
09022 if (pwdchange & PWDCHANGE_INTERNAL)
09023 vm_change_password(vmu, newpassword);
09024 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09025 vm_change_password_shell(vmu, newpassword);
09026
09027 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09028 cmd = ast_play_and_wait(chan, vm_passchanged);
09029
09030
09031 if (ast_test_flag(vmu, VM_FORCENAME)) {
09032 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09033 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09034 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09035 if (cmd < 0 || cmd == 't' || cmd == '#')
09036 return cmd;
09037 }
09038 }
09039
09040
09041 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09042 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09043 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09044 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09045 if (cmd < 0 || cmd == 't' || cmd == '#')
09046 return cmd;
09047 }
09048
09049 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09050 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09051 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09052 if (cmd < 0 || cmd == 't' || cmd == '#')
09053 return cmd;
09054 }
09055 }
09056
09057 return cmd;
09058 }
09059
09060 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09061 {
09062 int cmd = 0;
09063 int retries = 0;
09064 int duration = 0;
09065 char newpassword[80] = "";
09066 char newpassword2[80] = "";
09067 char prefile[PATH_MAX] = "";
09068 unsigned char buf[256];
09069 int bytes = 0;
09070
09071 if (ast_adsi_available(chan)) {
09072 bytes += adsi_logo(buf + bytes);
09073 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09074 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09075 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09076 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09077 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09078 }
09079 while ((cmd >= 0) && (cmd != 't')) {
09080 if (cmd)
09081 retries = 0;
09082 switch (cmd) {
09083 case '1':
09084 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09085 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09086 break;
09087 case '2':
09088 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09089 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09090 break;
09091 case '3':
09092 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09093 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09094 break;
09095 case '4':
09096 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09097 break;
09098 case '5':
09099 if (vmu->password[0] == '-') {
09100 cmd = ast_play_and_wait(chan, "vm-no");
09101 break;
09102 }
09103 newpassword[1] = '\0';
09104 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09105 if (cmd == '#')
09106 newpassword[0] = '\0';
09107 else {
09108 if (cmd < 0)
09109 break;
09110 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09111 break;
09112 }
09113 }
09114 cmd = check_password(vmu, newpassword);
09115 if (cmd != 0) {
09116 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09117 cmd = ast_play_and_wait(chan, vm_invalid_password);
09118 if (!cmd) {
09119 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09120 }
09121 break;
09122 }
09123 newpassword2[1] = '\0';
09124 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09125 if (cmd == '#')
09126 newpassword2[0] = '\0';
09127 else {
09128 if (cmd < 0)
09129 break;
09130
09131 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09132 break;
09133 }
09134 }
09135 if (strcmp(newpassword, newpassword2)) {
09136 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09137 cmd = ast_play_and_wait(chan, vm_mismatch);
09138 if (!cmd) {
09139 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09140 }
09141 break;
09142 }
09143 if (pwdchange & PWDCHANGE_INTERNAL)
09144 vm_change_password(vmu, newpassword);
09145 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09146 vm_change_password_shell(vmu, newpassword);
09147
09148 ast_debug(1, "User %s set password to %s of length %d\n",
09149 vms->username, newpassword, (int) strlen(newpassword));
09150 cmd = ast_play_and_wait(chan, vm_passchanged);
09151 break;
09152 case '*':
09153 cmd = 't';
09154 break;
09155 default:
09156 cmd = 0;
09157 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09158 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09159 if (ast_fileexists(prefile, NULL, NULL)) {
09160 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09161 }
09162 DISPOSE(prefile, -1);
09163 if (!cmd) {
09164 cmd = ast_play_and_wait(chan, "vm-options");
09165 }
09166 if (!cmd) {
09167 cmd = ast_waitfordigit(chan, 6000);
09168 }
09169 if (!cmd) {
09170 retries++;
09171 }
09172 if (retries > 3) {
09173 cmd = 't';
09174 }
09175 }
09176 }
09177 if (cmd == 't')
09178 cmd = 0;
09179 return cmd;
09180 }
09181
09182
09183
09184
09185
09186
09187
09188
09189
09190
09191
09192
09193
09194
09195
09196
09197
09198 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09199 {
09200 int cmd = 0;
09201 int retries = 0;
09202 int duration = 0;
09203 char prefile[PATH_MAX] = "";
09204 unsigned char buf[256];
09205 int bytes = 0;
09206
09207 if (ast_adsi_available(chan)) {
09208 bytes += adsi_logo(buf + bytes);
09209 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09210 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09211 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09212 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09213 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09214 }
09215
09216 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09217 while ((cmd >= 0) && (cmd != 't')) {
09218 if (cmd)
09219 retries = 0;
09220 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09221 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09222 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09223 cmd = 't';
09224 } else {
09225 switch (cmd) {
09226 case '1':
09227 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09228 break;
09229 case '2':
09230 DELETE(prefile, -1, prefile, vmu);
09231 ast_play_and_wait(chan, "vm-tempremoved");
09232 cmd = 't';
09233 break;
09234 case '*':
09235 cmd = 't';
09236 break;
09237 default:
09238 cmd = ast_play_and_wait(chan,
09239 ast_fileexists(prefile, NULL, NULL) > 0 ?
09240 "vm-tempgreeting2" : "vm-tempgreeting");
09241 if (!cmd)
09242 cmd = ast_waitfordigit(chan, 6000);
09243 if (!cmd)
09244 retries++;
09245 if (retries > 3)
09246 cmd = 't';
09247 }
09248 }
09249 DISPOSE(prefile, -1);
09250 }
09251 if (cmd == 't')
09252 cmd = 0;
09253 return cmd;
09254 }
09255
09256
09257
09258
09259
09260
09261
09262
09263
09264 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09265 {
09266 int cmd = 0;
09267
09268 if (vms->lastmsg > -1) {
09269 cmd = play_message(chan, vmu, vms);
09270 } else {
09271 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09272 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09273 if (!cmd) {
09274 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09275 cmd = ast_play_and_wait(chan, vms->fn);
09276 }
09277 if (!cmd)
09278 cmd = ast_play_and_wait(chan, "vm-messages");
09279 } else {
09280 if (!cmd)
09281 cmd = ast_play_and_wait(chan, "vm-messages");
09282 if (!cmd) {
09283 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09284 cmd = ast_play_and_wait(chan, vms->fn);
09285 }
09286 }
09287 }
09288 return cmd;
09289 }
09290
09291
09292 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09293 {
09294 int cmd = 0;
09295
09296 if (vms->lastmsg > -1) {
09297 cmd = play_message(chan, vmu, vms);
09298 } else {
09299 if (!strcasecmp(vms->fn, "INBOX")) {
09300 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09301 } else {
09302 cmd = ast_play_and_wait(chan, "vm-nomessages");
09303 }
09304 }
09305 return cmd;
09306 }
09307
09308
09309
09310
09311
09312
09313
09314
09315
09316 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09317 {
09318 int cmd = 0;
09319
09320 if (vms->lastmsg > -1) {
09321 cmd = play_message(chan, vmu, vms);
09322 } else {
09323 cmd = ast_play_and_wait(chan, "vm-youhave");
09324 if (!cmd)
09325 cmd = ast_play_and_wait(chan, "vm-no");
09326 if (!cmd) {
09327 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09328 cmd = ast_play_and_wait(chan, vms->fn);
09329 }
09330 if (!cmd)
09331 cmd = ast_play_and_wait(chan, "vm-messages");
09332 }
09333 return cmd;
09334 }
09335
09336
09337
09338
09339
09340
09341
09342
09343
09344 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09345 {
09346 int cmd;
09347
09348 if (vms->lastmsg > -1) {
09349 cmd = play_message(chan, vmu, vms);
09350 } else {
09351 cmd = ast_play_and_wait(chan, "vm-no");
09352 if (!cmd)
09353 cmd = ast_play_and_wait(chan, "vm-message");
09354 if (!cmd) {
09355 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09356 cmd = ast_play_and_wait(chan, vms->fn);
09357 }
09358 }
09359 return cmd;
09360 }
09361
09362
09363
09364
09365
09366
09367
09368
09369
09370 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09371 {
09372 int cmd;
09373
09374 if (vms->lastmsg > -1) {
09375 cmd = play_message(chan, vmu, vms);
09376 } else {
09377 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09378 if (!cmd)
09379 cmd = ast_play_and_wait(chan, "vm-messages");
09380 if (!cmd) {
09381 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09382 cmd = ast_play_and_wait(chan, vms->fn);
09383 }
09384 }
09385 return cmd;
09386 }
09387
09388
09389
09390
09391
09392
09393
09394
09395
09396 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09397 {
09398 int cmd;
09399
09400 if (vms->lastmsg > -1) {
09401 cmd = play_message(chan, vmu, vms);
09402 } else {
09403 cmd = ast_play_and_wait(chan, "vm-no");
09404 if (!cmd) {
09405 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09406 cmd = ast_play_and_wait(chan, vms->fn);
09407 }
09408 if (!cmd)
09409 cmd = ast_play_and_wait(chan, "vm-messages");
09410 }
09411 return cmd;
09412 }
09413
09414
09415
09416
09417
09418
09419
09420
09421
09422 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09423 {
09424 int cmd;
09425
09426 if (vms->lastmsg > -1) {
09427 cmd = play_message(chan, vmu, vms);
09428 } else {
09429 cmd = ast_play_and_wait(chan, "vm-you");
09430 if (!cmd)
09431 cmd = ast_play_and_wait(chan, "vm-haveno");
09432 if (!cmd)
09433 cmd = ast_play_and_wait(chan, "vm-messages");
09434 if (!cmd) {
09435 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09436 cmd = ast_play_and_wait(chan, vms->fn);
09437 }
09438 }
09439 return cmd;
09440 }
09441
09442
09443
09444
09445
09446
09447
09448
09449
09450 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09451 {
09452 int cmd = 0;
09453
09454 if (vms->lastmsg > -1) {
09455 cmd = play_message(chan, vmu, vms);
09456 } else {
09457 cmd = ast_play_and_wait(chan, "vm-no");
09458 if (!cmd) {
09459 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09460 cmd = ast_play_and_wait(chan, vms->fn);
09461 }
09462 }
09463 return cmd;
09464 }
09465
09466
09467
09468
09469
09470
09471
09472
09473
09474
09475
09476
09477 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09478 {
09479 if (!strncasecmp(chan->language, "es", 2)) {
09480 return vm_browse_messages_es(chan, vms, vmu);
09481 } else if (!strncasecmp(chan->language, "gr", 2)) {
09482 return vm_browse_messages_gr(chan, vms, vmu);
09483 } else if (!strncasecmp(chan->language, "he", 2)) {
09484 return vm_browse_messages_he(chan, vms, vmu);
09485 } else if (!strncasecmp(chan->language, "it", 2)) {
09486 return vm_browse_messages_it(chan, vms, vmu);
09487 } else if (!strncasecmp(chan->language, "pt", 2)) {
09488 return vm_browse_messages_pt(chan, vms, vmu);
09489 } else if (!strncasecmp(chan->language, "vi", 2)) {
09490 return vm_browse_messages_vi(chan, vms, vmu);
09491 } else if (!strncasecmp(chan->language, "zh", 2)) {
09492 return vm_browse_messages_zh(chan, vms, vmu);
09493 } else {
09494 return vm_browse_messages_en(chan, vms, vmu);
09495 }
09496 }
09497
09498 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09499 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09500 int skipuser, int max_logins, int silent)
09501 {
09502 int useadsi = 0, valid = 0, logretries = 0;
09503 char password[AST_MAX_EXTENSION]="", *passptr;
09504 struct ast_vm_user vmus, *vmu = NULL;
09505
09506
09507 adsi_begin(chan, &useadsi);
09508 if (!skipuser && useadsi)
09509 adsi_login(chan);
09510 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09511 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09512 return -1;
09513 }
09514
09515
09516
09517 while (!valid && (logretries < max_logins)) {
09518
09519 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09520 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09521 return -1;
09522 }
09523 if (ast_strlen_zero(mailbox)) {
09524 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09525 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09526 } else {
09527 ast_verb(3, "Username not entered\n");
09528 return -1;
09529 }
09530 } else if (mailbox[0] == '*') {
09531
09532 if (ast_exists_extension(chan, chan->context, "a", 1,
09533 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09534 return -1;
09535 }
09536 mailbox[0] = '\0';
09537 }
09538
09539 if (useadsi)
09540 adsi_password(chan);
09541
09542 if (!ast_strlen_zero(prefix)) {
09543 char fullusername[80] = "";
09544 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09545 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09546 ast_copy_string(mailbox, fullusername, mailbox_size);
09547 }
09548
09549 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09550 vmu = find_user(&vmus, context, mailbox);
09551 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09552
09553 password[0] = '\0';
09554 } else {
09555 if (ast_streamfile(chan, vm_password, chan->language)) {
09556 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09557 return -1;
09558 }
09559 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09560 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09561 return -1;
09562 } else if (password[0] == '*') {
09563
09564 if (ast_exists_extension(chan, chan->context, "a", 1,
09565 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09566 mailbox[0] = '*';
09567 return -1;
09568 }
09569 mailbox[0] = '\0';
09570 }
09571 }
09572
09573 if (vmu) {
09574 passptr = vmu->password;
09575 if (passptr[0] == '-') passptr++;
09576 }
09577 if (vmu && !strcmp(passptr, password))
09578 valid++;
09579 else {
09580 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09581 if (!ast_strlen_zero(prefix))
09582 mailbox[0] = '\0';
09583 }
09584 logretries++;
09585 if (!valid) {
09586 if (skipuser || logretries >= max_logins) {
09587 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09588 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09589 return -1;
09590 }
09591 } else {
09592 if (useadsi)
09593 adsi_login(chan);
09594 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09595 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09596 return -1;
09597 }
09598 }
09599 if (ast_waitstream(chan, ""))
09600 return -1;
09601 }
09602 }
09603 if (!valid && (logretries >= max_logins)) {
09604 ast_stopstream(chan);
09605 ast_play_and_wait(chan, "vm-goodbye");
09606 return -1;
09607 }
09608 if (vmu && !skipuser) {
09609 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09610 }
09611 return 0;
09612 }
09613
09614 static int vm_execmain(struct ast_channel *chan, const char *data)
09615 {
09616
09617
09618
09619 int res = -1;
09620 int cmd = 0;
09621 int valid = 0;
09622 char prefixstr[80] ="";
09623 char ext_context[256]="";
09624 int box;
09625 int useadsi = 0;
09626 int skipuser = 0;
09627 struct vm_state vms;
09628 struct ast_vm_user *vmu = NULL, vmus;
09629 char *context = NULL;
09630 int silentexit = 0;
09631 struct ast_flags flags = { 0 };
09632 signed char record_gain = 0;
09633 int play_auto = 0;
09634 int play_folder = 0;
09635 int in_urgent = 0;
09636 #ifdef IMAP_STORAGE
09637 int deleted = 0;
09638 #endif
09639
09640
09641 memset(&vms, 0, sizeof(vms));
09642
09643 vms.lastmsg = -1;
09644
09645 memset(&vmus, 0, sizeof(vmus));
09646
09647 if (chan->_state != AST_STATE_UP) {
09648 ast_debug(1, "Before ast_answer\n");
09649 ast_answer(chan);
09650 }
09651
09652 if (!ast_strlen_zero(data)) {
09653 char *opts[OPT_ARG_ARRAY_SIZE];
09654 char *parse;
09655 AST_DECLARE_APP_ARGS(args,
09656 AST_APP_ARG(argv0);
09657 AST_APP_ARG(argv1);
09658 );
09659
09660 parse = ast_strdupa(data);
09661
09662 AST_STANDARD_APP_ARGS(args, parse);
09663
09664 if (args.argc == 2) {
09665 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09666 return -1;
09667 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09668 int gain;
09669 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09670 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09671 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09672 return -1;
09673 } else {
09674 record_gain = (signed char) gain;
09675 }
09676 } else {
09677 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09678 }
09679 }
09680 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09681 play_auto = 1;
09682 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09683
09684 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09685 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09686 play_folder = -1;
09687 }
09688 } else {
09689 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09690 }
09691 } else {
09692 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09693 }
09694 if (play_folder > 9 || play_folder < 0) {
09695 ast_log(AST_LOG_WARNING,
09696 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09697 opts[OPT_ARG_PLAYFOLDER]);
09698 play_folder = 0;
09699 }
09700 }
09701 } else {
09702
09703 while (*(args.argv0)) {
09704 if (*(args.argv0) == 's')
09705 ast_set_flag(&flags, OPT_SILENT);
09706 else if (*(args.argv0) == 'p')
09707 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09708 else
09709 break;
09710 (args.argv0)++;
09711 }
09712
09713 }
09714
09715 valid = ast_test_flag(&flags, OPT_SILENT);
09716
09717 if ((context = strchr(args.argv0, '@')))
09718 *context++ = '\0';
09719
09720 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09721 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09722 else
09723 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09724
09725 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09726 skipuser++;
09727 else
09728 valid = 0;
09729 }
09730
09731 if (!valid)
09732 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09733
09734 ast_debug(1, "After vm_authenticate\n");
09735
09736 if (vms.username[0] == '*') {
09737 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09738
09739
09740 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09741 res = 0;
09742 goto out;
09743 }
09744 }
09745
09746 if (!res) {
09747 valid = 1;
09748 if (!skipuser)
09749 vmu = &vmus;
09750 } else {
09751 res = 0;
09752 }
09753
09754
09755 adsi_begin(chan, &useadsi);
09756
09757 if (!valid) {
09758 goto out;
09759 }
09760
09761 #ifdef IMAP_STORAGE
09762 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
09763 pthread_setspecific(ts_vmstate.key, &vms);
09764
09765 vms.interactive = 1;
09766 vms.updated = 1;
09767 if (vmu)
09768 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
09769 vmstate_insert(&vms);
09770 init_vm_state(&vms);
09771 #endif
09772
09773 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09774 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
09775 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09776 return -1;
09777 }
09778 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09779 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
09780 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09781 return -1;
09782 }
09783
09784
09785 if (!ast_strlen_zero(vmu->language))
09786 ast_string_field_set(chan, language, vmu->language);
09787
09788
09789 ast_debug(1, "Before open_mailbox\n");
09790 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09791 if (res < 0)
09792 goto out;
09793 vms.oldmessages = vms.lastmsg + 1;
09794 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
09795
09796 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09797 if (res < 0)
09798 goto out;
09799 vms.newmessages = vms.lastmsg + 1;
09800 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
09801
09802 in_urgent = 1;
09803 res = open_mailbox(&vms, vmu, 11);
09804 if (res < 0)
09805 goto out;
09806 vms.urgentmessages = vms.lastmsg + 1;
09807 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
09808
09809
09810 if (play_auto) {
09811 if (vms.urgentmessages) {
09812 in_urgent = 1;
09813 res = open_mailbox(&vms, vmu, 11);
09814 } else {
09815 in_urgent = 0;
09816 res = open_mailbox(&vms, vmu, play_folder);
09817 }
09818 if (res < 0)
09819 goto out;
09820
09821
09822 if (vms.lastmsg == -1) {
09823 in_urgent = 0;
09824 cmd = vm_browse_messages(chan, &vms, vmu);
09825 res = 0;
09826 goto out;
09827 }
09828 } else {
09829 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
09830
09831 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09832 in_urgent = 0;
09833 play_folder = 1;
09834 if (res < 0)
09835 goto out;
09836 } else if (!vms.urgentmessages && vms.newmessages) {
09837
09838 in_urgent = 0;
09839 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09840 if (res < 0)
09841 goto out;
09842 }
09843 }
09844
09845 if (useadsi)
09846 adsi_status(chan, &vms);
09847 res = 0;
09848
09849
09850 if (!strcasecmp(vmu->mailbox, vmu->password) &&
09851 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
09852 if (ast_play_and_wait(chan, "vm-newuser") == -1)
09853 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
09854 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
09855 if ((cmd == 't') || (cmd == '#')) {
09856
09857 res = 0;
09858 goto out;
09859 } else if (cmd < 0) {
09860
09861 res = -1;
09862 goto out;
09863 }
09864 }
09865 #ifdef IMAP_STORAGE
09866 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
09867 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
09868 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
09869 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09870 }
09871 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09872 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
09873 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09874 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09875 }
09876 #endif
09877 if (play_auto) {
09878 cmd = '1';
09879 } else {
09880 cmd = vm_intro(chan, vmu, &vms);
09881 }
09882
09883 vms.repeats = 0;
09884 vms.starting = 1;
09885 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09886
09887 switch (cmd) {
09888 case '1':
09889 vms.curmsg = 0;
09890
09891 case '5':
09892 cmd = vm_browse_messages(chan, &vms, vmu);
09893 break;
09894 case '2':
09895 if (useadsi)
09896 adsi_folders(chan, 0, "Change to folder...");
09897 cmd = get_folder2(chan, "vm-changeto", 0);
09898 if (cmd == '#') {
09899 cmd = 0;
09900 } else if (cmd > 0) {
09901 cmd = cmd - '0';
09902 res = close_mailbox(&vms, vmu);
09903 if (res == ERROR_LOCK_PATH)
09904 goto out;
09905
09906 if (cmd != 11) in_urgent = 0;
09907 res = open_mailbox(&vms, vmu, cmd);
09908 if (res < 0)
09909 goto out;
09910 play_folder = cmd;
09911 cmd = 0;
09912 }
09913 if (useadsi)
09914 adsi_status2(chan, &vms);
09915
09916 if (!cmd)
09917 cmd = vm_play_folder_name(chan, vms.vmbox);
09918
09919 vms.starting = 1;
09920 break;
09921 case '3':
09922 cmd = 0;
09923 vms.repeats = 0;
09924 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09925 switch (cmd) {
09926 case '1':
09927 if (vms.lastmsg > -1 && !vms.starting) {
09928 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
09929 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09930 res = cmd;
09931 goto out;
09932 }
09933 } else
09934 cmd = ast_play_and_wait(chan, "vm-sorry");
09935 cmd = 't';
09936 break;
09937 case '2':
09938 if (!vms.starting)
09939 ast_verb(3, "Callback Requested\n");
09940 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
09941 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
09942 if (cmd == 9) {
09943 silentexit = 1;
09944 goto out;
09945 } else if (cmd == ERROR_LOCK_PATH) {
09946 res = cmd;
09947 goto out;
09948 }
09949 } else
09950 cmd = ast_play_and_wait(chan, "vm-sorry");
09951 cmd = 't';
09952 break;
09953 case '3':
09954 if (vms.lastmsg > -1 && !vms.starting) {
09955 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
09956 if (cmd == ERROR_LOCK_PATH) {
09957 res = cmd;
09958 goto out;
09959 }
09960 } else
09961 cmd = ast_play_and_wait(chan, "vm-sorry");
09962 cmd = 't';
09963 break;
09964 case '4':
09965 if (!ast_strlen_zero(vmu->dialout)) {
09966 cmd = dialout(chan, vmu, NULL, vmu->dialout);
09967 if (cmd == 9) {
09968 silentexit = 1;
09969 goto out;
09970 }
09971 } else
09972 cmd = ast_play_and_wait(chan, "vm-sorry");
09973 cmd = 't';
09974 break;
09975
09976 case '5':
09977 if (ast_test_flag(vmu, VM_SVMAIL)) {
09978 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
09979 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09980 res = cmd;
09981 goto out;
09982 }
09983 } else
09984 cmd = ast_play_and_wait(chan, "vm-sorry");
09985 cmd = 't';
09986 break;
09987
09988 case '*':
09989 cmd = 't';
09990 break;
09991
09992 default:
09993 cmd = 0;
09994 if (!vms.starting) {
09995 cmd = ast_play_and_wait(chan, "vm-toreply");
09996 }
09997 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
09998 cmd = ast_play_and_wait(chan, "vm-tocallback");
09999 }
10000 if (!cmd && !vms.starting) {
10001 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10002 }
10003 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10004 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10005 }
10006 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
10007 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10008 if (!cmd)
10009 cmd = ast_play_and_wait(chan, "vm-starmain");
10010 if (!cmd)
10011 cmd = ast_waitfordigit(chan, 6000);
10012 if (!cmd)
10013 vms.repeats++;
10014 if (vms.repeats > 3)
10015 cmd = 't';
10016 }
10017 }
10018 if (cmd == 't') {
10019 cmd = 0;
10020 vms.repeats = 0;
10021 }
10022 break;
10023 case '4':
10024 if (vms.curmsg > 0) {
10025 vms.curmsg--;
10026 cmd = play_message(chan, vmu, &vms);
10027 } else {
10028
10029
10030
10031
10032 if (in_urgent == 0 && vms.urgentmessages > 0) {
10033
10034 in_urgent = 1;
10035 res = close_mailbox(&vms, vmu);
10036 if (res == ERROR_LOCK_PATH)
10037 goto out;
10038 res = open_mailbox(&vms, vmu, 11);
10039 if (res < 0)
10040 goto out;
10041 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10042 vms.curmsg = vms.lastmsg;
10043 if (vms.lastmsg < 0)
10044 cmd = ast_play_and_wait(chan, "vm-nomore");
10045 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10046 vms.curmsg = vms.lastmsg;
10047 cmd = play_message(chan, vmu, &vms);
10048 } else {
10049 cmd = ast_play_and_wait(chan, "vm-nomore");
10050 }
10051 }
10052 break;
10053 case '6':
10054 if (vms.curmsg < vms.lastmsg) {
10055 vms.curmsg++;
10056 cmd = play_message(chan, vmu, &vms);
10057 } else {
10058 if (in_urgent && vms.newmessages > 0) {
10059
10060
10061
10062
10063 in_urgent = 0;
10064 res = close_mailbox(&vms, vmu);
10065 if (res == ERROR_LOCK_PATH)
10066 goto out;
10067 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10068 if (res < 0)
10069 goto out;
10070 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10071 vms.curmsg = -1;
10072 if (vms.lastmsg < 0) {
10073 cmd = ast_play_and_wait(chan, "vm-nomore");
10074 }
10075 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10076 vms.curmsg = 0;
10077 cmd = play_message(chan, vmu, &vms);
10078 } else {
10079 cmd = ast_play_and_wait(chan, "vm-nomore");
10080 }
10081 }
10082 break;
10083 case '7':
10084 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10085 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10086 if (useadsi)
10087 adsi_delete(chan, &vms);
10088 if (vms.deleted[vms.curmsg]) {
10089 if (play_folder == 0) {
10090 if (in_urgent) {
10091 vms.urgentmessages--;
10092 } else {
10093 vms.newmessages--;
10094 }
10095 }
10096 else if (play_folder == 1)
10097 vms.oldmessages--;
10098 cmd = ast_play_and_wait(chan, "vm-deleted");
10099 } else {
10100 if (play_folder == 0) {
10101 if (in_urgent) {
10102 vms.urgentmessages++;
10103 } else {
10104 vms.newmessages++;
10105 }
10106 }
10107 else if (play_folder == 1)
10108 vms.oldmessages++;
10109 cmd = ast_play_and_wait(chan, "vm-undeleted");
10110 }
10111 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10112 if (vms.curmsg < vms.lastmsg) {
10113 vms.curmsg++;
10114 cmd = play_message(chan, vmu, &vms);
10115 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10116 vms.curmsg = 0;
10117 cmd = play_message(chan, vmu, &vms);
10118 } else {
10119
10120
10121
10122
10123 if (in_urgent == 1) {
10124
10125 in_urgent = 0;
10126 res = close_mailbox(&vms, vmu);
10127 if (res == ERROR_LOCK_PATH)
10128 goto out;
10129 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10130 if (res < 0)
10131 goto out;
10132 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10133 vms.curmsg = -1;
10134 if (vms.lastmsg < 0)
10135 cmd = ast_play_and_wait(chan, "vm-nomore");
10136 } else {
10137 cmd = ast_play_and_wait(chan, "vm-nomore");
10138 }
10139 }
10140 }
10141 } else
10142 cmd = 0;
10143 #ifdef IMAP_STORAGE
10144 deleted = 1;
10145 #endif
10146 break;
10147
10148 case '8':
10149 if (vms.lastmsg > -1) {
10150 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10151 if (cmd == ERROR_LOCK_PATH) {
10152 res = cmd;
10153 goto out;
10154 }
10155 } else {
10156
10157
10158
10159
10160 if (in_urgent == 1 && vms.newmessages > 0) {
10161
10162 in_urgent = 0;
10163 res = close_mailbox(&vms, vmu);
10164 if (res == ERROR_LOCK_PATH)
10165 goto out;
10166 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10167 if (res < 0)
10168 goto out;
10169 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10170 vms.curmsg = -1;
10171 if (vms.lastmsg < 0)
10172 cmd = ast_play_and_wait(chan, "vm-nomore");
10173 } else {
10174 cmd = ast_play_and_wait(chan, "vm-nomore");
10175 }
10176 }
10177 break;
10178 case '9':
10179 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10180
10181 cmd = 0;
10182 break;
10183 }
10184 if (useadsi)
10185 adsi_folders(chan, 1, "Save to folder...");
10186 cmd = get_folder2(chan, "vm-savefolder", 1);
10187 box = 0;
10188 if (cmd == '#') {
10189 cmd = 0;
10190 break;
10191 } else if (cmd > 0) {
10192 box = cmd = cmd - '0';
10193 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10194 if (cmd == ERROR_LOCK_PATH) {
10195 res = cmd;
10196 goto out;
10197 #ifndef IMAP_STORAGE
10198 } else if (!cmd) {
10199 vms.deleted[vms.curmsg] = 1;
10200 #endif
10201 } else {
10202 vms.deleted[vms.curmsg] = 0;
10203 vms.heard[vms.curmsg] = 0;
10204 }
10205 }
10206 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10207 if (useadsi)
10208 adsi_message(chan, &vms);
10209 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10210 if (!cmd) {
10211 cmd = ast_play_and_wait(chan, "vm-message");
10212 if (!cmd)
10213 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10214 if (!cmd)
10215 cmd = ast_play_and_wait(chan, "vm-savedto");
10216 if (!cmd)
10217 cmd = vm_play_folder_name(chan, vms.fn);
10218 } else {
10219 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10220 }
10221 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10222 if (vms.curmsg < vms.lastmsg) {
10223 vms.curmsg++;
10224 cmd = play_message(chan, vmu, &vms);
10225 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10226 vms.curmsg = 0;
10227 cmd = play_message(chan, vmu, &vms);
10228 } else {
10229
10230
10231
10232
10233 if (in_urgent == 1 && vms.newmessages > 0) {
10234
10235 in_urgent = 0;
10236 res = close_mailbox(&vms, vmu);
10237 if (res == ERROR_LOCK_PATH)
10238 goto out;
10239 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10240 if (res < 0)
10241 goto out;
10242 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10243 vms.curmsg = -1;
10244 if (vms.lastmsg < 0)
10245 cmd = ast_play_and_wait(chan, "vm-nomore");
10246 } else {
10247 cmd = ast_play_and_wait(chan, "vm-nomore");
10248 }
10249 }
10250 }
10251 break;
10252 case '*':
10253 if (!vms.starting) {
10254 cmd = ast_play_and_wait(chan, "vm-onefor");
10255 if (!strncasecmp(chan->language, "he", 2)) {
10256 cmd = ast_play_and_wait(chan, "vm-for");
10257 }
10258 if (!cmd)
10259 cmd = vm_play_folder_name(chan, vms.vmbox);
10260 if (!cmd)
10261 cmd = ast_play_and_wait(chan, "vm-opts");
10262 if (!cmd)
10263 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10264 } else
10265 cmd = 0;
10266 break;
10267 case '0':
10268 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10269 if (useadsi)
10270 adsi_status(chan, &vms);
10271 break;
10272 default:
10273 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10274 break;
10275 }
10276 }
10277 if ((cmd == 't') || (cmd == '#')) {
10278
10279 res = 0;
10280 } else {
10281
10282 res = -1;
10283 }
10284
10285 out:
10286 if (res > -1) {
10287 ast_stopstream(chan);
10288 adsi_goodbye(chan);
10289 if (valid && res != OPERATOR_EXIT) {
10290 if (silentexit)
10291 res = ast_play_and_wait(chan, "vm-dialout");
10292 else
10293 res = ast_play_and_wait(chan, "vm-goodbye");
10294 }
10295 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10296 res = 0;
10297 }
10298 if (useadsi)
10299 ast_adsi_unload_session(chan);
10300 }
10301 if (vmu)
10302 close_mailbox(&vms, vmu);
10303 if (valid) {
10304 int new = 0, old = 0, urgent = 0;
10305 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10306 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10307
10308 run_externnotify(vmu->context, vmu->mailbox, NULL);
10309 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10310 queue_mwi_event(ext_context, urgent, new, old);
10311 }
10312 #ifdef IMAP_STORAGE
10313
10314 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10315 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10316 ast_mutex_lock(&vms.lock);
10317 #ifdef HAVE_IMAP_TK2006
10318 if (LEVELUIDPLUS (vms.mailstream)) {
10319 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10320 } else
10321 #endif
10322 mail_expunge(vms.mailstream);
10323 ast_mutex_unlock(&vms.lock);
10324 }
10325
10326
10327 if (vmu) {
10328 vmstate_delete(&vms);
10329 }
10330 #endif
10331 if (vmu)
10332 free_user(vmu);
10333 if (vms.deleted)
10334 ast_free(vms.deleted);
10335 if (vms.heard)
10336 ast_free(vms.heard);
10337
10338 #ifdef IMAP_STORAGE
10339 pthread_setspecific(ts_vmstate.key, NULL);
10340 #endif
10341 return res;
10342 }
10343
10344 static int vm_exec(struct ast_channel *chan, const char *data)
10345 {
10346 int res = 0;
10347 char *tmp;
10348 struct leave_vm_options leave_options;
10349 struct ast_flags flags = { 0 };
10350 char *opts[OPT_ARG_ARRAY_SIZE];
10351 AST_DECLARE_APP_ARGS(args,
10352 AST_APP_ARG(argv0);
10353 AST_APP_ARG(argv1);
10354 );
10355
10356 memset(&leave_options, 0, sizeof(leave_options));
10357
10358 if (chan->_state != AST_STATE_UP)
10359 ast_answer(chan);
10360
10361 if (!ast_strlen_zero(data)) {
10362 tmp = ast_strdupa(data);
10363 AST_STANDARD_APP_ARGS(args, tmp);
10364 if (args.argc == 2) {
10365 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10366 return -1;
10367 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10368 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10369 int gain;
10370
10371 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10372 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10373 return -1;
10374 } else {
10375 leave_options.record_gain = (signed char) gain;
10376 }
10377 }
10378 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10379 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10380 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10381 }
10382 }
10383 } else {
10384 char temp[256];
10385 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10386 if (res < 0)
10387 return res;
10388 if (ast_strlen_zero(temp))
10389 return 0;
10390 args.argv0 = ast_strdupa(temp);
10391 }
10392
10393 res = leave_voicemail(chan, args.argv0, &leave_options);
10394 if (res == 't') {
10395 ast_play_and_wait(chan, "vm-goodbye");
10396 res = 0;
10397 }
10398
10399 if (res == OPERATOR_EXIT) {
10400 res = 0;
10401 }
10402
10403 if (res == ERROR_LOCK_PATH) {
10404 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10405 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10406 res = 0;
10407 }
10408
10409 return res;
10410 }
10411
10412 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10413 {
10414 struct ast_vm_user *vmu;
10415
10416 AST_LIST_TRAVERSE(&users, vmu, list) {
10417 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10418 if (strcasecmp(vmu->context, context)) {
10419 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10420 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10421 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10422 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10423 }
10424 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10425 return NULL;
10426 }
10427 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10428 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10429 return NULL;
10430 }
10431 }
10432
10433 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10434 return NULL;
10435
10436 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10437 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10438
10439 AST_LIST_INSERT_TAIL(&users, vmu, list);
10440
10441 return vmu;
10442 }
10443
10444 static int append_mailbox(const char *context, const char *box, const char *data)
10445 {
10446
10447 char *tmp;
10448 char *stringp;
10449 char *s;
10450 struct ast_vm_user *vmu;
10451 char *mailbox_full;
10452 int new = 0, old = 0, urgent = 0;
10453 char secretfn[PATH_MAX] = "";
10454
10455 tmp = ast_strdupa(data);
10456
10457 if (!(vmu = find_or_create(context, box)))
10458 return -1;
10459
10460 populate_defaults(vmu);
10461
10462 stringp = tmp;
10463 if ((s = strsep(&stringp, ","))) {
10464 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10465 }
10466 if (stringp && (s = strsep(&stringp, ","))) {
10467 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10468 }
10469 if (stringp && (s = strsep(&stringp, ","))) {
10470 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10471 }
10472 if (stringp && (s = strsep(&stringp, ","))) {
10473 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10474 }
10475 if (stringp && (s = strsep(&stringp, ","))) {
10476 apply_options(vmu, s);
10477 }
10478
10479 switch (vmu->passwordlocation) {
10480 case OPT_PWLOC_SPOOLDIR:
10481 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10482 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10483 }
10484
10485 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10486 strcpy(mailbox_full, box);
10487 strcat(mailbox_full, "@");
10488 strcat(mailbox_full, context);
10489
10490 inboxcount2(mailbox_full, &urgent, &new, &old);
10491 queue_mwi_event(mailbox_full, urgent, new, old);
10492
10493 return 0;
10494 }
10495
10496 AST_TEST_DEFINE(test_voicemail_vmuser)
10497 {
10498 int res = 0;
10499 struct ast_vm_user *vmu;
10500
10501 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10502 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10503 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10504 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10505 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10506 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10507 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir";
10508 #ifdef IMAP_STORAGE
10509 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10510 "imapfolder=INBOX|imapvmshareid=6000";
10511 #endif
10512
10513 switch (cmd) {
10514 case TEST_INIT:
10515 info->name = "vmuser";
10516 info->category = "/apps/app_voicemail/";
10517 info->summary = "Vmuser unit test";
10518 info->description =
10519 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10520 return AST_TEST_NOT_RUN;
10521 case TEST_EXECUTE:
10522 break;
10523 }
10524
10525 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10526 return AST_TEST_NOT_RUN;
10527 }
10528 ast_set_flag(vmu, VM_ALLOCED);
10529
10530 apply_options(vmu, options_string);
10531
10532 if (!ast_test_flag(vmu, VM_ATTACH)) {
10533 ast_test_status_update(test, "Parse failure for attach option\n");
10534 res = 1;
10535 }
10536 if (strcasecmp(vmu->attachfmt, "wav49")) {
10537 ast_test_status_update(test, "Parse failure for attachftm option\n");
10538 res = 1;
10539 }
10540 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10541 ast_test_status_update(test, "Parse failure for serveremail option\n");
10542 res = 1;
10543 }
10544 if (strcasecmp(vmu->zonetag, "central")) {
10545 ast_test_status_update(test, "Parse failure for tz option\n");
10546 res = 1;
10547 }
10548 if (!ast_test_flag(vmu, VM_DELETE)) {
10549 ast_test_status_update(test, "Parse failure for delete option\n");
10550 res = 1;
10551 }
10552 if (!ast_test_flag(vmu, VM_SAYCID)) {
10553 ast_test_status_update(test, "Parse failure for saycid option\n");
10554 res = 1;
10555 }
10556 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10557 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10558 res = 1;
10559 }
10560 if (!ast_test_flag(vmu, VM_REVIEW)) {
10561 ast_test_status_update(test, "Parse failure for review option\n");
10562 res = 1;
10563 }
10564 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10565 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10566 res = 1;
10567 }
10568 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10569 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10570 res = 1;
10571 }
10572 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10573 ast_test_status_update(test, "Parse failure for operator option\n");
10574 res = 1;
10575 }
10576 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10577 ast_test_status_update(test, "Parse failure for envelope option\n");
10578 res = 1;
10579 }
10580 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10581 ast_test_status_update(test, "Parse failure for moveheard option\n");
10582 res = 1;
10583 }
10584 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10585 ast_test_status_update(test, "Parse failure for sayduration option\n");
10586 res = 1;
10587 }
10588 if (vmu->saydurationm != 5) {
10589 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10590 res = 1;
10591 }
10592 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10593 ast_test_status_update(test, "Parse failure for forcename option\n");
10594 res = 1;
10595 }
10596 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10597 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10598 res = 1;
10599 }
10600 if (strcasecmp(vmu->callback, "somecontext")) {
10601 ast_test_status_update(test, "Parse failure for callbacks option\n");
10602 res = 1;
10603 }
10604 if (strcasecmp(vmu->dialout, "somecontext2")) {
10605 ast_test_status_update(test, "Parse failure for dialout option\n");
10606 res = 1;
10607 }
10608 if (strcasecmp(vmu->exit, "somecontext3")) {
10609 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10610 res = 1;
10611 }
10612 if (vmu->minsecs != 10) {
10613 ast_test_status_update(test, "Parse failure for minsecs option\n");
10614 res = 1;
10615 }
10616 if (vmu->maxsecs != 100) {
10617 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10618 res = 1;
10619 }
10620 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10621 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10622 res = 1;
10623 }
10624 if (vmu->maxdeletedmsg != 50) {
10625 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10626 res = 1;
10627 }
10628 if (vmu->volgain != 1.3) {
10629 ast_test_status_update(test, "Parse failure for volgain option\n");
10630 res = 1;
10631 }
10632 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10633 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10634 res = 1;
10635 }
10636 #ifdef IMAP_STORAGE
10637 apply_options(vmu, option_string2);
10638
10639 if (strcasecmp(vmu->imapuser, "imapuser")) {
10640 ast_test_status_update(test, "Parse failure for imapuser option\n");
10641 res = 1;
10642 }
10643 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10644 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10645 res = 1;
10646 }
10647 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10648 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10649 res = 1;
10650 }
10651 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10652 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10653 res = 1;
10654 }
10655 #endif
10656
10657 free_user(vmu);
10658 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10659 }
10660
10661 static int vm_box_exists(struct ast_channel *chan, const char *data)
10662 {
10663 struct ast_vm_user svm;
10664 char *context, *box;
10665 AST_DECLARE_APP_ARGS(args,
10666 AST_APP_ARG(mbox);
10667 AST_APP_ARG(options);
10668 );
10669 static int dep_warning = 0;
10670
10671 if (ast_strlen_zero(data)) {
10672 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10673 return -1;
10674 }
10675
10676 if (!dep_warning) {
10677 dep_warning = 1;
10678 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10679 }
10680
10681 box = ast_strdupa(data);
10682
10683 AST_STANDARD_APP_ARGS(args, box);
10684
10685 if (args.options) {
10686 }
10687
10688 if ((context = strchr(args.mbox, '@'))) {
10689 *context = '\0';
10690 context++;
10691 }
10692
10693 if (find_user(&svm, context, args.mbox)) {
10694 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10695 } else
10696 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10697
10698 return 0;
10699 }
10700
10701 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10702 {
10703 struct ast_vm_user svm;
10704 AST_DECLARE_APP_ARGS(arg,
10705 AST_APP_ARG(mbox);
10706 AST_APP_ARG(context);
10707 );
10708
10709 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
10710
10711 if (ast_strlen_zero(arg.mbox)) {
10712 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
10713 return -1;
10714 }
10715
10716 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
10717 return 0;
10718 }
10719
10720 static struct ast_custom_function mailbox_exists_acf = {
10721 .name = "MAILBOX_EXISTS",
10722 .read = acf_mailbox_exists,
10723 };
10724
10725 static int vmauthenticate(struct ast_channel *chan, const char *data)
10726 {
10727 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
10728 struct ast_vm_user vmus;
10729 char *options = NULL;
10730 int silent = 0, skipuser = 0;
10731 int res = -1;
10732
10733 if (data) {
10734 s = ast_strdupa(data);
10735 user = strsep(&s, ",");
10736 options = strsep(&s, ",");
10737 if (user) {
10738 s = user;
10739 user = strsep(&s, "@");
10740 context = strsep(&s, "");
10741 if (!ast_strlen_zero(user))
10742 skipuser++;
10743 ast_copy_string(mailbox, user, sizeof(mailbox));
10744 }
10745 }
10746
10747 if (options) {
10748 silent = (strchr(options, 's')) != NULL;
10749 }
10750
10751 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
10752 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
10753 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
10754 ast_play_and_wait(chan, "auth-thankyou");
10755 res = 0;
10756 } else if (mailbox[0] == '*') {
10757
10758 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10759 res = 0;
10760 }
10761 }
10762
10763 return res;
10764 }
10765
10766 static char *show_users_realtime(int fd, const char *context)
10767 {
10768 struct ast_config *cfg;
10769 const char *cat = NULL;
10770
10771 if (!(cfg = ast_load_realtime_multientry("voicemail",
10772 "context", context, SENTINEL))) {
10773 return CLI_FAILURE;
10774 }
10775
10776 ast_cli(fd,
10777 "\n"
10778 "=============================================================\n"
10779 "=== Configured Voicemail Users ==============================\n"
10780 "=============================================================\n"
10781 "===\n");
10782
10783 while ((cat = ast_category_browse(cfg, cat))) {
10784 struct ast_variable *var = NULL;
10785 ast_cli(fd,
10786 "=== Mailbox ...\n"
10787 "===\n");
10788 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
10789 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
10790 ast_cli(fd,
10791 "===\n"
10792 "=== ---------------------------------------------------------\n"
10793 "===\n");
10794 }
10795
10796 ast_cli(fd,
10797 "=============================================================\n"
10798 "\n");
10799
10800 ast_config_destroy(cfg);
10801
10802 return CLI_SUCCESS;
10803 }
10804
10805 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
10806 {
10807 int which = 0;
10808 int wordlen;
10809 struct ast_vm_user *vmu;
10810 const char *context = "";
10811
10812
10813 if (pos > 4)
10814 return NULL;
10815 if (pos == 3)
10816 return (state == 0) ? ast_strdup("for") : NULL;
10817 wordlen = strlen(word);
10818 AST_LIST_TRAVERSE(&users, vmu, list) {
10819 if (!strncasecmp(word, vmu->context, wordlen)) {
10820 if (context && strcmp(context, vmu->context) && ++which > state)
10821 return ast_strdup(vmu->context);
10822
10823 context = vmu->context;
10824 }
10825 }
10826 return NULL;
10827 }
10828
10829
10830 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10831 {
10832 struct ast_vm_user *vmu;
10833 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
10834 const char *context = NULL;
10835 int users_counter = 0;
10836
10837 switch (cmd) {
10838 case CLI_INIT:
10839 e->command = "voicemail show users";
10840 e->usage =
10841 "Usage: voicemail show users [for <context>]\n"
10842 " Lists all mailboxes currently set up\n";
10843 return NULL;
10844 case CLI_GENERATE:
10845 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
10846 }
10847
10848 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
10849 return CLI_SHOWUSAGE;
10850 if (a->argc == 5) {
10851 if (strcmp(a->argv[3],"for"))
10852 return CLI_SHOWUSAGE;
10853 context = a->argv[4];
10854 }
10855
10856 if (ast_check_realtime("voicemail")) {
10857 if (!context) {
10858 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
10859 return CLI_SHOWUSAGE;
10860 }
10861 return show_users_realtime(a->fd, context);
10862 }
10863
10864 AST_LIST_LOCK(&users);
10865 if (AST_LIST_EMPTY(&users)) {
10866 ast_cli(a->fd, "There are no voicemail users currently defined\n");
10867 AST_LIST_UNLOCK(&users);
10868 return CLI_FAILURE;
10869 }
10870 if (a->argc == 3)
10871 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10872 else {
10873 int count = 0;
10874 AST_LIST_TRAVERSE(&users, vmu, list) {
10875 if (!strcmp(context, vmu->context))
10876 count++;
10877 }
10878 if (count) {
10879 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10880 } else {
10881 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
10882 AST_LIST_UNLOCK(&users);
10883 return CLI_FAILURE;
10884 }
10885 }
10886 AST_LIST_TRAVERSE(&users, vmu, list) {
10887 int newmsgs = 0, oldmsgs = 0;
10888 char count[12], tmp[256] = "";
10889
10890 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
10891 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
10892 inboxcount(tmp, &newmsgs, &oldmsgs);
10893 snprintf(count, sizeof(count), "%d", newmsgs);
10894 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
10895 users_counter++;
10896 }
10897 }
10898 AST_LIST_UNLOCK(&users);
10899 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
10900 return CLI_SUCCESS;
10901 }
10902
10903
10904 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10905 {
10906 struct vm_zone *zone;
10907 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
10908 char *res = CLI_SUCCESS;
10909
10910 switch (cmd) {
10911 case CLI_INIT:
10912 e->command = "voicemail show zones";
10913 e->usage =
10914 "Usage: voicemail show zones\n"
10915 " Lists zone message formats\n";
10916 return NULL;
10917 case CLI_GENERATE:
10918 return NULL;
10919 }
10920
10921 if (a->argc != 3)
10922 return CLI_SHOWUSAGE;
10923
10924 AST_LIST_LOCK(&zones);
10925 if (!AST_LIST_EMPTY(&zones)) {
10926 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
10927 AST_LIST_TRAVERSE(&zones, zone, list) {
10928 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
10929 }
10930 } else {
10931 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
10932 res = CLI_FAILURE;
10933 }
10934 AST_LIST_UNLOCK(&zones);
10935
10936 return res;
10937 }
10938
10939
10940 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10941 {
10942 switch (cmd) {
10943 case CLI_INIT:
10944 e->command = "voicemail reload";
10945 e->usage =
10946 "Usage: voicemail reload\n"
10947 " Reload voicemail configuration\n";
10948 return NULL;
10949 case CLI_GENERATE:
10950 return NULL;
10951 }
10952
10953 if (a->argc != 2)
10954 return CLI_SHOWUSAGE;
10955
10956 ast_cli(a->fd, "Reloading voicemail configuration...\n");
10957 load_config(1);
10958
10959 return CLI_SUCCESS;
10960 }
10961
10962 static struct ast_cli_entry cli_voicemail[] = {
10963 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
10964 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
10965 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
10966 };
10967
10968 #ifdef IMAP_STORAGE
10969 #define DATA_EXPORT_VM_USERS(USER) \
10970 USER(ast_vm_user, context, AST_DATA_STRING) \
10971 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
10972 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
10973 USER(ast_vm_user, fullname, AST_DATA_STRING) \
10974 USER(ast_vm_user, email, AST_DATA_STRING) \
10975 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
10976 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
10977 USER(ast_vm_user, pager, AST_DATA_STRING) \
10978 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
10979 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
10980 USER(ast_vm_user, language, AST_DATA_STRING) \
10981 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
10982 USER(ast_vm_user, callback, AST_DATA_STRING) \
10983 USER(ast_vm_user, dialout, AST_DATA_STRING) \
10984 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
10985 USER(ast_vm_user, exit, AST_DATA_STRING) \
10986 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
10987 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
10988 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
10989 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
10990 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
10991 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
10992 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
10993 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
10994 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
10995 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
10996 #else
10997 #define DATA_EXPORT_VM_USERS(USER) \
10998 USER(ast_vm_user, context, AST_DATA_STRING) \
10999 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11000 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11001 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11002 USER(ast_vm_user, email, AST_DATA_STRING) \
11003 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11004 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11005 USER(ast_vm_user, pager, AST_DATA_STRING) \
11006 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11007 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11008 USER(ast_vm_user, language, AST_DATA_STRING) \
11009 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11010 USER(ast_vm_user, callback, AST_DATA_STRING) \
11011 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11012 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11013 USER(ast_vm_user, exit, AST_DATA_STRING) \
11014 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11015 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11016 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11017 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11018 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11019 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11020 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11021 #endif
11022
11023 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11024
11025 #define DATA_EXPORT_VM_ZONES(ZONE) \
11026 ZONE(vm_zone, name, AST_DATA_STRING) \
11027 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11028 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11029
11030 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11031
11032
11033
11034
11035
11036
11037
11038
11039 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11040 struct ast_data *data_root, struct ast_vm_user *user)
11041 {
11042 struct ast_data *data_user, *data_zone;
11043 struct ast_data *data_state;
11044 struct vm_zone *zone = NULL;
11045 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11046 char ext_context[256] = "";
11047
11048 data_user = ast_data_add_node(data_root, "user");
11049 if (!data_user) {
11050 return -1;
11051 }
11052
11053 ast_data_add_structure(ast_vm_user, data_user, user);
11054
11055 AST_LIST_LOCK(&zones);
11056 AST_LIST_TRAVERSE(&zones, zone, list) {
11057 if (!strcmp(zone->name, user->zonetag)) {
11058 break;
11059 }
11060 }
11061 AST_LIST_UNLOCK(&zones);
11062
11063
11064 data_state = ast_data_add_node(data_user, "state");
11065 if (!data_state) {
11066 return -1;
11067 }
11068 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11069 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11070 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11071 ast_data_add_int(data_state, "newmsg", newmsg);
11072 ast_data_add_int(data_state, "oldmsg", oldmsg);
11073
11074 if (zone) {
11075 data_zone = ast_data_add_node(data_user, "zone");
11076 ast_data_add_structure(vm_zone, data_zone, zone);
11077 }
11078
11079 if (!ast_data_search_match(search, data_user)) {
11080 ast_data_remove_node(data_root, data_user);
11081 }
11082
11083 return 0;
11084 }
11085
11086 static int vm_users_data_provider_get(const struct ast_data_search *search,
11087 struct ast_data *data_root)
11088 {
11089 struct ast_vm_user *user;
11090
11091 AST_LIST_LOCK(&users);
11092 AST_LIST_TRAVERSE(&users, user, list) {
11093 vm_users_data_provider_get_helper(search, data_root, user);
11094 }
11095 AST_LIST_UNLOCK(&users);
11096
11097 return 0;
11098 }
11099
11100 static const struct ast_data_handler vm_users_data_provider = {
11101 .version = AST_DATA_HANDLER_VERSION,
11102 .get = vm_users_data_provider_get
11103 };
11104
11105 static const struct ast_data_entry vm_data_providers[] = {
11106 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11107 };
11108
11109 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11110 {
11111 int new = 0, old = 0, urgent = 0;
11112
11113 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11114
11115 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11116 mwi_sub->old_urgent = urgent;
11117 mwi_sub->old_new = new;
11118 mwi_sub->old_old = old;
11119 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11120 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11121 }
11122 }
11123
11124 static void poll_subscribed_mailboxes(void)
11125 {
11126 struct mwi_sub *mwi_sub;
11127
11128 AST_RWLIST_RDLOCK(&mwi_subs);
11129 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11130 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11131 poll_subscribed_mailbox(mwi_sub);
11132 }
11133 }
11134 AST_RWLIST_UNLOCK(&mwi_subs);
11135 }
11136
11137 static void *mb_poll_thread(void *data)
11138 {
11139 while (poll_thread_run) {
11140 struct timespec ts = { 0, };
11141 struct timeval wait;
11142
11143 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11144 ts.tv_sec = wait.tv_sec;
11145 ts.tv_nsec = wait.tv_usec * 1000;
11146
11147 ast_mutex_lock(&poll_lock);
11148 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11149 ast_mutex_unlock(&poll_lock);
11150
11151 if (!poll_thread_run)
11152 break;
11153
11154 poll_subscribed_mailboxes();
11155 }
11156
11157 return NULL;
11158 }
11159
11160 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11161 {
11162 ast_free(mwi_sub);
11163 }
11164
11165 static int handle_unsubscribe(void *datap)
11166 {
11167 struct mwi_sub *mwi_sub;
11168 uint32_t *uniqueid = datap;
11169
11170 AST_RWLIST_WRLOCK(&mwi_subs);
11171 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11172 if (mwi_sub->uniqueid == *uniqueid) {
11173 AST_LIST_REMOVE_CURRENT(entry);
11174 break;
11175 }
11176 }
11177 AST_RWLIST_TRAVERSE_SAFE_END
11178 AST_RWLIST_UNLOCK(&mwi_subs);
11179
11180 if (mwi_sub)
11181 mwi_sub_destroy(mwi_sub);
11182
11183 ast_free(uniqueid);
11184 return 0;
11185 }
11186
11187 static int handle_subscribe(void *datap)
11188 {
11189 unsigned int len;
11190 struct mwi_sub *mwi_sub;
11191 struct mwi_sub_task *p = datap;
11192
11193 len = sizeof(*mwi_sub);
11194 if (!ast_strlen_zero(p->mailbox))
11195 len += strlen(p->mailbox);
11196
11197 if (!ast_strlen_zero(p->context))
11198 len += strlen(p->context) + 1;
11199
11200 if (!(mwi_sub = ast_calloc(1, len)))
11201 return -1;
11202
11203 mwi_sub->uniqueid = p->uniqueid;
11204 if (!ast_strlen_zero(p->mailbox))
11205 strcpy(mwi_sub->mailbox, p->mailbox);
11206
11207 if (!ast_strlen_zero(p->context)) {
11208 strcat(mwi_sub->mailbox, "@");
11209 strcat(mwi_sub->mailbox, p->context);
11210 }
11211
11212 AST_RWLIST_WRLOCK(&mwi_subs);
11213 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11214 AST_RWLIST_UNLOCK(&mwi_subs);
11215 ast_free((void *) p->mailbox);
11216 ast_free((void *) p->context);
11217 ast_free(p);
11218 poll_subscribed_mailbox(mwi_sub);
11219 return 0;
11220 }
11221
11222 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11223 {
11224 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11225 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11226 return;
11227
11228 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11229 return;
11230
11231 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11232 *uniqueid = u;
11233 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11234 ast_free(uniqueid);
11235 }
11236 }
11237
11238 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11239 {
11240 struct mwi_sub_task *mwist;
11241
11242 if (ast_event_get_type(event) != AST_EVENT_SUB)
11243 return;
11244
11245 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11246 return;
11247
11248 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11249 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11250 return;
11251 }
11252 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11253 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11254 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11255
11256 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11257 ast_free(mwist);
11258 }
11259 }
11260
11261 static void start_poll_thread(void)
11262 {
11263 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11264 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11265 AST_EVENT_IE_END);
11266
11267 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11268 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11269 AST_EVENT_IE_END);
11270
11271 if (mwi_sub_sub)
11272 ast_event_report_subs(mwi_sub_sub);
11273
11274 poll_thread_run = 1;
11275
11276 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11277 }
11278
11279 static void stop_poll_thread(void)
11280 {
11281 poll_thread_run = 0;
11282
11283 if (mwi_sub_sub) {
11284 ast_event_unsubscribe(mwi_sub_sub);
11285 mwi_sub_sub = NULL;
11286 }
11287
11288 if (mwi_unsub_sub) {
11289 ast_event_unsubscribe(mwi_unsub_sub);
11290 mwi_unsub_sub = NULL;
11291 }
11292
11293 ast_mutex_lock(&poll_lock);
11294 ast_cond_signal(&poll_cond);
11295 ast_mutex_unlock(&poll_lock);
11296
11297 pthread_join(poll_thread, NULL);
11298
11299 poll_thread = AST_PTHREADT_NULL;
11300 }
11301
11302
11303 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11304 {
11305 struct ast_vm_user *vmu = NULL;
11306 const char *id = astman_get_header(m, "ActionID");
11307 char actionid[128] = "";
11308
11309 if (!ast_strlen_zero(id))
11310 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11311
11312 AST_LIST_LOCK(&users);
11313
11314 if (AST_LIST_EMPTY(&users)) {
11315 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11316 AST_LIST_UNLOCK(&users);
11317 return RESULT_SUCCESS;
11318 }
11319
11320 astman_send_ack(s, m, "Voicemail user list will follow");
11321
11322 AST_LIST_TRAVERSE(&users, vmu, list) {
11323 char dirname[256];
11324
11325 #ifdef IMAP_STORAGE
11326 int new, old;
11327 inboxcount(vmu->mailbox, &new, &old);
11328 #endif
11329
11330 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11331 astman_append(s,
11332 "%s"
11333 "Event: VoicemailUserEntry\r\n"
11334 "VMContext: %s\r\n"
11335 "VoiceMailbox: %s\r\n"
11336 "Fullname: %s\r\n"
11337 "Email: %s\r\n"
11338 "Pager: %s\r\n"
11339 "ServerEmail: %s\r\n"
11340 "MailCommand: %s\r\n"
11341 "Language: %s\r\n"
11342 "TimeZone: %s\r\n"
11343 "Callback: %s\r\n"
11344 "Dialout: %s\r\n"
11345 "UniqueID: %s\r\n"
11346 "ExitContext: %s\r\n"
11347 "SayDurationMinimum: %d\r\n"
11348 "SayEnvelope: %s\r\n"
11349 "SayCID: %s\r\n"
11350 "AttachMessage: %s\r\n"
11351 "AttachmentFormat: %s\r\n"
11352 "DeleteMessage: %s\r\n"
11353 "VolumeGain: %.2f\r\n"
11354 "CanReview: %s\r\n"
11355 "CallOperator: %s\r\n"
11356 "MaxMessageCount: %d\r\n"
11357 "MaxMessageLength: %d\r\n"
11358 "NewMessageCount: %d\r\n"
11359 #ifdef IMAP_STORAGE
11360 "OldMessageCount: %d\r\n"
11361 "IMAPUser: %s\r\n"
11362 #endif
11363 "\r\n",
11364 actionid,
11365 vmu->context,
11366 vmu->mailbox,
11367 vmu->fullname,
11368 vmu->email,
11369 vmu->pager,
11370 vmu->serveremail,
11371 vmu->mailcmd,
11372 vmu->language,
11373 vmu->zonetag,
11374 vmu->callback,
11375 vmu->dialout,
11376 vmu->uniqueid,
11377 vmu->exit,
11378 vmu->saydurationm,
11379 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11380 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11381 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11382 vmu->attachfmt,
11383 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11384 vmu->volgain,
11385 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11386 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11387 vmu->maxmsg,
11388 vmu->maxsecs,
11389 #ifdef IMAP_STORAGE
11390 new, old, vmu->imapuser
11391 #else
11392 count_messages(vmu, dirname)
11393 #endif
11394 );
11395 }
11396 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11397
11398 AST_LIST_UNLOCK(&users);
11399
11400 return RESULT_SUCCESS;
11401 }
11402
11403
11404 static void free_vm_users(void)
11405 {
11406 struct ast_vm_user *current;
11407 AST_LIST_LOCK(&users);
11408 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11409 ast_set_flag(current, VM_ALLOCED);
11410 free_user(current);
11411 }
11412 AST_LIST_UNLOCK(&users);
11413 }
11414
11415
11416 static void free_vm_zones(void)
11417 {
11418 struct vm_zone *zcur;
11419 AST_LIST_LOCK(&zones);
11420 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11421 free_zone(zcur);
11422 AST_LIST_UNLOCK(&zones);
11423 }
11424
11425 static const char *substitute_escapes(const char *value)
11426 {
11427 char *current;
11428
11429
11430 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11431
11432 ast_str_reset(str);
11433
11434
11435 for (current = (char *) value; *current; current++) {
11436 if (*current == '\\') {
11437 current++;
11438 if (!*current) {
11439 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11440 break;
11441 }
11442 switch (*current) {
11443 case 'r':
11444 ast_str_append(&str, 0, "\r");
11445 break;
11446 case 'n':
11447 #ifdef IMAP_STORAGE
11448 if (!str->used || str->str[str->used - 1] != '\r') {
11449 ast_str_append(&str, 0, "\r");
11450 }
11451 #endif
11452 ast_str_append(&str, 0, "\n");
11453 break;
11454 case 't':
11455 ast_str_append(&str, 0, "\t");
11456 break;
11457 default:
11458 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11459 break;
11460 }
11461 } else {
11462 ast_str_append(&str, 0, "%c", *current);
11463 }
11464 }
11465
11466 return ast_str_buffer(str);
11467 }
11468
11469 static int load_config(int reload)
11470 {
11471 struct ast_vm_user *current;
11472 struct ast_config *cfg, *ucfg;
11473 char *cat;
11474 struct ast_variable *var;
11475 const char *val;
11476 char *q, *stringp, *tmp;
11477 int x;
11478 int tmpadsi[4];
11479 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11480 char secretfn[PATH_MAX] = "";
11481
11482 ast_unload_realtime("voicemail");
11483 ast_unload_realtime("voicemail_data");
11484
11485 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11486 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11487 return 0;
11488 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11489 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11490 ucfg = NULL;
11491 }
11492 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11493 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11494 ast_config_destroy(ucfg);
11495 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11496 return 0;
11497 }
11498 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11499 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11500 return 0;
11501 } else {
11502 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11503 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11504 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11505 ucfg = NULL;
11506 }
11507 }
11508 #ifdef IMAP_STORAGE
11509 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11510 #endif
11511
11512 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11513 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11514 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11515 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11516 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11517
11518
11519 free_vm_users();
11520
11521
11522 free_vm_zones();
11523
11524 AST_LIST_LOCK(&users);
11525
11526 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11527 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11528
11529 if (cfg) {
11530
11531
11532 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11533 val = "default";
11534 ast_copy_string(userscontext, val, sizeof(userscontext));
11535
11536 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11537 val = "yes";
11538 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11539
11540 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11541 val = "no";
11542 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11543
11544 volgain = 0.0;
11545 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11546 sscanf(val, "%30lf", &volgain);
11547
11548 #ifdef ODBC_STORAGE
11549 strcpy(odbc_database, "asterisk");
11550 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11551 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11552 }
11553 strcpy(odbc_table, "voicemessages");
11554 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11555 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11556 }
11557 #endif
11558
11559 strcpy(mailcmd, SENDMAIL);
11560 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11561 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11562
11563 maxsilence = 0;
11564 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11565 maxsilence = atoi(val);
11566 if (maxsilence > 0)
11567 maxsilence *= 1000;
11568 }
11569
11570 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11571 maxmsg = MAXMSG;
11572 } else {
11573 maxmsg = atoi(val);
11574 if (maxmsg < 0) {
11575 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11576 maxmsg = MAXMSG;
11577 } else if (maxmsg > MAXMSGLIMIT) {
11578 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11579 maxmsg = MAXMSGLIMIT;
11580 }
11581 }
11582
11583 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11584 maxdeletedmsg = 0;
11585 } else {
11586 if (sscanf(val, "%30d", &x) == 1)
11587 maxdeletedmsg = x;
11588 else if (ast_true(val))
11589 maxdeletedmsg = MAXMSG;
11590 else
11591 maxdeletedmsg = 0;
11592
11593 if (maxdeletedmsg < 0) {
11594 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11595 maxdeletedmsg = MAXMSG;
11596 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11597 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11598 maxdeletedmsg = MAXMSGLIMIT;
11599 }
11600 }
11601
11602
11603 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11604 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11605 }
11606
11607
11608 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11609 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11610 }
11611
11612
11613 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11614 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11615 pwdchange = PWDCHANGE_EXTERNAL;
11616 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11617 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11618 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11619 }
11620
11621
11622 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11623 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11624 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11625 }
11626
11627 #ifdef IMAP_STORAGE
11628
11629 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11630 ast_copy_string(imapserver, val, sizeof(imapserver));
11631 } else {
11632 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11633 }
11634
11635 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11636 ast_copy_string(imapport, val, sizeof(imapport));
11637 } else {
11638 ast_copy_string(imapport, "143", sizeof(imapport));
11639 }
11640
11641 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11642 ast_copy_string(imapflags, val, sizeof(imapflags));
11643 }
11644
11645 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11646 ast_copy_string(authuser, val, sizeof(authuser));
11647 }
11648
11649 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11650 ast_copy_string(authpassword, val, sizeof(authpassword));
11651 }
11652
11653 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11654 if (ast_false(val))
11655 expungeonhangup = 0;
11656 else
11657 expungeonhangup = 1;
11658 } else {
11659 expungeonhangup = 1;
11660 }
11661
11662 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11663 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11664 } else {
11665 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11666 }
11667 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11668 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11669 }
11670 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11671 imapgreetings = ast_true(val);
11672 } else {
11673 imapgreetings = 0;
11674 }
11675 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11676 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11677 } else {
11678 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
11679 }
11680
11681
11682
11683
11684
11685 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
11686 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
11687 } else {
11688 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
11689 }
11690
11691 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
11692 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
11693 } else {
11694 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
11695 }
11696
11697 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
11698 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
11699 } else {
11700 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
11701 }
11702
11703 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
11704 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
11705 } else {
11706 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
11707 }
11708
11709
11710 imapversion++;
11711 #endif
11712
11713 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
11714 ast_copy_string(externnotify, val, sizeof(externnotify));
11715 ast_debug(1, "found externnotify: %s\n", externnotify);
11716 } else {
11717 externnotify[0] = '\0';
11718 }
11719
11720
11721 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
11722 ast_debug(1, "Enabled SMDI voicemail notification\n");
11723 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
11724 smdi_iface = ast_smdi_interface_find(val);
11725 } else {
11726 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
11727 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
11728 }
11729 if (!smdi_iface) {
11730 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
11731 }
11732 }
11733
11734
11735 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
11736 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
11737 silencethreshold = atoi(val);
11738
11739 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
11740 val = ASTERISK_USERNAME;
11741 ast_copy_string(serveremail, val, sizeof(serveremail));
11742
11743 vmmaxsecs = 0;
11744 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
11745 if (sscanf(val, "%30d", &x) == 1) {
11746 vmmaxsecs = x;
11747 } else {
11748 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11749 }
11750 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
11751 static int maxmessage_deprecate = 0;
11752 if (maxmessage_deprecate == 0) {
11753 maxmessage_deprecate = 1;
11754 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
11755 }
11756 if (sscanf(val, "%30d", &x) == 1) {
11757 vmmaxsecs = x;
11758 } else {
11759 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11760 }
11761 }
11762
11763 vmminsecs = 0;
11764 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
11765 if (sscanf(val, "%30d", &x) == 1) {
11766 vmminsecs = x;
11767 if (maxsilence / 1000 >= vmminsecs) {
11768 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
11769 }
11770 } else {
11771 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11772 }
11773 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
11774 static int maxmessage_deprecate = 0;
11775 if (maxmessage_deprecate == 0) {
11776 maxmessage_deprecate = 1;
11777 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
11778 }
11779 if (sscanf(val, "%30d", &x) == 1) {
11780 vmminsecs = x;
11781 if (maxsilence / 1000 >= vmminsecs) {
11782 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
11783 }
11784 } else {
11785 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11786 }
11787 }
11788
11789 val = ast_variable_retrieve(cfg, "general", "format");
11790 if (!val) {
11791 val = "wav";
11792 } else {
11793 tmp = ast_strdupa(val);
11794 val = ast_format_str_reduce(tmp);
11795 if (!val) {
11796 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
11797 val = "wav";
11798 }
11799 }
11800 ast_copy_string(vmfmts, val, sizeof(vmfmts));
11801
11802 skipms = 3000;
11803 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
11804 if (sscanf(val, "%30d", &x) == 1) {
11805 maxgreet = x;
11806 } else {
11807 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
11808 }
11809 }
11810
11811 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
11812 if (sscanf(val, "%30d", &x) == 1) {
11813 skipms = x;
11814 } else {
11815 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
11816 }
11817 }
11818
11819 maxlogins = 3;
11820 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
11821 if (sscanf(val, "%30d", &x) == 1) {
11822 maxlogins = x;
11823 } else {
11824 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
11825 }
11826 }
11827
11828 minpassword = MINPASSWORD;
11829 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
11830 if (sscanf(val, "%30d", &x) == 1) {
11831 minpassword = x;
11832 } else {
11833 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
11834 }
11835 }
11836
11837
11838 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
11839 val = "no";
11840 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
11841
11842
11843 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
11844 val = "no";
11845 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
11846
11847 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
11848 ast_debug(1, "VM_CID Internal context string: %s\n", val);
11849 stringp = ast_strdupa(val);
11850 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
11851 if (!ast_strlen_zero(stringp)) {
11852 q = strsep(&stringp, ",");
11853 while ((*q == ' ')||(*q == '\t'))
11854 q++;
11855 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
11856 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
11857 } else {
11858 cidinternalcontexts[x][0] = '\0';
11859 }
11860 }
11861 }
11862 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
11863 ast_debug(1, "VM Review Option disabled globally\n");
11864 val = "no";
11865 }
11866 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
11867
11868
11869 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
11870 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
11871 val = "no";
11872 } else {
11873 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
11874 }
11875 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
11876 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
11877 ast_debug(1, "VM next message wrap disabled globally\n");
11878 val = "no";
11879 }
11880 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
11881
11882 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
11883 ast_debug(1, "VM Operator break disabled globally\n");
11884 val = "no";
11885 }
11886 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
11887
11888 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
11889 ast_debug(1, "VM CID Info before msg disabled globally\n");
11890 val = "no";
11891 }
11892 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
11893
11894 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
11895 ast_debug(1, "Send Voicemail msg disabled globally\n");
11896 val = "no";
11897 }
11898 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
11899
11900 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
11901 ast_debug(1, "ENVELOPE before msg enabled globally\n");
11902 val = "yes";
11903 }
11904 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
11905
11906 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
11907 ast_debug(1, "Move Heard enabled globally\n");
11908 val = "yes";
11909 }
11910 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
11911
11912 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
11913 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
11914 val = "no";
11915 }
11916 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
11917
11918 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
11919 ast_debug(1, "Duration info before msg enabled globally\n");
11920 val = "yes";
11921 }
11922 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
11923
11924 saydurationminfo = 2;
11925 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
11926 if (sscanf(val, "%30d", &x) == 1) {
11927 saydurationminfo = x;
11928 } else {
11929 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
11930 }
11931 }
11932
11933 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
11934 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
11935 val = "no";
11936 }
11937 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
11938
11939 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
11940 ast_copy_string(dialcontext, val, sizeof(dialcontext));
11941 ast_debug(1, "found dialout context: %s\n", dialcontext);
11942 } else {
11943 dialcontext[0] = '\0';
11944 }
11945
11946 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
11947 ast_copy_string(callcontext, val, sizeof(callcontext));
11948 ast_debug(1, "found callback context: %s\n", callcontext);
11949 } else {
11950 callcontext[0] = '\0';
11951 }
11952
11953 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
11954 ast_copy_string(exitcontext, val, sizeof(exitcontext));
11955 ast_debug(1, "found operator context: %s\n", exitcontext);
11956 } else {
11957 exitcontext[0] = '\0';
11958 }
11959
11960
11961 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
11962 ast_copy_string(vm_password, val, sizeof(vm_password));
11963 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
11964 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
11965 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
11966 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
11967 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
11968 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
11969 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
11970 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
11971 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
11972 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
11973 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
11974 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
11975 }
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
11978 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
11979 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
11980 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
11981 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
11982 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
11983 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
11984 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
11985 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
11986 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
11987
11988 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
11989 val = "no";
11990 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
11991
11992 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
11993 val = "voicemail.conf";
11994 }
11995 if (!(strcmp(val, "spooldir"))) {
11996 passwordlocation = OPT_PWLOC_SPOOLDIR;
11997 } else {
11998 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
11999 }
12000
12001 poll_freq = DEFAULT_POLL_FREQ;
12002 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12003 if (sscanf(val, "%30u", &poll_freq) != 1) {
12004 poll_freq = DEFAULT_POLL_FREQ;
12005 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12006 }
12007 }
12008
12009 poll_mailboxes = 0;
12010 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12011 poll_mailboxes = ast_true(val);
12012
12013 if (ucfg) {
12014 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12015 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12016 continue;
12017 if ((current = find_or_create(userscontext, cat))) {
12018 populate_defaults(current);
12019 apply_options_full(current, ast_variable_browse(ucfg, cat));
12020 ast_copy_string(current->context, userscontext, sizeof(current->context));
12021 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12022 current->passwordlocation = OPT_PWLOC_USERSCONF;
12023 }
12024
12025 switch (current->passwordlocation) {
12026 case OPT_PWLOC_SPOOLDIR:
12027 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12028 read_password_from_file(secretfn, current->password, sizeof(current->password));
12029 }
12030 }
12031 }
12032 ast_config_destroy(ucfg);
12033 }
12034 cat = ast_category_browse(cfg, NULL);
12035 while (cat) {
12036 if (strcasecmp(cat, "general")) {
12037 var = ast_variable_browse(cfg, cat);
12038 if (strcasecmp(cat, "zonemessages")) {
12039
12040 while (var) {
12041 append_mailbox(cat, var->name, var->value);
12042 var = var->next;
12043 }
12044 } else {
12045
12046 while (var) {
12047 struct vm_zone *z;
12048 if ((z = ast_malloc(sizeof(*z)))) {
12049 char *msg_format, *tzone;
12050 msg_format = ast_strdupa(var->value);
12051 tzone = strsep(&msg_format, "|,");
12052 if (msg_format) {
12053 ast_copy_string(z->name, var->name, sizeof(z->name));
12054 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12055 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12056 AST_LIST_LOCK(&zones);
12057 AST_LIST_INSERT_HEAD(&zones, z, list);
12058 AST_LIST_UNLOCK(&zones);
12059 } else {
12060 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12061 ast_free(z);
12062 }
12063 } else {
12064 AST_LIST_UNLOCK(&users);
12065 ast_config_destroy(cfg);
12066 return -1;
12067 }
12068 var = var->next;
12069 }
12070 }
12071 }
12072 cat = ast_category_browse(cfg, cat);
12073 }
12074 memset(fromstring, 0, sizeof(fromstring));
12075 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12076 strcpy(charset, "ISO-8859-1");
12077 if (emailbody) {
12078 ast_free(emailbody);
12079 emailbody = NULL;
12080 }
12081 if (emailsubject) {
12082 ast_free(emailsubject);
12083 emailsubject = NULL;
12084 }
12085 if (pagerbody) {
12086 ast_free(pagerbody);
12087 pagerbody = NULL;
12088 }
12089 if (pagersubject) {
12090 ast_free(pagersubject);
12091 pagersubject = NULL;
12092 }
12093 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12094 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12095 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12096 ast_copy_string(fromstring, val, sizeof(fromstring));
12097 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12098 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12099 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12100 ast_copy_string(charset, val, sizeof(charset));
12101 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12102 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12103 for (x = 0; x < 4; x++) {
12104 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12105 }
12106 }
12107 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12108 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12109 for (x = 0; x < 4; x++) {
12110 memcpy(&adsisec[x], &tmpadsi[x], 1);
12111 }
12112 }
12113 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12114 if (atoi(val)) {
12115 adsiver = atoi(val);
12116 }
12117 }
12118 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12119 ast_copy_string(zonetag, val, sizeof(zonetag));
12120 }
12121 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12122 ast_copy_string(locale, val, sizeof(locale));
12123 }
12124 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12125 emailsubject = ast_strdup(val);
12126 }
12127 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12128 emailbody = ast_strdup(substitute_escapes(val));
12129 }
12130 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12131 pagersubject = ast_strdup(val);
12132 }
12133 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12134 pagerbody = ast_strdup(substitute_escapes(val));
12135 }
12136 AST_LIST_UNLOCK(&users);
12137 ast_config_destroy(cfg);
12138
12139 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12140 start_poll_thread();
12141 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12142 stop_poll_thread();;
12143
12144 return 0;
12145 } else {
12146 AST_LIST_UNLOCK(&users);
12147 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12148 if (ucfg)
12149 ast_config_destroy(ucfg);
12150 return 0;
12151 }
12152 }
12153
12154 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12155 {
12156 int res = -1;
12157 char dir[PATH_MAX];
12158 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12159 ast_debug(2, "About to try retrieving name file %s\n", dir);
12160 RETRIEVE(dir, -1, mailbox, context);
12161 if (ast_fileexists(dir, NULL, NULL)) {
12162 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12163 }
12164 DISPOSE(dir, -1);
12165 return res;
12166 }
12167
12168 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12169 struct ast_config *pwconf;
12170 struct ast_flags config_flags = { 0 };
12171
12172 pwconf = ast_config_load(secretfn, config_flags);
12173 if (pwconf) {
12174 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12175 if (val) {
12176 ast_copy_string(password, val, passwordlen);
12177 return;
12178 }
12179 }
12180 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12181 }
12182
12183 static int write_password_to_file(const char *secretfn, const char *password) {
12184 struct ast_config *conf;
12185 struct ast_category *cat;
12186 struct ast_variable *var;
12187
12188 if (!(conf=ast_config_new())) {
12189 ast_log(LOG_ERROR, "Error creating new config structure\n");
12190 return -1;
12191 }
12192 if (!(cat=ast_category_new("general","",1))) {
12193 ast_log(LOG_ERROR, "Error creating new category structure\n");
12194 return -1;
12195 }
12196 if (!(var=ast_variable_new("password",password,""))) {
12197 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12198 return -1;
12199 }
12200 ast_category_append(conf,cat);
12201 ast_variable_append(cat,var);
12202 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12203 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12204 return -1;
12205 }
12206 return 0;
12207 }
12208
12209 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12210 {
12211 char *context;
12212 char *args_copy;
12213 int res;
12214
12215 if (ast_strlen_zero(data)) {
12216 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12217 return -1;
12218 }
12219
12220 args_copy = ast_strdupa(data);
12221 if ((context = strchr(args_copy, '@'))) {
12222 *context++ = '\0';
12223 } else {
12224 context = "default";
12225 }
12226
12227 if ((res = sayname(chan, args_copy, context) < 0)) {
12228 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12229 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12230 if (!res) {
12231 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12232 }
12233 }
12234
12235 return res;
12236 }
12237
12238 #ifdef TEST_FRAMEWORK
12239 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12240 {
12241 return 0;
12242 }
12243
12244 static struct ast_frame *fake_read(struct ast_channel *ast)
12245 {
12246 return &ast_null_frame;
12247 }
12248
12249 AST_TEST_DEFINE(test_voicemail_vmsayname)
12250 {
12251 char dir[PATH_MAX];
12252 char dir2[PATH_MAX];
12253 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12254 static const char TEST_EXTENSION[] = "1234";
12255
12256 struct ast_channel *test_channel1 = NULL;
12257 int res = -1;
12258
12259 static const struct ast_channel_tech fake_tech = {
12260 .write = fake_write,
12261 .read = fake_read,
12262 };
12263
12264 switch (cmd) {
12265 case TEST_INIT:
12266 info->name = "vmsayname_exec";
12267 info->category = "/apps/app_voicemail/";
12268 info->summary = "Vmsayname unit test";
12269 info->description =
12270 "This tests passing various parameters to vmsayname";
12271 return AST_TEST_NOT_RUN;
12272 case TEST_EXECUTE:
12273 break;
12274 }
12275
12276 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12277 NULL, NULL, 0, 0, "TestChannel1"))) {
12278 goto exit_vmsayname_test;
12279 }
12280
12281
12282 test_channel1->nativeformats = AST_FORMAT_GSM;
12283 test_channel1->writeformat = AST_FORMAT_GSM;
12284 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12285 test_channel1->readformat = AST_FORMAT_GSM;
12286 test_channel1->rawreadformat = AST_FORMAT_GSM;
12287 test_channel1->tech = &fake_tech;
12288
12289 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12290 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12291 if (!(res = vmsayname_exec(test_channel1, dir))) {
12292 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12293 if (ast_fileexists(dir, NULL, NULL)) {
12294 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12295 res = -1;
12296 goto exit_vmsayname_test;
12297 } else {
12298
12299 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12300 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12301 goto exit_vmsayname_test;
12302 }
12303 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12304 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12305
12306 if ((res = symlink(dir, dir2))) {
12307 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12308 goto exit_vmsayname_test;
12309 }
12310 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12311 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12312 res = vmsayname_exec(test_channel1, dir);
12313
12314
12315 unlink(dir2);
12316 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12317 rmdir(dir2);
12318 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12319 rmdir(dir2);
12320 }
12321 }
12322
12323 exit_vmsayname_test:
12324
12325 if (test_channel1) {
12326 ast_hangup(test_channel1);
12327 }
12328
12329 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12330 }
12331
12332 AST_TEST_DEFINE(test_voicemail_msgcount)
12333 {
12334 int i, j, res = AST_TEST_PASS, syserr;
12335 struct ast_vm_user *vmu;
12336 struct vm_state vms;
12337 #ifdef IMAP_STORAGE
12338 struct ast_channel *chan = NULL;
12339 #endif
12340 struct {
12341 char dir[256];
12342 char file[256];
12343 char txtfile[256];
12344 } tmp[3];
12345 char syscmd[256];
12346 const char origweasels[] = "tt-weasels";
12347 const char testcontext[] = "test";
12348 const char testmailbox[] = "00000000";
12349 const char testspec[] = "00000000@test";
12350 FILE *txt;
12351 int new, old, urgent;
12352 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12353 const int folder2mbox[3] = { 1, 11, 0 };
12354 const int expected_results[3][12] = {
12355
12356 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12357 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12358 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12359 };
12360
12361 switch (cmd) {
12362 case TEST_INIT:
12363 info->name = "test_voicemail_msgcount";
12364 info->category = "/apps/app_voicemail/";
12365 info->summary = "Test Voicemail status checks";
12366 info->description =
12367 "Verify that message counts are correct when retrieved through the public API";
12368 return AST_TEST_NOT_RUN;
12369 case TEST_EXECUTE:
12370 break;
12371 }
12372
12373
12374 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12375 if ((syserr = ast_safe_system(syscmd))) {
12376 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12377 syserr > 0 ? strerror(syserr) : "unable to fork()");
12378 return AST_TEST_FAIL;
12379 }
12380
12381 #ifdef IMAP_STORAGE
12382 if (!(chan = ast_dummy_channel_alloc())) {
12383 ast_test_status_update(test, "Unable to create dummy channel\n");
12384 return AST_TEST_FAIL;
12385 }
12386 #endif
12387
12388 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12389 !(vmu = find_or_create(testcontext, testmailbox))) {
12390 ast_test_status_update(test, "Cannot create vmu structure\n");
12391 ast_unreplace_sigchld();
12392 return AST_TEST_FAIL;
12393 }
12394
12395 populate_defaults(vmu);
12396 memset(&vms, 0, sizeof(vms));
12397
12398
12399 for (i = 0; i < 3; i++) {
12400 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12401 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12402 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12403
12404 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12405 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12406 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12407 if ((syserr = ast_safe_system(syscmd))) {
12408 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12409 syserr > 0 ? strerror(syserr) : "unable to fork()");
12410 ast_unreplace_sigchld();
12411 return AST_TEST_FAIL;
12412 }
12413 }
12414
12415 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12416 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12417 fclose(txt);
12418 } else {
12419 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12420 res = AST_TEST_FAIL;
12421 break;
12422 }
12423 open_mailbox(&vms, vmu, folder2mbox[i]);
12424 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12425
12426
12427 for (j = 0; j < 3; j++) {
12428
12429 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12430 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12431 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12432 res = AST_TEST_FAIL;
12433 }
12434 }
12435
12436 new = old = urgent = 0;
12437 if (ast_app_inboxcount(testspec, &new, &old)) {
12438 ast_test_status_update(test, "inboxcount returned failure\n");
12439 res = AST_TEST_FAIL;
12440 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12441 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12442 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12443 res = AST_TEST_FAIL;
12444 }
12445
12446 new = old = urgent = 0;
12447 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12448 ast_test_status_update(test, "inboxcount2 returned failure\n");
12449 res = AST_TEST_FAIL;
12450 } else if (old != expected_results[i][6 + 0] ||
12451 urgent != expected_results[i][6 + 1] ||
12452 new != expected_results[i][6 + 2] ) {
12453 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12454 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12455 res = AST_TEST_FAIL;
12456 }
12457
12458 new = old = urgent = 0;
12459 for (j = 0; j < 3; j++) {
12460 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12461 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12462 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12463 res = AST_TEST_FAIL;
12464 }
12465 }
12466 }
12467
12468 for (i = 0; i < 3; i++) {
12469
12470
12471
12472 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12473 DISPOSE(tmp[i].dir, 0);
12474 }
12475
12476 if (vms.deleted) {
12477 ast_free(vms.deleted);
12478 }
12479 if (vms.heard) {
12480 ast_free(vms.heard);
12481 }
12482
12483 #ifdef IMAP_STORAGE
12484 chan = ast_channel_release(chan);
12485 #endif
12486
12487
12488 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12489 if ((syserr = ast_safe_system(syscmd))) {
12490 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12491 syserr > 0 ? strerror(syserr) : "unable to fork()");
12492 }
12493
12494 return res;
12495 }
12496
12497 AST_TEST_DEFINE(test_voicemail_notify_endl)
12498 {
12499 int res = AST_TEST_PASS;
12500 char testcontext[] = "test";
12501 char testmailbox[] = "00000000";
12502 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12503 char attach[256], attach2[256];
12504 char buf[256] = "";
12505 struct ast_channel *chan = NULL;
12506 struct ast_vm_user *vmu, vmus = {
12507 .flags = 0,
12508 };
12509 FILE *file;
12510 struct {
12511 char *name;
12512 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12513 void *location;
12514 union {
12515 int intval;
12516 char *strval;
12517 } u;
12518 } test_items[] = {
12519 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12520 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12521 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12522 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12523 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12524 { "attach2", STRPTR, attach2, .u.strval = "" },
12525 { "attach", STRPTR, attach, .u.strval = "" },
12526 };
12527 int which;
12528
12529 switch (cmd) {
12530 case TEST_INIT:
12531 info->name = "test_voicemail_notify_endl";
12532 info->category = "/apps/app_voicemail/";
12533 info->summary = "Test Voicemail notification end-of-line";
12534 info->description =
12535 "Verify that notification emails use a consistent end-of-line character";
12536 return AST_TEST_NOT_RUN;
12537 case TEST_EXECUTE:
12538 break;
12539 }
12540
12541 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12542 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12543
12544 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12545 !(vmu = find_or_create(testcontext, testmailbox))) {
12546 ast_test_status_update(test, "Cannot create vmu structure\n");
12547 return AST_TEST_NOT_RUN;
12548 }
12549
12550 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12551 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12552 return AST_TEST_NOT_RUN;
12553 }
12554
12555 populate_defaults(vmu);
12556 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12557 #ifdef IMAP_STORAGE
12558
12559 #endif
12560
12561 file = tmpfile();
12562 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12563
12564 rewind(file);
12565 if (ftruncate(fileno(file), 0)) {
12566 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12567 res = AST_TEST_FAIL;
12568 break;
12569 }
12570
12571
12572 if (test_items[which].type == INT) {
12573 *((int *) test_items[which].location) = test_items[which].u.intval;
12574 } else if (test_items[which].type == FLAGVAL) {
12575 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12576 ast_clear_flag(vmu, test_items[which].u.intval);
12577 } else {
12578 ast_set_flag(vmu, test_items[which].u.intval);
12579 }
12580 } else if (test_items[which].type == STATIC) {
12581 strcpy(test_items[which].location, test_items[which].u.strval);
12582 } else if (test_items[which].type == STRPTR) {
12583 test_items[which].location = test_items[which].u.strval;
12584 }
12585
12586 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12587 rewind(file);
12588 while (fgets(buf, sizeof(buf), file)) {
12589 if (
12590 #ifdef IMAP_STORAGE
12591 buf[strlen(buf) - 2] != '\r'
12592 #else
12593 buf[strlen(buf) - 2] == '\r'
12594 #endif
12595 || buf[strlen(buf) - 1] != '\n') {
12596 res = AST_TEST_FAIL;
12597 }
12598 }
12599 }
12600 fclose(file);
12601 return res;
12602 }
12603 #endif
12604
12605 static int reload(void)
12606 {
12607 return load_config(1);
12608 }
12609
12610 static int unload_module(void)
12611 {
12612 int res;
12613
12614 res = ast_unregister_application(app);
12615 res |= ast_unregister_application(app2);
12616 res |= ast_unregister_application(app3);
12617 res |= ast_unregister_application(app4);
12618 res |= ast_unregister_application(sayname_app);
12619 res |= ast_custom_function_unregister(&mailbox_exists_acf);
12620 res |= ast_manager_unregister("VoicemailUsersList");
12621 res |= ast_data_unregister(NULL);
12622 #ifdef TEST_FRAMEWORK
12623 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
12624 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
12625 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
12626 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
12627 #endif
12628 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12629 ast_uninstall_vm_functions();
12630 ao2_ref(inprocess_container, -1);
12631
12632 if (poll_thread != AST_PTHREADT_NULL)
12633 stop_poll_thread();
12634
12635 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
12636 ast_unload_realtime("voicemail");
12637 ast_unload_realtime("voicemail_data");
12638
12639 free_vm_users();
12640 free_vm_zones();
12641 return res;
12642 }
12643
12644 static int load_module(void)
12645 {
12646 int res;
12647 my_umask = umask(0);
12648 umask(my_umask);
12649
12650 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
12651 return AST_MODULE_LOAD_DECLINE;
12652 }
12653
12654
12655 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
12656
12657 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
12658 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
12659 }
12660
12661 if ((res = load_config(0)))
12662 return res;
12663
12664 res = ast_register_application_xml(app, vm_exec);
12665 res |= ast_register_application_xml(app2, vm_execmain);
12666 res |= ast_register_application_xml(app3, vm_box_exists);
12667 res |= ast_register_application_xml(app4, vmauthenticate);
12668 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
12669 res |= ast_custom_function_register(&mailbox_exists_acf);
12670 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
12671 #ifdef TEST_FRAMEWORK
12672 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
12673 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
12674 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
12675 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
12676 #endif
12677
12678 if (res)
12679 return res;
12680
12681 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12682 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
12683
12684 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
12685 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
12686 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
12687
12688 return res;
12689 }
12690
12691 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
12692 {
12693 int cmd = 0;
12694 char destination[80] = "";
12695 int retries = 0;
12696
12697 if (!num) {
12698 ast_verb(3, "Destination number will be entered manually\n");
12699 while (retries < 3 && cmd != 't') {
12700 destination[1] = '\0';
12701 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
12702 if (!cmd)
12703 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
12704 if (!cmd)
12705 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
12706 if (!cmd) {
12707 cmd = ast_waitfordigit(chan, 6000);
12708 if (cmd)
12709 destination[0] = cmd;
12710 }
12711 if (!cmd) {
12712 retries++;
12713 } else {
12714
12715 if (cmd < 0)
12716 return 0;
12717 if (cmd == '*') {
12718 ast_verb(3, "User hit '*' to cancel outgoing call\n");
12719 return 0;
12720 }
12721 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
12722 retries++;
12723 else
12724 cmd = 't';
12725 }
12726 }
12727 if (retries >= 3) {
12728 return 0;
12729 }
12730
12731 } else {
12732 if (option_verbose > 2)
12733 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
12734 ast_copy_string(destination, num, sizeof(destination));
12735 }
12736
12737 if (!ast_strlen_zero(destination)) {
12738 if (destination[strlen(destination) -1 ] == '*')
12739 return 0;
12740 if (option_verbose > 2)
12741 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
12742 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
12743 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
12744 chan->priority = 0;
12745 return 9;
12746 }
12747 return 0;
12748 }
12749
12750
12751
12752
12753
12754
12755
12756
12757
12758
12759
12760
12761
12762
12763 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)
12764 {
12765 int res = 0;
12766 char filename[PATH_MAX];
12767 struct ast_config *msg_cfg = NULL;
12768 const char *origtime, *context;
12769 char *name, *num;
12770 int retries = 0;
12771 char *cid;
12772 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
12773
12774 vms->starting = 0;
12775
12776 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12777
12778
12779 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
12780 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
12781 msg_cfg = ast_config_load(filename, config_flags);
12782 DISPOSE(vms->curdir, vms->curmsg);
12783 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
12784 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
12785 return 0;
12786 }
12787
12788 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
12789 ast_config_destroy(msg_cfg);
12790 return 0;
12791 }
12792
12793 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
12794
12795 context = ast_variable_retrieve(msg_cfg, "message", "context");
12796 if (!strncasecmp("macro", context, 5))
12797 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
12798 switch (option) {
12799 case 3:
12800 if (!res)
12801 res = play_message_datetime(chan, vmu, origtime, filename);
12802 if (!res)
12803 res = play_message_callerid(chan, vms, cid, context, 0);
12804
12805 res = 't';
12806 break;
12807
12808 case 2:
12809
12810 if (ast_strlen_zero(cid))
12811 break;
12812
12813 ast_callerid_parse(cid, &name, &num);
12814 while ((res > -1) && (res != 't')) {
12815 switch (res) {
12816 case '1':
12817 if (num) {
12818
12819 res = dialout(chan, vmu, num, vmu->callback);
12820 if (res) {
12821 ast_config_destroy(msg_cfg);
12822 return 9;
12823 }
12824 } else {
12825 res = '2';
12826 }
12827 break;
12828
12829 case '2':
12830
12831 if (!ast_strlen_zero(vmu->dialout)) {
12832 res = dialout(chan, vmu, NULL, vmu->dialout);
12833 if (res) {
12834 ast_config_destroy(msg_cfg);
12835 return 9;
12836 }
12837 } else {
12838 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
12839 res = ast_play_and_wait(chan, "vm-sorry");
12840 }
12841 ast_config_destroy(msg_cfg);
12842 return res;
12843 case '*':
12844 res = 't';
12845 break;
12846 case '3':
12847 case '4':
12848 case '5':
12849 case '6':
12850 case '7':
12851 case '8':
12852 case '9':
12853 case '0':
12854
12855 res = ast_play_and_wait(chan, "vm-sorry");
12856 retries++;
12857 break;
12858 default:
12859 if (num) {
12860 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
12861 res = ast_play_and_wait(chan, "vm-num-i-have");
12862 if (!res)
12863 res = play_message_callerid(chan, vms, num, vmu->context, 1);
12864 if (!res)
12865 res = ast_play_and_wait(chan, "vm-tocallnum");
12866
12867 if (!ast_strlen_zero(vmu->dialout)) {
12868 if (!res)
12869 res = ast_play_and_wait(chan, "vm-calldiffnum");
12870 }
12871 } else {
12872 res = ast_play_and_wait(chan, "vm-nonumber");
12873 if (!ast_strlen_zero(vmu->dialout)) {
12874 if (!res)
12875 res = ast_play_and_wait(chan, "vm-toenternumber");
12876 }
12877 }
12878 if (!res)
12879 res = ast_play_and_wait(chan, "vm-star-cancel");
12880 if (!res)
12881 res = ast_waitfordigit(chan, 6000);
12882 if (!res) {
12883 retries++;
12884 if (retries > 3)
12885 res = 't';
12886 }
12887 break;
12888
12889 }
12890 if (res == 't')
12891 res = 0;
12892 else if (res == '*')
12893 res = -1;
12894 }
12895 break;
12896
12897 case 1:
12898
12899 if (ast_strlen_zero(cid))
12900 break;
12901
12902 ast_callerid_parse(cid, &name, &num);
12903 if (!num) {
12904 ast_verb(3, "No CID number available, no reply sent\n");
12905 if (!res)
12906 res = ast_play_and_wait(chan, "vm-nonumber");
12907 ast_config_destroy(msg_cfg);
12908 return res;
12909 } else {
12910 struct ast_vm_user vmu2;
12911 if (find_user(&vmu2, vmu->context, num)) {
12912 struct leave_vm_options leave_options;
12913 char mailbox[AST_MAX_EXTENSION * 2 + 2];
12914 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
12915
12916 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
12917
12918 memset(&leave_options, 0, sizeof(leave_options));
12919 leave_options.record_gain = record_gain;
12920 res = leave_voicemail(chan, mailbox, &leave_options);
12921 if (!res)
12922 res = 't';
12923 ast_config_destroy(msg_cfg);
12924 return res;
12925 } else {
12926
12927 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
12928 ast_play_and_wait(chan, "vm-nobox");
12929 res = 't';
12930 ast_config_destroy(msg_cfg);
12931 return res;
12932 }
12933 }
12934 res = 0;
12935
12936 break;
12937 }
12938
12939 #ifndef IMAP_STORAGE
12940 ast_config_destroy(msg_cfg);
12941
12942 if (!res) {
12943 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12944 vms->heard[msg] = 1;
12945 res = wait_file(chan, vms, vms->fn);
12946 }
12947 #endif
12948 return res;
12949 }
12950
12951 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
12952 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
12953 signed char record_gain, struct vm_state *vms, char *flag)
12954 {
12955
12956 int res = 0;
12957 int cmd = 0;
12958 int max_attempts = 3;
12959 int attempts = 0;
12960 int recorded = 0;
12961 int msg_exists = 0;
12962 signed char zero_gain = 0;
12963 char tempfile[PATH_MAX];
12964 char *acceptdtmf = "#";
12965 char *canceldtmf = "";
12966 int canceleddtmf = 0;
12967
12968
12969
12970
12971 if (duration == NULL) {
12972 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
12973 return -1;
12974 }
12975
12976 if (!outsidecaller)
12977 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
12978 else
12979 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
12980
12981 cmd = '3';
12982
12983 while ((cmd >= 0) && (cmd != 't')) {
12984 switch (cmd) {
12985 case '1':
12986 if (!msg_exists) {
12987
12988 cmd = '3';
12989 break;
12990 } else {
12991
12992 ast_verb(3, "Saving message as is\n");
12993 if (!outsidecaller)
12994 ast_filerename(tempfile, recordfile, NULL);
12995 ast_stream_and_wait(chan, "vm-msgsaved", "");
12996 if (!outsidecaller) {
12997
12998 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
12999 DISPOSE(recordfile, -1);
13000 }
13001 cmd = 't';
13002 return res;
13003 }
13004 case '2':
13005
13006 ast_verb(3, "Reviewing the message\n");
13007 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13008 break;
13009 case '3':
13010 msg_exists = 0;
13011
13012 if (recorded == 1)
13013 ast_verb(3, "Re-recording the message\n");
13014 else
13015 ast_verb(3, "Recording the message\n");
13016
13017 if (recorded && outsidecaller) {
13018 cmd = ast_play_and_wait(chan, INTRO);
13019 cmd = ast_play_and_wait(chan, "beep");
13020 }
13021 recorded = 1;
13022
13023 if (record_gain)
13024 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13025 if (ast_test_flag(vmu, VM_OPERATOR))
13026 canceldtmf = "0";
13027 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13028 if (strchr(canceldtmf, cmd)) {
13029
13030 canceleddtmf = 1;
13031 }
13032 if (record_gain)
13033 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13034 if (cmd == -1) {
13035
13036 if (!outsidecaller) {
13037
13038 ast_filedelete(tempfile, NULL);
13039 }
13040 return cmd;
13041 }
13042 if (cmd == '0') {
13043 break;
13044 } else if (cmd == '*') {
13045 break;
13046 #if 0
13047 } else if (vmu->review && (*duration < 5)) {
13048
13049 ast_verb(3, "Message too short\n");
13050 cmd = ast_play_and_wait(chan, "vm-tooshort");
13051 cmd = ast_filedelete(tempfile, NULL);
13052 break;
13053 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
13054
13055 ast_verb(3, "Nothing recorded\n");
13056 cmd = ast_filedelete(tempfile, NULL);
13057 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13058 if (!cmd)
13059 cmd = ast_play_and_wait(chan, "vm-speakup");
13060 break;
13061 #endif
13062 } else {
13063
13064 msg_exists = 1;
13065 cmd = 0;
13066 }
13067 break;
13068 case '4':
13069 if (outsidecaller) {
13070
13071 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13072 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13073 res = ast_play_and_wait(chan, "vm-marked-urgent");
13074 strcpy(flag, "Urgent");
13075 } else if (flag) {
13076 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13077 res = ast_play_and_wait(chan, "vm-urgent-removed");
13078 strcpy(flag, "");
13079 } else {
13080 ast_play_and_wait(chan, "vm-sorry");
13081 }
13082 cmd = 0;
13083 } else {
13084 cmd = ast_play_and_wait(chan, "vm-sorry");
13085 }
13086 break;
13087 case '5':
13088 case '6':
13089 case '7':
13090 case '8':
13091 case '9':
13092 case '*':
13093 case '#':
13094 cmd = ast_play_and_wait(chan, "vm-sorry");
13095 break;
13096 #if 0
13097
13098
13099 case '*':
13100
13101 cmd = ast_play_and_wait(chan, "vm-deleted");
13102 cmd = ast_filedelete(tempfile, NULL);
13103 if (outsidecaller) {
13104 res = vm_exec(chan, NULL);
13105 return res;
13106 }
13107 else
13108 return 1;
13109 #endif
13110 case '0':
13111 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13112 cmd = ast_play_and_wait(chan, "vm-sorry");
13113 break;
13114 }
13115 if (msg_exists || recorded) {
13116 cmd = ast_play_and_wait(chan, "vm-saveoper");
13117 if (!cmd)
13118 cmd = ast_waitfordigit(chan, 3000);
13119 if (cmd == '1') {
13120 ast_filerename(tempfile, recordfile, NULL);
13121 ast_play_and_wait(chan, "vm-msgsaved");
13122 cmd = '0';
13123 } else if (cmd == '4') {
13124 if (flag) {
13125 ast_play_and_wait(chan, "vm-marked-urgent");
13126 strcpy(flag, "Urgent");
13127 }
13128 ast_play_and_wait(chan, "vm-msgsaved");
13129 cmd = '0';
13130 } else {
13131 ast_play_and_wait(chan, "vm-deleted");
13132 DELETE(tempfile, -1, tempfile, vmu);
13133 cmd = '0';
13134 }
13135 }
13136 return cmd;
13137 default:
13138
13139
13140
13141 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13142 return cmd;
13143 if (msg_exists) {
13144 cmd = ast_play_and_wait(chan, "vm-review");
13145 if (!cmd && outsidecaller) {
13146 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13147 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13148 } else if (flag) {
13149 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13150 }
13151 }
13152 } else {
13153 cmd = ast_play_and_wait(chan, "vm-torerecord");
13154 if (!cmd)
13155 cmd = ast_waitfordigit(chan, 600);
13156 }
13157
13158 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13159 cmd = ast_play_and_wait(chan, "vm-reachoper");
13160 if (!cmd)
13161 cmd = ast_waitfordigit(chan, 600);
13162 }
13163 #if 0
13164 if (!cmd)
13165 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13166 #endif
13167 if (!cmd)
13168 cmd = ast_waitfordigit(chan, 6000);
13169 if (!cmd) {
13170 attempts++;
13171 }
13172 if (attempts > max_attempts) {
13173 cmd = 't';
13174 }
13175 }
13176 }
13177 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13178
13179 ast_filedelete(tempfile, NULL);
13180 }
13181
13182 if (cmd != 't' && outsidecaller)
13183 ast_play_and_wait(chan, "vm-goodbye");
13184
13185 return cmd;
13186 }
13187
13188
13189
13190
13191
13192 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13193 .load = load_module,
13194 .unload = unload_module,
13195 .reload = reload,
13196 .nonoptreq = "res_adsi,res_smdi",
13197 );