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: 306967 $")
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 char extension[4];
03903 int stopcount = 0;
03904
03905
03906
03907
03908
03909 if (!(msgdir = opendir(dir))) {
03910 return -1;
03911 }
03912
03913 while ((msgdirent = readdir(msgdir))) {
03914 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
03915 map[msgdirint] = 1;
03916 stopcount++;
03917 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
03918 }
03919 }
03920 closedir(msgdir);
03921
03922 for (x = 0; x < vmu->maxmsg; x++) {
03923 if (map[x] == 1) {
03924 stopcount--;
03925 } else if (map[x] == 0 && !stopcount) {
03926 break;
03927 }
03928 }
03929
03930 return x - 1;
03931 }
03932
03933 #endif
03934 #endif
03935 #ifndef IMAP_STORAGE
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946 static int copy(char *infile, char *outfile)
03947 {
03948 int ifd;
03949 int ofd;
03950 int res;
03951 int len;
03952 char buf[4096];
03953
03954 #ifdef HARDLINK_WHEN_POSSIBLE
03955
03956 if (link(infile, outfile)) {
03957 #endif
03958 if ((ifd = open(infile, O_RDONLY)) < 0) {
03959 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03960 return -1;
03961 }
03962 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03963 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03964 close(ifd);
03965 return -1;
03966 }
03967 do {
03968 len = read(ifd, buf, sizeof(buf));
03969 if (len < 0) {
03970 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03971 close(ifd);
03972 close(ofd);
03973 unlink(outfile);
03974 }
03975 if (len) {
03976 res = write(ofd, buf, len);
03977 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03978 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03979 close(ifd);
03980 close(ofd);
03981 unlink(outfile);
03982 }
03983 }
03984 } while (len);
03985 close(ifd);
03986 close(ofd);
03987 return 0;
03988 #ifdef HARDLINK_WHEN_POSSIBLE
03989 } else {
03990
03991 return 0;
03992 }
03993 #endif
03994 }
03995
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005 static void copy_plain_file(char *frompath, char *topath)
04006 {
04007 char frompath2[PATH_MAX], topath2[PATH_MAX];
04008 struct ast_variable *tmp,*var = NULL;
04009 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04010 ast_filecopy(frompath, topath, NULL);
04011 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04012 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04013 if (ast_check_realtime("voicemail_data")) {
04014 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04015
04016 for (tmp = var; tmp; tmp = tmp->next) {
04017 if (!strcasecmp(tmp->name, "origmailbox")) {
04018 origmailbox = tmp->value;
04019 } else if (!strcasecmp(tmp->name, "context")) {
04020 context = tmp->value;
04021 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04022 macrocontext = tmp->value;
04023 } else if (!strcasecmp(tmp->name, "exten")) {
04024 exten = tmp->value;
04025 } else if (!strcasecmp(tmp->name, "priority")) {
04026 priority = tmp->value;
04027 } else if (!strcasecmp(tmp->name, "callerchan")) {
04028 callerchan = tmp->value;
04029 } else if (!strcasecmp(tmp->name, "callerid")) {
04030 callerid = tmp->value;
04031 } else if (!strcasecmp(tmp->name, "origdate")) {
04032 origdate = tmp->value;
04033 } else if (!strcasecmp(tmp->name, "origtime")) {
04034 origtime = tmp->value;
04035 } else if (!strcasecmp(tmp->name, "category")) {
04036 category = tmp->value;
04037 } else if (!strcasecmp(tmp->name, "duration")) {
04038 duration = tmp->value;
04039 }
04040 }
04041 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);
04042 }
04043 copy(frompath2, topath2);
04044 ast_variables_destroy(var);
04045 }
04046 #endif
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056 static int vm_delete(char *file)
04057 {
04058 char *txt;
04059 int txtsize = 0;
04060
04061 txtsize = (strlen(file) + 5)*sizeof(char);
04062 txt = alloca(txtsize);
04063
04064
04065
04066 if (ast_check_realtime("voicemail_data")) {
04067 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04068 }
04069 snprintf(txt, txtsize, "%s.txt", file);
04070 unlink(txt);
04071 return ast_filedelete(file, NULL);
04072 }
04073
04074
04075
04076
04077 static int inbuf(struct baseio *bio, FILE *fi)
04078 {
04079 int l;
04080
04081 if (bio->ateof)
04082 return 0;
04083
04084 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04085 if (ferror(fi))
04086 return -1;
04087
04088 bio->ateof = 1;
04089 return 0;
04090 }
04091
04092 bio->iolen = l;
04093 bio->iocp = 0;
04094
04095 return 1;
04096 }
04097
04098
04099
04100
04101 static int inchar(struct baseio *bio, FILE *fi)
04102 {
04103 if (bio->iocp>=bio->iolen) {
04104 if (!inbuf(bio, fi))
04105 return EOF;
04106 }
04107
04108 return bio->iobuf[bio->iocp++];
04109 }
04110
04111
04112
04113
04114 static int ochar(struct baseio *bio, int c, FILE *so)
04115 {
04116 if (bio->linelength >= BASELINELEN) {
04117 if (fputs(ENDL, so) == EOF) {
04118 return -1;
04119 }
04120
04121 bio->linelength = 0;
04122 }
04123
04124 if (putc(((unsigned char) c), so) == EOF) {
04125 return -1;
04126 }
04127
04128 bio->linelength++;
04129
04130 return 1;
04131 }
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141
04142 static int base_encode(char *filename, FILE *so)
04143 {
04144 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04145 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04146 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04147 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04148 int i, hiteof = 0;
04149 FILE *fi;
04150 struct baseio bio;
04151
04152 memset(&bio, 0, sizeof(bio));
04153 bio.iocp = BASEMAXINLINE;
04154
04155 if (!(fi = fopen(filename, "rb"))) {
04156 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04157 return -1;
04158 }
04159
04160 while (!hiteof){
04161 unsigned char igroup[3], ogroup[4];
04162 int c, n;
04163
04164 memset(igroup, 0, sizeof(igroup));
04165
04166 for (n = 0; n < 3; n++) {
04167 if ((c = inchar(&bio, fi)) == EOF) {
04168 hiteof = 1;
04169 break;
04170 }
04171
04172 igroup[n] = (unsigned char) c;
04173 }
04174
04175 if (n > 0) {
04176 ogroup[0]= dtable[igroup[0] >> 2];
04177 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04178 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04179 ogroup[3]= dtable[igroup[2] & 0x3F];
04180
04181 if (n < 3) {
04182 ogroup[3] = '=';
04183
04184 if (n < 2)
04185 ogroup[2] = '=';
04186 }
04187
04188 for (i = 0; i < 4; i++)
04189 ochar(&bio, ogroup[i], so);
04190 }
04191 }
04192
04193 fclose(fi);
04194
04195 if (fputs(ENDL, so) == EOF) {
04196 return 0;
04197 }
04198
04199 return 1;
04200 }
04201
04202 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)
04203 {
04204 char callerid[256];
04205 char num[12];
04206 char fromdir[256], fromfile[256];
04207 struct ast_config *msg_cfg;
04208 const char *origcallerid, *origtime;
04209 char origcidname[80], origcidnum[80], origdate[80];
04210 int inttime;
04211 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04212
04213
04214 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04215 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04216 snprintf(num, sizeof(num), "%d", msgnum);
04217 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04218 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04219 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04220 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04221 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04222 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04223 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04224 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04225 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04226 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04227
04228
04229 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04230 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04231 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04232 strcat(fromfile, ".txt");
04233 }
04234 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04235 if (option_debug > 0) {
04236 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04237 }
04238 return;
04239 }
04240
04241 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04242 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04243 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04244 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04245 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04246 }
04247
04248 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04249 struct timeval tv = { inttime, };
04250 struct ast_tm tm;
04251 ast_localtime(&tv, &tm, NULL);
04252 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04253 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04254 }
04255 ast_config_destroy(msg_cfg);
04256 }
04257
04258
04259
04260
04261
04262
04263
04264
04265
04266 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04267 {
04268 const char *ptr;
04269
04270
04271 ast_str_set(buf, maxlen, "\"");
04272 for (ptr = from; *ptr; ptr++) {
04273 if (*ptr == '"' || *ptr == '\\') {
04274 ast_str_append(buf, maxlen, "\\%c", *ptr);
04275 } else {
04276 ast_str_append(buf, maxlen, "%c", *ptr);
04277 }
04278 }
04279 ast_str_append(buf, maxlen, "\"");
04280
04281 return ast_str_buffer(*buf);
04282 }
04283
04284
04285
04286
04287
04288 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04289 {
04290 const struct vm_zone *z = NULL;
04291 struct timeval t = ast_tvnow();
04292
04293
04294 if (!ast_strlen_zero(vmu->zonetag)) {
04295
04296 AST_LIST_LOCK(&zones);
04297 AST_LIST_TRAVERSE(&zones, z, list) {
04298 if (!strcmp(z->name, vmu->zonetag))
04299 break;
04300 }
04301 AST_LIST_UNLOCK(&zones);
04302 }
04303 ast_localtime(&t, tm, z ? z->timezone : NULL);
04304 return tm;
04305 }
04306
04307
04308
04309
04310
04311 static int check_mime(const char *str)
04312 {
04313 for (; *str; str++) {
04314 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04315 return 1;
04316 }
04317 }
04318 return 0;
04319 }
04320
04321
04322
04323
04324
04325
04326
04327
04328
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04339 {
04340 struct ast_str *tmp = ast_str_alloca(80);
04341 int first_section = 1;
04342
04343 ast_str_reset(*end);
04344 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04345 for (; *start; start++) {
04346 int need_encoding = 0;
04347 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04348 need_encoding = 1;
04349 }
04350 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04351 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04352 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04353 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04354
04355 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04356 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04357 first_section = 0;
04358 }
04359 if (need_encoding && *start == ' ') {
04360 ast_str_append(&tmp, -1, "_");
04361 } else if (need_encoding) {
04362 ast_str_append(&tmp, -1, "=%hhX", *start);
04363 } else {
04364 ast_str_append(&tmp, -1, "%c", *start);
04365 }
04366 }
04367 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04368 return ast_str_buffer(*end);
04369 }
04370
04371
04372
04373
04374
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394 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)
04395 {
04396 char date[256];
04397 char host[MAXHOSTNAMELEN] = "";
04398 char who[256];
04399 char bound[256];
04400 char dur[256];
04401 struct ast_tm tm;
04402 char enc_cidnum[256] = "", enc_cidname[256] = "";
04403 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04404 char *greeting_attachment;
04405 char filename[256];
04406
04407 if (!str1 || !str2) {
04408 ast_free(str1);
04409 ast_free(str2);
04410 return;
04411 }
04412
04413 if (cidnum) {
04414 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04415 }
04416 if (cidname) {
04417 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04418 }
04419 gethostname(host, sizeof(host) - 1);
04420
04421 if (strchr(srcemail, '@')) {
04422 ast_copy_string(who, srcemail, sizeof(who));
04423 } else {
04424 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04425 }
04426
04427 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04428 if (greeting_attachment) {
04429 *greeting_attachment++ = '\0';
04430 }
04431
04432 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04433 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04434 fprintf(p, "Date: %s" ENDL, date);
04435
04436
04437 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04438
04439 if (!ast_strlen_zero(fromstring)) {
04440 struct ast_channel *ast;
04441 if ((ast = ast_dummy_channel_alloc())) {
04442 char *ptr;
04443 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04444 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04445
04446 if (check_mime(ast_str_buffer(str1))) {
04447 int first_line = 1;
04448 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04449 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04450 *ptr = '\0';
04451 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04452 first_line = 0;
04453
04454 ast_str_set(&str2, 0, "%s", ptr + 1);
04455 }
04456 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04457 } else {
04458 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04459 }
04460 ast = ast_channel_release(ast);
04461 } else {
04462 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04463 }
04464 } else {
04465 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04466 }
04467
04468 if (check_mime(vmu->fullname)) {
04469 int first_line = 1;
04470 char *ptr;
04471 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04472 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04473 *ptr = '\0';
04474 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04475 first_line = 0;
04476
04477 ast_str_set(&str2, 0, "%s", ptr + 1);
04478 }
04479 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04480 } else {
04481 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04482 }
04483
04484 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04485 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04486 struct ast_channel *ast;
04487 if ((ast = ast_dummy_channel_alloc())) {
04488 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04489 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04490 if (check_mime(ast_str_buffer(str1))) {
04491 int first_line = 1;
04492 char *ptr;
04493 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04494 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04495 *ptr = '\0';
04496 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04497 first_line = 0;
04498
04499 ast_str_set(&str2, 0, "%s", ptr + 1);
04500 }
04501 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04502 } else {
04503 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04504 }
04505 ast = ast_channel_release(ast);
04506 } else {
04507 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04508 }
04509 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04510 if (ast_strlen_zero(flag)) {
04511 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04512 } else {
04513 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04514 }
04515 } else {
04516 if (ast_strlen_zero(flag)) {
04517 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04518 } else {
04519 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04520 }
04521 }
04522
04523 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04524 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04525 if (imap) {
04526
04527 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04528
04529 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04530 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04531 #ifdef IMAP_STORAGE
04532 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04533 #else
04534 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04535 #endif
04536
04537 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04538 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04539 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04540 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04541 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04542 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04543 if (!ast_strlen_zero(category)) {
04544 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04545 } else {
04546 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04547 }
04548 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04549 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04550 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04551 }
04552 if (!ast_strlen_zero(cidnum)) {
04553 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04554 }
04555 if (!ast_strlen_zero(cidname)) {
04556 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04557 }
04558 fprintf(p, "MIME-Version: 1.0" ENDL);
04559 if (attach_user_voicemail) {
04560
04561 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04562 (int) getpid(), (unsigned int) ast_random());
04563
04564 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04565 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04566 fprintf(p, "--%s" ENDL, bound);
04567 }
04568 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04569 if (emailbody || vmu->emailbody) {
04570 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04571 struct ast_channel *ast;
04572 if ((ast = ast_dummy_channel_alloc())) {
04573 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04574 ast_str_substitute_variables(&str1, 0, ast, e_body);
04575 #ifdef IMAP_STORAGE
04576 {
04577
04578 char *line = ast_str_buffer(str1), *next;
04579 do {
04580
04581 if ((next = strchr(line, '\n'))) {
04582 *next++ = '\0';
04583 }
04584 fprintf(p, "%s" ENDL, line);
04585 line = next;
04586 } while (!ast_strlen_zero(line));
04587 }
04588 #else
04589 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04590 #endif
04591 ast = ast_channel_release(ast);
04592 } else {
04593 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04594 }
04595 } else if (msgnum > -1) {
04596 if (strcmp(vmu->mailbox, mailbox)) {
04597
04598 struct ast_config *msg_cfg;
04599 const char *v;
04600 int inttime;
04601 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04602 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04603
04604 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04605 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04606 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04607 strcat(fromfile, ".txt");
04608 }
04609 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04610 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04611 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04612 }
04613
04614
04615
04616 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04617 struct timeval tv = { inttime, };
04618 struct ast_tm tm;
04619 ast_localtime(&tv, &tm, NULL);
04620 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04621 }
04622 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04623 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04624 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04625 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04626 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04627 date, origcallerid, origdate);
04628 ast_config_destroy(msg_cfg);
04629 } else {
04630 goto plain_message;
04631 }
04632 } else {
04633 plain_message:
04634 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04635 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04636 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04637 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04638 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04639 }
04640 } else {
04641 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04642 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04643 }
04644
04645 if (imap || attach_user_voicemail) {
04646 if (!ast_strlen_zero(attach2)) {
04647 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04648 ast_debug(5, "creating second attachment filename %s\n", filename);
04649 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04650 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04651 ast_debug(5, "creating attachment filename %s\n", filename);
04652 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04653 } else {
04654 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04655 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04656 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04657 }
04658 }
04659 ast_free(str1);
04660 ast_free(str2);
04661 }
04662
04663 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)
04664 {
04665 char tmpdir[256], newtmp[256];
04666 char fname[256];
04667 char tmpcmd[256];
04668 int tmpfd = -1;
04669
04670
04671 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04672
04673 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04674 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04675 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04676 tmpfd = mkstemp(newtmp);
04677 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04678 ast_debug(3, "newtmp: %s\n", newtmp);
04679 if (tmpfd > -1) {
04680 int soxstatus;
04681 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04682 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04683 attach = newtmp;
04684 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04685 } else {
04686 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04687 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04688 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04689 }
04690 }
04691 }
04692 fprintf(p, "--%s" ENDL, bound);
04693 if (msgnum > -1)
04694 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04695 else
04696 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04697 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04698 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04699 if (msgnum > -1)
04700 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04701 else
04702 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04703 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04704 base_encode(fname, p);
04705 if (last)
04706 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04707 if (tmpfd > -1) {
04708 unlink(fname);
04709 close(tmpfd);
04710 unlink(newtmp);
04711 }
04712 return 0;
04713 }
04714
04715 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)
04716 {
04717 FILE *p = NULL;
04718 char tmp[80] = "/tmp/astmail-XXXXXX";
04719 char tmp2[256];
04720 char *stringp;
04721
04722 if (vmu && ast_strlen_zero(vmu->email)) {
04723 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04724 return(0);
04725 }
04726
04727
04728 format = ast_strdupa(format);
04729 stringp = format;
04730 strsep(&stringp, "|");
04731
04732 if (!strcmp(format, "wav49"))
04733 format = "WAV";
04734 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));
04735
04736
04737 if ((p = vm_mkftemp(tmp)) == NULL) {
04738 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04739 return -1;
04740 } else {
04741 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04742 fclose(p);
04743 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04744 ast_safe_system(tmp2);
04745 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04746 }
04747 return 0;
04748 }
04749
04750 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)
04751 {
04752 char enc_cidnum[256], enc_cidname[256];
04753 char date[256];
04754 char host[MAXHOSTNAMELEN] = "";
04755 char who[256];
04756 char dur[PATH_MAX];
04757 char tmp[80] = "/tmp/astmail-XXXXXX";
04758 char tmp2[PATH_MAX];
04759 struct ast_tm tm;
04760 FILE *p;
04761 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04762
04763 if (!str1 || !str2) {
04764 ast_free(str1);
04765 ast_free(str2);
04766 return -1;
04767 }
04768
04769 if (cidnum) {
04770 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04771 }
04772 if (cidname) {
04773 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04774 }
04775
04776 if ((p = vm_mkftemp(tmp)) == NULL) {
04777 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04778 ast_free(str1);
04779 ast_free(str2);
04780 return -1;
04781 }
04782 gethostname(host, sizeof(host)-1);
04783 if (strchr(srcemail, '@')) {
04784 ast_copy_string(who, srcemail, sizeof(who));
04785 } else {
04786 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04787 }
04788 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04789 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04790 fprintf(p, "Date: %s\n", date);
04791
04792
04793 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04794
04795 if (!ast_strlen_zero(pagerfromstring)) {
04796 struct ast_channel *ast;
04797 if ((ast = ast_dummy_channel_alloc())) {
04798 char *ptr;
04799 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04800 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04801
04802 if (check_mime(ast_str_buffer(str1))) {
04803 int first_line = 1;
04804 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04805 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04806 *ptr = '\0';
04807 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04808 first_line = 0;
04809
04810 ast_str_set(&str2, 0, "%s", ptr + 1);
04811 }
04812 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04813 } else {
04814 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04815 }
04816 ast = ast_channel_release(ast);
04817 } else {
04818 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04819 }
04820 } else {
04821 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04822 }
04823
04824 if (check_mime(vmu->fullname)) {
04825 int first_line = 1;
04826 char *ptr;
04827 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04828 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04829 *ptr = '\0';
04830 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04831 first_line = 0;
04832
04833 ast_str_set(&str2, 0, "%s", ptr + 1);
04834 }
04835 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04836 } else {
04837 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04838 }
04839
04840 if (!ast_strlen_zero(pagersubject)) {
04841 struct ast_channel *ast;
04842 if ((ast = ast_dummy_channel_alloc())) {
04843 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04844 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04845 if (check_mime(ast_str_buffer(str1))) {
04846 int first_line = 1;
04847 char *ptr;
04848 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04849 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04850 *ptr = '\0';
04851 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04852 first_line = 0;
04853
04854 ast_str_set(&str2, 0, "%s", ptr + 1);
04855 }
04856 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04857 } else {
04858 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04859 }
04860 ast = ast_channel_release(ast);
04861 } else {
04862 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04863 }
04864 } else {
04865 if (ast_strlen_zero(flag)) {
04866 fprintf(p, "Subject: New VM\n\n");
04867 } else {
04868 fprintf(p, "Subject: New %s VM\n\n", flag);
04869 }
04870 }
04871
04872 if (pagerbody) {
04873 struct ast_channel *ast;
04874 if ((ast = ast_dummy_channel_alloc())) {
04875 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04876 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
04877 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04878 ast = ast_channel_release(ast);
04879 } else {
04880 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04881 }
04882 } else {
04883 fprintf(p, "New %s long %s msg in box %s\n"
04884 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04885 }
04886
04887 fclose(p);
04888 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04889 ast_safe_system(tmp2);
04890 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04891 ast_free(str1);
04892 ast_free(str2);
04893 return 0;
04894 }
04895
04896
04897
04898
04899
04900
04901
04902
04903
04904
04905 static int get_date(char *s, int len)
04906 {
04907 struct ast_tm tm;
04908 struct timeval t = ast_tvnow();
04909
04910 ast_localtime(&t, &tm, "UTC");
04911
04912 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04913 }
04914
04915 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
04916 {
04917 int res;
04918 char fn[PATH_MAX];
04919 char dest[PATH_MAX];
04920
04921 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04922
04923 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04924 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04925 return -1;
04926 }
04927
04928 RETRIEVE(fn, -1, ext, context);
04929 if (ast_fileexists(fn, NULL, NULL) > 0) {
04930 res = ast_stream_and_wait(chan, fn, ecodes);
04931 if (res) {
04932 DISPOSE(fn, -1);
04933 return res;
04934 }
04935 } else {
04936
04937 DISPOSE(fn, -1);
04938 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04939 if (res)
04940 return res;
04941 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04942 if (res)
04943 return res;
04944 }
04945 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04946 return res;
04947 }
04948
04949 static void free_zone(struct vm_zone *z)
04950 {
04951 ast_free(z);
04952 }
04953
04954 #ifdef ODBC_STORAGE
04955 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04956 {
04957 int x = -1;
04958 int res;
04959 SQLHSTMT stmt = NULL;
04960 char sql[PATH_MAX];
04961 char rowdata[20];
04962 char tmp[PATH_MAX] = "";
04963 struct odbc_obj *obj = NULL;
04964 char *context;
04965 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04966
04967 if (newmsgs)
04968 *newmsgs = 0;
04969 if (oldmsgs)
04970 *oldmsgs = 0;
04971 if (urgentmsgs)
04972 *urgentmsgs = 0;
04973
04974
04975 if (ast_strlen_zero(mailbox))
04976 return 0;
04977
04978 ast_copy_string(tmp, mailbox, sizeof(tmp));
04979
04980 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
04981 int u, n, o;
04982 char *next, *remaining = tmp;
04983 while ((next = strsep(&remaining, " ,"))) {
04984 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
04985 return -1;
04986 }
04987 if (urgentmsgs) {
04988 *urgentmsgs += u;
04989 }
04990 if (newmsgs) {
04991 *newmsgs += n;
04992 }
04993 if (oldmsgs) {
04994 *oldmsgs += o;
04995 }
04996 }
04997 return 0;
04998 }
04999
05000 context = strchr(tmp, '@');
05001 if (context) {
05002 *context = '\0';
05003 context++;
05004 } else
05005 context = "default";
05006
05007 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05008 do {
05009 if (newmsgs) {
05010 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05011 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05012 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05013 break;
05014 }
05015 res = SQLFetch(stmt);
05016 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05017 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05018 break;
05019 }
05020 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05021 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05022 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05023 break;
05024 }
05025 *newmsgs = atoi(rowdata);
05026 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05027 }
05028
05029 if (oldmsgs) {
05030 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05031 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05032 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05033 break;
05034 }
05035 res = SQLFetch(stmt);
05036 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05037 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05038 break;
05039 }
05040 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05041 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05042 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05043 break;
05044 }
05045 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05046 *oldmsgs = atoi(rowdata);
05047 }
05048
05049 if (urgentmsgs) {
05050 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05051 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05052 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05053 break;
05054 }
05055 res = SQLFetch(stmt);
05056 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05057 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05058 break;
05059 }
05060 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05061 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05062 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05063 break;
05064 }
05065 *urgentmsgs = atoi(rowdata);
05066 }
05067
05068 x = 0;
05069 } while (0);
05070 } else {
05071 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05072 }
05073
05074 if (stmt) {
05075 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05076 }
05077 if (obj) {
05078 ast_odbc_release_obj(obj);
05079 }
05080
05081 return x;
05082 }
05083
05084
05085
05086
05087
05088
05089
05090
05091
05092
05093 static int messagecount(const char *context, const char *mailbox, const char *folder)
05094 {
05095 struct odbc_obj *obj = NULL;
05096 int nummsgs = 0;
05097 int res;
05098 SQLHSTMT stmt = NULL;
05099 char sql[PATH_MAX];
05100 char rowdata[20];
05101 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05102 if (!folder)
05103 folder = "INBOX";
05104
05105 if (ast_strlen_zero(mailbox))
05106 return 0;
05107
05108 obj = ast_odbc_request_obj(odbc_database, 0);
05109 if (obj) {
05110 if (!strcmp(folder, "INBOX")) {
05111 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);
05112 } else {
05113 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05114 }
05115 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05116 if (!stmt) {
05117 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05118 goto yuck;
05119 }
05120 res = SQLFetch(stmt);
05121 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05122 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05123 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05124 goto yuck;
05125 }
05126 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05127 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05128 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05129 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05130 goto yuck;
05131 }
05132 nummsgs = atoi(rowdata);
05133 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05134 } else
05135 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05136
05137 yuck:
05138 if (obj)
05139 ast_odbc_release_obj(obj);
05140 return nummsgs;
05141 }
05142
05143
05144
05145
05146
05147
05148
05149
05150
05151 static int has_voicemail(const char *mailbox, const char *folder)
05152 {
05153 char tmp[256], *tmp2 = tmp, *box, *context;
05154 ast_copy_string(tmp, mailbox, sizeof(tmp));
05155 while ((context = box = strsep(&tmp2, ",&"))) {
05156 strsep(&context, "@");
05157 if (ast_strlen_zero(context))
05158 context = "default";
05159 if (messagecount(context, box, folder))
05160 return 1;
05161 }
05162 return 0;
05163 }
05164 #endif
05165 #ifndef IMAP_STORAGE
05166
05167
05168
05169
05170
05171
05172
05173
05174
05175
05176
05177
05178
05179
05180
05181
05182 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)
05183 {
05184 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05185 const char *frombox = mbox(vmu, imbox);
05186 int recipmsgnum;
05187 int res = 0;
05188
05189 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05190
05191 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05192 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
05193 } else {
05194 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05195 }
05196
05197 if (!dir)
05198 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05199 else
05200 ast_copy_string(fromdir, dir, sizeof(fromdir));
05201
05202 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05203 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05204
05205 if (vm_lock_path(todir))
05206 return ERROR_LOCK_PATH;
05207
05208 recipmsgnum = last_message_index(recip, todir) + 1;
05209 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05210 make_file(topath, sizeof(topath), todir, recipmsgnum);
05211 #ifndef ODBC_STORAGE
05212 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05213 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05214 } else {
05215 #endif
05216
05217
05218
05219 copy_plain_file(frompath, topath);
05220 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05221 vm_delete(topath);
05222 #ifndef ODBC_STORAGE
05223 }
05224 #endif
05225 } else {
05226 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05227 res = -1;
05228 }
05229 ast_unlock_path(todir);
05230 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05231 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05232 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05233 flag);
05234
05235 return res;
05236 }
05237 #endif
05238 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05239
05240 static int messagecount(const char *context, const char *mailbox, const char *folder)
05241 {
05242 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05243 }
05244
05245 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05246 {
05247 DIR *dir;
05248 struct dirent *de;
05249 char fn[256];
05250 int ret = 0;
05251
05252
05253 if (ast_strlen_zero(mailbox))
05254 return 0;
05255
05256 if (ast_strlen_zero(folder))
05257 folder = "INBOX";
05258 if (ast_strlen_zero(context))
05259 context = "default";
05260
05261 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05262
05263 if (!(dir = opendir(fn)))
05264 return 0;
05265
05266 while ((de = readdir(dir))) {
05267 if (!strncasecmp(de->d_name, "msg", 3)) {
05268 if (shortcircuit) {
05269 ret = 1;
05270 break;
05271 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05272 ret++;
05273 }
05274 }
05275 }
05276
05277 closedir(dir);
05278
05279 return ret;
05280 }
05281
05282
05283
05284
05285
05286
05287
05288
05289
05290
05291 static int has_voicemail(const char *mailbox, const char *folder)
05292 {
05293 char tmp[256], *tmp2 = tmp, *box, *context;
05294 ast_copy_string(tmp, mailbox, sizeof(tmp));
05295 if (ast_strlen_zero(folder)) {
05296 folder = "INBOX";
05297 }
05298 while ((box = strsep(&tmp2, ",&"))) {
05299 if ((context = strchr(box, '@')))
05300 *context++ = '\0';
05301 else
05302 context = "default";
05303 if (__has_voicemail(context, box, folder, 1))
05304 return 1;
05305
05306 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05307 return 1;
05308 }
05309 }
05310 return 0;
05311 }
05312
05313
05314 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05315 {
05316 char tmp[256];
05317 char *context;
05318
05319
05320 if (ast_strlen_zero(mailbox))
05321 return 0;
05322
05323 if (newmsgs)
05324 *newmsgs = 0;
05325 if (oldmsgs)
05326 *oldmsgs = 0;
05327 if (urgentmsgs)
05328 *urgentmsgs = 0;
05329
05330 if (strchr(mailbox, ',')) {
05331 int tmpnew, tmpold, tmpurgent;
05332 char *mb, *cur;
05333
05334 ast_copy_string(tmp, mailbox, sizeof(tmp));
05335 mb = tmp;
05336 while ((cur = strsep(&mb, ", "))) {
05337 if (!ast_strlen_zero(cur)) {
05338 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05339 return -1;
05340 else {
05341 if (newmsgs)
05342 *newmsgs += tmpnew;
05343 if (oldmsgs)
05344 *oldmsgs += tmpold;
05345 if (urgentmsgs)
05346 *urgentmsgs += tmpurgent;
05347 }
05348 }
05349 }
05350 return 0;
05351 }
05352
05353 ast_copy_string(tmp, mailbox, sizeof(tmp));
05354
05355 if ((context = strchr(tmp, '@')))
05356 *context++ = '\0';
05357 else
05358 context = "default";
05359
05360 if (newmsgs)
05361 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05362 if (oldmsgs)
05363 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05364 if (urgentmsgs)
05365 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05366
05367 return 0;
05368 }
05369
05370 #endif
05371
05372
05373 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05374 {
05375 int urgentmsgs = 0;
05376 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05377 if (newmsgs) {
05378 *newmsgs += urgentmsgs;
05379 }
05380 return res;
05381 }
05382
05383 static void run_externnotify(char *context, char *extension, const char *flag)
05384 {
05385 char arguments[255];
05386 char ext_context[256] = "";
05387 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05388 struct ast_smdi_mwi_message *mwi_msg;
05389
05390 if (!ast_strlen_zero(context))
05391 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05392 else
05393 ast_copy_string(ext_context, extension, sizeof(ext_context));
05394
05395 if (smdi_iface) {
05396 if (ast_app_has_voicemail(ext_context, NULL))
05397 ast_smdi_mwi_set(smdi_iface, extension);
05398 else
05399 ast_smdi_mwi_unset(smdi_iface, extension);
05400
05401 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05402 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05403 if (!strncmp(mwi_msg->cause, "INV", 3))
05404 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05405 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05406 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05407 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05408 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05409 } else {
05410 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05411 }
05412 }
05413
05414 if (!ast_strlen_zero(externnotify)) {
05415 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05416 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05417 } else {
05418 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05419 ast_debug(1, "Executing %s\n", arguments);
05420 ast_safe_system(arguments);
05421 }
05422 }
05423 }
05424
05425
05426
05427
05428
05429
05430 struct leave_vm_options {
05431 unsigned int flags;
05432 signed char record_gain;
05433 char *exitcontext;
05434 };
05435
05436
05437
05438
05439
05440
05441
05442
05443
05444
05445
05446 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05447 {
05448 #ifdef IMAP_STORAGE
05449 int newmsgs, oldmsgs;
05450 #else
05451 char urgdir[PATH_MAX];
05452 #endif
05453 char txtfile[PATH_MAX];
05454 char tmptxtfile[PATH_MAX];
05455 struct vm_state *vms = NULL;
05456 char callerid[256];
05457 FILE *txt;
05458 char date[256];
05459 int txtdes;
05460 int res = 0;
05461 int msgnum;
05462 int duration = 0;
05463 int ausemacro = 0;
05464 int ousemacro = 0;
05465 int ouseexten = 0;
05466 char tmpdur[16];
05467 char priority[16];
05468 char origtime[16];
05469 char dir[PATH_MAX];
05470 char tmpdir[PATH_MAX];
05471 char fn[PATH_MAX];
05472 char prefile[PATH_MAX] = "";
05473 char tempfile[PATH_MAX] = "";
05474 char ext_context[256] = "";
05475 char fmt[80];
05476 char *context;
05477 char ecodes[17] = "#";
05478 struct ast_str *tmp = ast_str_create(16);
05479 char *tmpptr;
05480 struct ast_vm_user *vmu;
05481 struct ast_vm_user svm;
05482 const char *category = NULL;
05483 const char *code;
05484 const char *alldtmf = "0123456789ABCD*#";
05485 char flag[80];
05486
05487 if (!tmp) {
05488 return -1;
05489 }
05490
05491 ast_str_set(&tmp, 0, "%s", ext);
05492 ext = ast_str_buffer(tmp);
05493 if ((context = strchr(ext, '@'))) {
05494 *context++ = '\0';
05495 tmpptr = strchr(context, '&');
05496 } else {
05497 tmpptr = strchr(ext, '&');
05498 }
05499
05500 if (tmpptr)
05501 *tmpptr++ = '\0';
05502
05503 ast_channel_lock(chan);
05504 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05505 category = ast_strdupa(category);
05506 }
05507 ast_channel_unlock(chan);
05508
05509 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05510 ast_copy_string(flag, "Urgent", sizeof(flag));
05511 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05512 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05513 } else {
05514 flag[0] = '\0';
05515 }
05516
05517 ast_debug(3, "Before find_user\n");
05518 if (!(vmu = find_user(&svm, context, ext))) {
05519 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05520 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05521 ast_free(tmp);
05522 return res;
05523 }
05524
05525 if (strcmp(vmu->context, "default"))
05526 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05527 else
05528 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05529
05530
05531
05532
05533
05534
05535 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05536 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05537 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05538 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05539 }
05540
05541
05542
05543
05544 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05545 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05546 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05547 ast_free(tmp);
05548 return -1;
05549 }
05550 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05551 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05552 ast_copy_string(prefile, tempfile, sizeof(prefile));
05553
05554 DISPOSE(tempfile, -1);
05555
05556 #ifndef IMAP_STORAGE
05557 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05558 #else
05559 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05560 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05561 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05562 }
05563 #endif
05564
05565
05566 if (ast_test_flag(vmu, VM_OPERATOR)) {
05567 if (!ast_strlen_zero(vmu->exit)) {
05568 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05569 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05570 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05571 ouseexten = 1;
05572 }
05573 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05574 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05575 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05576 ouseexten = 1;
05577 } else if (!ast_strlen_zero(chan->macrocontext)
05578 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05579 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05580 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05581 ousemacro = 1;
05582 }
05583 }
05584
05585 if (!ast_strlen_zero(vmu->exit)) {
05586 if (ast_exists_extension(chan, vmu->exit, "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 }
05590 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05591 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05592 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05593 } else if (!ast_strlen_zero(chan->macrocontext)
05594 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05595 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05596 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05597 ausemacro = 1;
05598 }
05599
05600 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05601 for (code = alldtmf; *code; code++) {
05602 char e[2] = "";
05603 e[0] = *code;
05604 if (strchr(ecodes, e[0]) == NULL
05605 && ast_canmatch_extension(chan, chan->context, e, 1,
05606 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05607 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05608 }
05609 }
05610 }
05611
05612
05613 if (!ast_strlen_zero(prefile)) {
05614 #ifdef ODBC_STORAGE
05615 int success =
05616 #endif
05617 RETRIEVE(prefile, -1, ext, context);
05618 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05619 if (ast_streamfile(chan, prefile, chan->language) > -1)
05620 res = ast_waitstream(chan, ecodes);
05621 #ifdef ODBC_STORAGE
05622 if (success == -1) {
05623
05624 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05625 store_file(prefile, vmu->mailbox, vmu->context, -1);
05626 }
05627 #endif
05628 } else {
05629 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05630 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05631 }
05632 DISPOSE(prefile, -1);
05633 if (res < 0) {
05634 ast_debug(1, "Hang up during prefile playback\n");
05635 free_user(vmu);
05636 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05637 ast_free(tmp);
05638 return -1;
05639 }
05640 }
05641 if (res == '#') {
05642
05643 ast_set_flag(options, OPT_SILENT);
05644 res = 0;
05645 }
05646
05647 if (vmu->maxmsg == 0) {
05648 if (option_debug > 2)
05649 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05650 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05651 goto leave_vm_out;
05652 }
05653 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05654 res = ast_stream_and_wait(chan, INTRO, ecodes);
05655 if (res == '#') {
05656 ast_set_flag(options, OPT_SILENT);
05657 res = 0;
05658 }
05659 }
05660 if (res > 0)
05661 ast_stopstream(chan);
05662
05663
05664 if (res == '*') {
05665 chan->exten[0] = 'a';
05666 chan->exten[1] = '\0';
05667 if (!ast_strlen_zero(vmu->exit)) {
05668 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05669 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05670 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05671 }
05672 chan->priority = 0;
05673 free_user(vmu);
05674 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05675 ast_free(tmp);
05676 return 0;
05677 }
05678
05679
05680 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05681 transfer:
05682 if (ouseexten || ousemacro) {
05683 chan->exten[0] = 'o';
05684 chan->exten[1] = '\0';
05685 if (!ast_strlen_zero(vmu->exit)) {
05686 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05687 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05688 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05689 }
05690 ast_play_and_wait(chan, "transfer");
05691 chan->priority = 0;
05692 free_user(vmu);
05693 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05694 }
05695 ast_free(tmp);
05696 return OPERATOR_EXIT;
05697 }
05698
05699
05700 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05701 if (!ast_strlen_zero(options->exitcontext))
05702 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05703 free_user(vmu);
05704 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05705 ast_free(tmp);
05706 return res;
05707 }
05708
05709 if (res < 0) {
05710 free_user(vmu);
05711 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05712 ast_free(tmp);
05713 return -1;
05714 }
05715
05716 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05717 if (!ast_strlen_zero(fmt)) {
05718 msgnum = 0;
05719
05720 #ifdef IMAP_STORAGE
05721
05722
05723 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05724 if (res < 0) {
05725 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05726 ast_free(tmp);
05727 return -1;
05728 }
05729 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05730
05731
05732
05733
05734 if (!(vms = create_vm_state_from_user(vmu))) {
05735 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05736 ast_free(tmp);
05737 return -1;
05738 }
05739 }
05740 vms->newmessages++;
05741
05742
05743 msgnum = newmsgs + oldmsgs;
05744 ast_debug(3, "Messagecount set to %d\n", msgnum);
05745 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05746
05747 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05748
05749 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05750 goto leave_vm_out;
05751 }
05752 #else
05753 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05754 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05755 if (!res)
05756 res = ast_waitstream(chan, "");
05757 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05758 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05759 inprocess_count(vmu->mailbox, vmu->context, -1);
05760 goto leave_vm_out;
05761 }
05762
05763 #endif
05764 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05765 txtdes = mkstemp(tmptxtfile);
05766 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05767 if (txtdes < 0) {
05768 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05769 if (!res)
05770 res = ast_waitstream(chan, "");
05771 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05772 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05773 inprocess_count(vmu->mailbox, vmu->context, -1);
05774 goto leave_vm_out;
05775 }
05776
05777
05778 if (res >= 0) {
05779
05780 res = ast_stream_and_wait(chan, "beep", "");
05781 }
05782
05783
05784 if (ast_check_realtime("voicemail_data")) {
05785 snprintf(priority, sizeof(priority), "%d", chan->priority);
05786 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05787 get_date(date, sizeof(date));
05788 ast_callerid_merge(callerid, sizeof(callerid),
05789 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05790 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05791 "Unknown");
05792 ast_store_realtime("voicemail_data",
05793 "origmailbox", ext,
05794 "context", chan->context,
05795 "macrocontext", chan->macrocontext,
05796 "exten", chan->exten,
05797 "priority", priority,
05798 "callerchan", chan->name,
05799 "callerid", callerid,
05800 "origdate", date,
05801 "origtime", origtime,
05802 "category", S_OR(category, ""),
05803 "filename", tmptxtfile,
05804 SENTINEL);
05805 }
05806
05807
05808 txt = fdopen(txtdes, "w+");
05809 if (txt) {
05810 get_date(date, sizeof(date));
05811 ast_callerid_merge(callerid, sizeof(callerid),
05812 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05813 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05814 "Unknown");
05815 fprintf(txt,
05816 ";\n"
05817 "; Message Information file\n"
05818 ";\n"
05819 "[message]\n"
05820 "origmailbox=%s\n"
05821 "context=%s\n"
05822 "macrocontext=%s\n"
05823 "exten=%s\n"
05824 "rdnis=%s\n"
05825 "priority=%d\n"
05826 "callerchan=%s\n"
05827 "callerid=%s\n"
05828 "origdate=%s\n"
05829 "origtime=%ld\n"
05830 "category=%s\n",
05831 ext,
05832 chan->context,
05833 chan->macrocontext,
05834 chan->exten,
05835 S_COR(chan->redirecting.from.number.valid,
05836 chan->redirecting.from.number.str, "unknown"),
05837 chan->priority,
05838 chan->name,
05839 callerid,
05840 date, (long) time(NULL),
05841 category ? category : "");
05842 } else {
05843 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05844 inprocess_count(vmu->mailbox, vmu->context, -1);
05845 if (ast_check_realtime("voicemail_data")) {
05846 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05847 }
05848 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05849 goto leave_vm_out;
05850 }
05851 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05852
05853 if (txt) {
05854 fprintf(txt, "flag=%s\n", flag);
05855 if (duration < vmu->minsecs) {
05856 fclose(txt);
05857 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmu->minsecs);
05858 ast_filedelete(tmptxtfile, NULL);
05859 unlink(tmptxtfile);
05860 if (ast_check_realtime("voicemail_data")) {
05861 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05862 }
05863 inprocess_count(vmu->mailbox, vmu->context, -1);
05864 } else {
05865 fprintf(txt, "duration=%d\n", duration);
05866 fclose(txt);
05867 if (vm_lock_path(dir)) {
05868 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05869
05870 ast_filedelete(tmptxtfile, NULL);
05871 unlink(tmptxtfile);
05872 inprocess_count(vmu->mailbox, vmu->context, -1);
05873 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05874 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05875 unlink(tmptxtfile);
05876 ast_unlock_path(dir);
05877 inprocess_count(vmu->mailbox, vmu->context, -1);
05878 if (ast_check_realtime("voicemail_data")) {
05879 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05880 }
05881 } else {
05882 #ifndef IMAP_STORAGE
05883 msgnum = last_message_index(vmu, dir) + 1;
05884 #endif
05885 make_file(fn, sizeof(fn), dir, msgnum);
05886
05887
05888 #ifndef IMAP_STORAGE
05889 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05890 #else
05891 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05892 #endif
05893
05894 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05895 ast_filerename(tmptxtfile, fn, NULL);
05896 rename(tmptxtfile, txtfile);
05897 inprocess_count(vmu->mailbox, vmu->context, -1);
05898
05899
05900
05901 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05902 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05903
05904 ast_unlock_path(dir);
05905 if (ast_check_realtime("voicemail_data")) {
05906 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05907 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
05908 }
05909
05910
05911
05912 if (ast_fileexists(fn, NULL, NULL) > 0) {
05913 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05914 }
05915
05916
05917 while (tmpptr) {
05918 struct ast_vm_user recipu, *recip;
05919 char *exten, *cntx;
05920
05921 exten = strsep(&tmpptr, "&");
05922 cntx = strchr(exten, '@');
05923 if (cntx) {
05924 *cntx = '\0';
05925 cntx++;
05926 }
05927 if ((recip = find_user(&recipu, cntx, exten))) {
05928 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05929 free_user(recip);
05930 }
05931 }
05932 #ifndef IMAP_STORAGE
05933 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05934
05935 char sfn[PATH_MAX];
05936 char dfn[PATH_MAX];
05937 int x;
05938
05939 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05940 x = last_message_index(vmu, urgdir) + 1;
05941 make_file(sfn, sizeof(sfn), dir, msgnum);
05942 make_file(dfn, sizeof(dfn), urgdir, x);
05943 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
05944 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05945
05946 ast_copy_string(fn, dfn, sizeof(fn));
05947 msgnum = x;
05948 }
05949 #endif
05950
05951 if (ast_fileexists(fn, NULL, NULL)) {
05952 #ifdef IMAP_STORAGE
05953 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
05954 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05955 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05956 flag);
05957 #else
05958 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
05959 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05960 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05961 flag);
05962 #endif
05963 }
05964
05965
05966 if (ast_fileexists(fn, NULL, NULL)) {
05967 DISPOSE(dir, msgnum);
05968 }
05969 }
05970 }
05971 } else {
05972 inprocess_count(vmu->mailbox, vmu->context, -1);
05973 }
05974 if (res == '0') {
05975 goto transfer;
05976 } else if (res > 0 && res != 't')
05977 res = 0;
05978
05979 if (duration < vmu->minsecs)
05980
05981 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05982 else
05983 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05984 } else
05985 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
05986 leave_vm_out:
05987 free_user(vmu);
05988
05989 #ifdef IMAP_STORAGE
05990
05991 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
05992 if (expungeonhangup == 1) {
05993 ast_mutex_lock(&vms->lock);
05994 #ifdef HAVE_IMAP_TK2006
05995 if (LEVELUIDPLUS (vms->mailstream)) {
05996 mail_expunge_full(vms->mailstream, NIL, EX_UID);
05997 } else
05998 #endif
05999 mail_expunge(vms->mailstream);
06000 ast_mutex_unlock(&vms->lock);
06001 }
06002 #endif
06003
06004 ast_free(tmp);
06005 return res;
06006 }
06007
06008 #if !defined(IMAP_STORAGE) && !defined(ODBC_STORAGE)
06009 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06010 {
06011
06012
06013 int x, dest;
06014 char sfn[PATH_MAX];
06015 char dfn[PATH_MAX];
06016
06017 if (vm_lock_path(dir))
06018 return ERROR_LOCK_PATH;
06019
06020 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06021 make_file(sfn, sizeof(sfn), dir, x);
06022 if (EXISTS(dir, x, sfn, NULL)) {
06023
06024 if (x != dest) {
06025 make_file(dfn, sizeof(dfn), dir, dest);
06026 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06027 }
06028
06029 dest++;
06030 }
06031 }
06032 ast_unlock_path(dir);
06033
06034 return dest;
06035 }
06036 #endif
06037
06038 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06039 {
06040 int d;
06041 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06042 return d;
06043 }
06044
06045 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06046 {
06047 #ifdef IMAP_STORAGE
06048
06049
06050 char sequence[10];
06051 char mailbox[256];
06052 int res;
06053
06054
06055 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06056
06057 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06058 ast_mutex_lock(&vms->lock);
06059
06060 if (box == OLD_FOLDER) {
06061 mail_setflag(vms->mailstream, sequence, "\\Seen");
06062 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06063 } else if (box == NEW_FOLDER) {
06064 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06065 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06066 }
06067 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06068 ast_mutex_unlock(&vms->lock);
06069 return 0;
06070 }
06071
06072 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06073 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06074 if (mail_create(vms->mailstream, mailbox) == NIL)
06075 ast_debug(5, "Folder exists.\n");
06076 else
06077 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06078 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06079 ast_mutex_unlock(&vms->lock);
06080 return res;
06081 #else
06082 char *dir = vms->curdir;
06083 char *username = vms->username;
06084 char *context = vmu->context;
06085 char sfn[PATH_MAX];
06086 char dfn[PATH_MAX];
06087 char ddir[PATH_MAX];
06088 const char *dbox = mbox(vmu, box);
06089 int x, i;
06090 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06091
06092 if (vm_lock_path(ddir))
06093 return ERROR_LOCK_PATH;
06094
06095 x = last_message_index(vmu, ddir) + 1;
06096
06097 if (box == 10 && x >= vmu->maxdeletedmsg) {
06098 x--;
06099 for (i = 1; i <= x; i++) {
06100
06101 make_file(sfn, sizeof(sfn), ddir, i);
06102 make_file(dfn, sizeof(dfn), ddir, i - 1);
06103 if (EXISTS(ddir, i, sfn, NULL)) {
06104 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06105 } else
06106 break;
06107 }
06108 } else {
06109 if (x >= vmu->maxmsg) {
06110 ast_unlock_path(ddir);
06111 return -1;
06112 }
06113 }
06114 make_file(sfn, sizeof(sfn), dir, msg);
06115 make_file(dfn, sizeof(dfn), ddir, x);
06116 if (strcmp(sfn, dfn)) {
06117 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06118 }
06119 ast_unlock_path(ddir);
06120 #endif
06121 return 0;
06122 }
06123
06124 static int adsi_logo(unsigned char *buf)
06125 {
06126 int bytes = 0;
06127 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06128 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06129 return bytes;
06130 }
06131
06132 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06133 {
06134 unsigned char buf[256];
06135 int bytes = 0;
06136 int x;
06137 char num[5];
06138
06139 *useadsi = 0;
06140 bytes += ast_adsi_data_mode(buf + bytes);
06141 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06142
06143 bytes = 0;
06144 bytes += adsi_logo(buf);
06145 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06146 #ifdef DISPLAY
06147 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06148 #endif
06149 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06150 bytes += ast_adsi_data_mode(buf + bytes);
06151 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06152
06153 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06154 bytes = 0;
06155 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06156 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06157 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06158 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06159 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06160 return 0;
06161 }
06162
06163 #ifdef DISPLAY
06164
06165 bytes = 0;
06166 bytes += ast_adsi_logo(buf);
06167 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06168 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06169 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06170 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06171 #endif
06172 bytes = 0;
06173 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06174 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06175 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06176 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06177 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06178 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06179 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06180
06181 #ifdef DISPLAY
06182
06183 bytes = 0;
06184 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06185 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06186
06187 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06188 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06189 #endif
06190
06191 bytes = 0;
06192
06193 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06194 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06195 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06196 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06197 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06198 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06199 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06200
06201 #ifdef DISPLAY
06202
06203 bytes = 0;
06204 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06205 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06206 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06207 #endif
06208
06209 bytes = 0;
06210 for (x = 0; x < 5; x++) {
06211 snprintf(num, sizeof(num), "%d", x);
06212 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06213 }
06214 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06215 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06216
06217 #ifdef DISPLAY
06218
06219 bytes = 0;
06220 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06221 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06222 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06223 #endif
06224
06225 if (ast_adsi_end_download(chan)) {
06226 bytes = 0;
06227 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06228 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06229 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06230 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06231 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06232 return 0;
06233 }
06234 bytes = 0;
06235 bytes += ast_adsi_download_disconnect(buf + bytes);
06236 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06237 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06238
06239 ast_debug(1, "Done downloading scripts...\n");
06240
06241 #ifdef DISPLAY
06242
06243 bytes = 0;
06244 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06245 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06246 #endif
06247 ast_debug(1, "Restarting session...\n");
06248
06249 bytes = 0;
06250
06251 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06252 *useadsi = 1;
06253 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06254 } else
06255 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06256
06257 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06258 return 0;
06259 }
06260
06261 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06262 {
06263 int x;
06264 if (!ast_adsi_available(chan))
06265 return;
06266 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06267 if (x < 0)
06268 return;
06269 if (!x) {
06270 if (adsi_load_vmail(chan, useadsi)) {
06271 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06272 return;
06273 }
06274 } else
06275 *useadsi = 1;
06276 }
06277
06278 static void adsi_login(struct ast_channel *chan)
06279 {
06280 unsigned char buf[256];
06281 int bytes = 0;
06282 unsigned char keys[8];
06283 int x;
06284 if (!ast_adsi_available(chan))
06285 return;
06286
06287 for (x = 0; x < 8; x++)
06288 keys[x] = 0;
06289
06290 keys[3] = ADSI_KEY_APPS + 3;
06291
06292 bytes += adsi_logo(buf + bytes);
06293 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06294 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06295 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06296 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06297 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06298 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06299 bytes += ast_adsi_set_keys(buf + bytes, keys);
06300 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06301 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06302 }
06303
06304 static void adsi_password(struct ast_channel *chan)
06305 {
06306 unsigned char buf[256];
06307 int bytes = 0;
06308 unsigned char keys[8];
06309 int x;
06310 if (!ast_adsi_available(chan))
06311 return;
06312
06313 for (x = 0; x < 8; x++)
06314 keys[x] = 0;
06315
06316 keys[3] = ADSI_KEY_APPS + 3;
06317
06318 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06319 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06320 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06321 bytes += ast_adsi_set_keys(buf + bytes, keys);
06322 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06323 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06324 }
06325
06326 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06327 {
06328 unsigned char buf[256];
06329 int bytes = 0;
06330 unsigned char keys[8];
06331 int x, y;
06332
06333 if (!ast_adsi_available(chan))
06334 return;
06335
06336 for (x = 0; x < 5; x++) {
06337 y = ADSI_KEY_APPS + 12 + start + x;
06338 if (y > ADSI_KEY_APPS + 12 + 4)
06339 y = 0;
06340 keys[x] = ADSI_KEY_SKT | y;
06341 }
06342 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06343 keys[6] = 0;
06344 keys[7] = 0;
06345
06346 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06347 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06348 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06349 bytes += ast_adsi_set_keys(buf + bytes, keys);
06350 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06351
06352 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06353 }
06354
06355 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06356 {
06357 int bytes = 0;
06358 unsigned char buf[256];
06359 char buf1[256], buf2[256];
06360 char fn2[PATH_MAX];
06361
06362 char cid[256] = "";
06363 char *val;
06364 char *name, *num;
06365 char datetime[21] = "";
06366 FILE *f;
06367
06368 unsigned char keys[8];
06369
06370 int x;
06371
06372 if (!ast_adsi_available(chan))
06373 return;
06374
06375
06376 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06377 f = fopen(fn2, "r");
06378 if (f) {
06379 while (!feof(f)) {
06380 if (!fgets((char *) buf, sizeof(buf), f)) {
06381 continue;
06382 }
06383 if (!feof(f)) {
06384 char *stringp = NULL;
06385 stringp = (char *) buf;
06386 strsep(&stringp, "=");
06387 val = strsep(&stringp, "=");
06388 if (!ast_strlen_zero(val)) {
06389 if (!strcmp((char *) buf, "callerid"))
06390 ast_copy_string(cid, val, sizeof(cid));
06391 if (!strcmp((char *) buf, "origdate"))
06392 ast_copy_string(datetime, val, sizeof(datetime));
06393 }
06394 }
06395 }
06396 fclose(f);
06397 }
06398
06399 for (x = 0; x < 5; x++)
06400 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06401 keys[6] = 0x0;
06402 keys[7] = 0x0;
06403
06404 if (!vms->curmsg) {
06405
06406 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06407 }
06408 if (vms->curmsg >= vms->lastmsg) {
06409
06410 if (vms->curmsg) {
06411
06412 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06413 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06414
06415 } else {
06416
06417 keys[3] = 1;
06418 }
06419 }
06420
06421 if (!ast_strlen_zero(cid)) {
06422 ast_callerid_parse(cid, &name, &num);
06423 if (!name)
06424 name = num;
06425 } else
06426 name = "Unknown Caller";
06427
06428
06429
06430 if (vms->deleted[vms->curmsg])
06431 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06432
06433
06434 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06435 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06436 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06437 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06438
06439 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06440 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06441 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06442 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06443 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06444 bytes += ast_adsi_set_keys(buf + bytes, keys);
06445 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06446
06447 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06448 }
06449
06450 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06451 {
06452 int bytes = 0;
06453 unsigned char buf[256];
06454 unsigned char keys[8];
06455
06456 int x;
06457
06458 if (!ast_adsi_available(chan))
06459 return;
06460
06461
06462 for (x = 0; x < 5; x++)
06463 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06464
06465 keys[6] = 0x0;
06466 keys[7] = 0x0;
06467
06468 if (!vms->curmsg) {
06469
06470 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06471 }
06472 if (vms->curmsg >= vms->lastmsg) {
06473
06474 if (vms->curmsg) {
06475
06476 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06477 } else {
06478
06479 keys[3] = 1;
06480 }
06481 }
06482
06483
06484 if (vms->deleted[vms->curmsg])
06485 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06486
06487
06488 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06489 bytes += ast_adsi_set_keys(buf + bytes, keys);
06490 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06491
06492 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06493 }
06494
06495 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06496 {
06497 unsigned char buf[256] = "";
06498 char buf1[256] = "", buf2[256] = "";
06499 int bytes = 0;
06500 unsigned char keys[8];
06501 int x;
06502
06503 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06504 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06505 if (!ast_adsi_available(chan))
06506 return;
06507 if (vms->newmessages) {
06508 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06509 if (vms->oldmessages) {
06510 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06511 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06512 } else {
06513 snprintf(buf2, sizeof(buf2), "%s.", newm);
06514 }
06515 } else if (vms->oldmessages) {
06516 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06517 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06518 } else {
06519 strcpy(buf1, "You have no messages.");
06520 buf2[0] = ' ';
06521 buf2[1] = '\0';
06522 }
06523 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06524 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06525 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06526
06527 for (x = 0; x < 6; x++)
06528 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06529 keys[6] = 0;
06530 keys[7] = 0;
06531
06532
06533 if (vms->lastmsg < 0)
06534 keys[0] = 1;
06535 bytes += ast_adsi_set_keys(buf + bytes, keys);
06536
06537 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06538
06539 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06540 }
06541
06542 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06543 {
06544 unsigned char buf[256] = "";
06545 char buf1[256] = "", buf2[256] = "";
06546 int bytes = 0;
06547 unsigned char keys[8];
06548 int x;
06549
06550 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06551
06552 if (!ast_adsi_available(chan))
06553 return;
06554
06555
06556 for (x = 0; x < 6; x++)
06557 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06558
06559 keys[6] = 0;
06560 keys[7] = 0;
06561
06562 if ((vms->lastmsg + 1) < 1)
06563 keys[0] = 0;
06564
06565 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06566 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06567
06568 if (vms->lastmsg + 1)
06569 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06570 else
06571 strcpy(buf2, "no messages.");
06572 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06573 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06574 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06575 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06576 bytes += ast_adsi_set_keys(buf + bytes, keys);
06577
06578 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06579
06580 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06581
06582 }
06583
06584
06585
06586
06587
06588
06589
06590
06591
06592
06593
06594
06595
06596
06597
06598 static void adsi_goodbye(struct ast_channel *chan)
06599 {
06600 unsigned char buf[256];
06601 int bytes = 0;
06602
06603 if (!ast_adsi_available(chan))
06604 return;
06605 bytes += adsi_logo(buf + bytes);
06606 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06607 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06608 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06609 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06610
06611 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06612 }
06613
06614
06615
06616
06617
06618 static int get_folder(struct ast_channel *chan, int start)
06619 {
06620 int x;
06621 int d;
06622 char fn[PATH_MAX];
06623 d = ast_play_and_wait(chan, "vm-press");
06624 if (d)
06625 return d;
06626 for (x = start; x < 5; x++) {
06627 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06628 return d;
06629 d = ast_play_and_wait(chan, "vm-for");
06630 if (d)
06631 return d;
06632 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06633 d = vm_play_folder_name(chan, fn);
06634 if (d)
06635 return d;
06636 d = ast_waitfordigit(chan, 500);
06637 if (d)
06638 return d;
06639 }
06640 d = ast_play_and_wait(chan, "vm-tocancel");
06641 if (d)
06642 return d;
06643 d = ast_waitfordigit(chan, 4000);
06644 return d;
06645 }
06646
06647
06648
06649
06650
06651
06652
06653
06654
06655
06656
06657
06658
06659 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06660 {
06661 int res = 0;
06662 int loops = 0;
06663 res = ast_play_and_wait(chan, fn);
06664 while (((res < '0') || (res > '9')) &&
06665 (res != '#') && (res >= 0) &&
06666 loops < 4) {
06667 res = get_folder(chan, 0);
06668 loops++;
06669 }
06670 if (loops == 4) {
06671 return '#';
06672 }
06673 return res;
06674 }
06675
06676
06677
06678
06679
06680
06681
06682
06683
06684
06685
06686
06687
06688
06689
06690
06691
06692
06693
06694 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06695 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06696 {
06697 #ifdef IMAP_STORAGE
06698 int res;
06699 #endif
06700 int cmd = 0;
06701 int retries = 0, prepend_duration = 0, already_recorded = 0;
06702 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06703 char textfile[PATH_MAX];
06704 struct ast_config *msg_cfg;
06705 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06706 #ifndef IMAP_STORAGE
06707 signed char zero_gain = 0;
06708 #endif
06709 const char *duration_str;
06710
06711
06712 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06713 strcpy(textfile, msgfile);
06714 strcpy(backup, msgfile);
06715 strcpy(backup_textfile, msgfile);
06716 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06717 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06718 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06719
06720 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06721 *duration = atoi(duration_str);
06722 } else {
06723 *duration = 0;
06724 }
06725
06726 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06727 if (cmd)
06728 retries = 0;
06729 switch (cmd) {
06730 case '1':
06731
06732 #ifdef IMAP_STORAGE
06733
06734 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06735 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06736 res = ast_play_and_wait(chan, INTRO);
06737 res = ast_play_and_wait(chan, "beep");
06738 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, record_gain, vms, flag);
06739 cmd = 't';
06740 #else
06741
06742
06743
06744 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06745 strcpy(textfile, msgfile);
06746 strncat(textfile, ".txt", sizeof(textfile) - 1);
06747 *duration = 0;
06748
06749
06750 if (!msg_cfg) {
06751 cmd = 0;
06752 break;
06753 }
06754
06755
06756 #ifndef IMAP_STORAGE
06757 if (already_recorded) {
06758 ast_filecopy(backup, msgfile, NULL);
06759 copy(backup_textfile, textfile);
06760 }
06761 else {
06762 ast_filecopy(msgfile, backup, NULL);
06763 copy(textfile, backup_textfile);
06764 }
06765 #endif
06766 already_recorded = 1;
06767
06768 if (record_gain)
06769 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06770
06771 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06772 if (cmd == 'S') {
06773 ast_filerename(backup, msgfile, NULL);
06774 }
06775
06776 if (record_gain)
06777 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06778
06779
06780 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06781 *duration = atoi(duration_str);
06782
06783 if (prepend_duration) {
06784 struct ast_category *msg_cat;
06785
06786 char duration_buf[12];
06787
06788 *duration += prepend_duration;
06789 msg_cat = ast_category_get(msg_cfg, "message");
06790 snprintf(duration_buf, 11, "%ld", *duration);
06791 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06792 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06793 }
06794 }
06795
06796 #endif
06797 break;
06798 case '2':
06799
06800 #ifdef IMAP_STORAGE
06801 *vms->introfn = '\0';
06802 #endif
06803 cmd = 't';
06804 break;
06805 case '*':
06806 cmd = '*';
06807 break;
06808 default:
06809 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06810
06811 if (!cmd)
06812 cmd = ast_play_and_wait(chan, "vm-starmain");
06813
06814 if (!cmd)
06815 cmd = ast_waitfordigit(chan, 6000);
06816 if (!cmd)
06817 retries++;
06818 if (retries > 3)
06819 cmd = 't';
06820 }
06821 }
06822
06823 if (msg_cfg)
06824 ast_config_destroy(msg_cfg);
06825 if (prepend_duration)
06826 *duration = prepend_duration;
06827
06828 if (already_recorded && cmd == -1) {
06829
06830 ast_filerename(backup, msgfile, NULL);
06831 rename(backup_textfile, textfile);
06832 }
06833
06834 if (cmd == 't' || cmd == 'S')
06835 cmd = 0;
06836 return cmd;
06837 }
06838
06839 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06840 {
06841 struct ast_event *event;
06842 char *mailbox, *context;
06843
06844
06845 context = mailbox = ast_strdupa(box);
06846 strsep(&context, "@");
06847 if (ast_strlen_zero(context))
06848 context = "default";
06849
06850 if (!(event = ast_event_new(AST_EVENT_MWI,
06851 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06852 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06853 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06854 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06855 AST_EVENT_IE_END))) {
06856 return;
06857 }
06858
06859 ast_event_queue_and_cache(event);
06860 }
06861
06862
06863
06864
06865
06866
06867
06868
06869
06870
06871
06872
06873
06874
06875
06876 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)
06877 {
06878 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06879 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06880 const char *category;
06881 char *myserveremail = serveremail;
06882
06883 ast_channel_lock(chan);
06884 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06885 category = ast_strdupa(category);
06886 }
06887 ast_channel_unlock(chan);
06888
06889 #ifndef IMAP_STORAGE
06890 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
06891 #else
06892 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
06893 #endif
06894 make_file(fn, sizeof(fn), todir, msgnum);
06895 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06896
06897 if (!ast_strlen_zero(vmu->attachfmt)) {
06898 if (strstr(fmt, vmu->attachfmt))
06899 fmt = vmu->attachfmt;
06900 else
06901 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);
06902 }
06903
06904
06905 fmt = ast_strdupa(fmt);
06906 stringp = fmt;
06907 strsep(&stringp, "|");
06908
06909 if (!ast_strlen_zero(vmu->serveremail))
06910 myserveremail = vmu->serveremail;
06911
06912 if (!ast_strlen_zero(vmu->email)) {
06913 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
06914
06915 if (attach_user_voicemail)
06916 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
06917
06918
06919 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
06920
06921 if (attach_user_voicemail)
06922 DISPOSE(todir, msgnum);
06923 }
06924
06925 if (!ast_strlen_zero(vmu->pager)) {
06926 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
06927 }
06928
06929 if (ast_test_flag(vmu, VM_DELETE))
06930 DELETE(todir, msgnum, fn, vmu);
06931
06932
06933 if (ast_app_has_voicemail(ext_context, NULL))
06934 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
06935
06936 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
06937
06938 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);
06939 run_externnotify(vmu->context, vmu->mailbox, flag);
06940
06941 #ifdef IMAP_STORAGE
06942 vm_delete(fn);
06943 if (ast_test_flag(vmu, VM_DELETE)) {
06944 vm_imap_delete(NULL, vms->curmsg, vmu);
06945 vms->newmessages--;
06946 }
06947 #endif
06948
06949 return 0;
06950 }
06951
06952
06953
06954
06955
06956
06957
06958
06959
06960
06961
06962
06963
06964
06965
06966
06967
06968
06969
06970
06971
06972
06973
06974
06975
06976
06977
06978
06979 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)
06980 {
06981 #ifdef IMAP_STORAGE
06982 int todircount = 0;
06983 struct vm_state *dstvms;
06984 #endif
06985 char username[70]="";
06986 char fn[PATH_MAX];
06987 char ecodes[16] = "#";
06988 int res = 0, cmd = 0;
06989 struct ast_vm_user *receiver = NULL, *vmtmp;
06990 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06991 char *stringp;
06992 const char *s;
06993 int saved_messages = 0;
06994 int valid_extensions = 0;
06995 char *dir;
06996 int curmsg;
06997 char urgent_str[7] = "";
06998 char tmptxtfile[PATH_MAX];
06999 int prompt_played = 0;
07000 #ifndef IMAP_STORAGE
07001 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07002 #endif
07003 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07004 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07005 }
07006
07007 if (vms == NULL) return -1;
07008 dir = vms->curdir;
07009 curmsg = vms->curmsg;
07010
07011 tmptxtfile[0] = '\0';
07012 while (!res && !valid_extensions) {
07013 int use_directory = 0;
07014 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07015 int done = 0;
07016 int retries = 0;
07017 cmd = 0;
07018 while ((cmd >= 0) && !done ){
07019 if (cmd)
07020 retries = 0;
07021 switch (cmd) {
07022 case '1':
07023 use_directory = 0;
07024 done = 1;
07025 break;
07026 case '2':
07027 use_directory = 1;
07028 done = 1;
07029 break;
07030 case '*':
07031 cmd = 't';
07032 done = 1;
07033 break;
07034 default:
07035
07036 cmd = ast_play_and_wait(chan, "vm-forward");
07037 if (!cmd)
07038 cmd = ast_waitfordigit(chan, 3000);
07039 if (!cmd)
07040 retries++;
07041 if (retries > 3) {
07042 cmd = 't';
07043 done = 1;
07044 }
07045
07046 }
07047 }
07048 if (cmd < 0 || cmd == 't')
07049 break;
07050 }
07051
07052 if (use_directory) {
07053
07054
07055 char old_context[sizeof(chan->context)];
07056 char old_exten[sizeof(chan->exten)];
07057 int old_priority;
07058 struct ast_app* directory_app;
07059
07060 directory_app = pbx_findapp("Directory");
07061 if (directory_app) {
07062 char vmcontext[256];
07063
07064 memcpy(old_context, chan->context, sizeof(chan->context));
07065 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07066 old_priority = chan->priority;
07067
07068
07069 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07070 res = pbx_exec(chan, directory_app, vmcontext);
07071
07072 ast_copy_string(username, chan->exten, sizeof(username));
07073
07074
07075 memcpy(chan->context, old_context, sizeof(chan->context));
07076 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07077 chan->priority = old_priority;
07078 } else {
07079 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07080 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07081 }
07082 } else {
07083
07084 res = ast_streamfile(chan, "vm-extension", chan->language);
07085 prompt_played++;
07086 if (res || prompt_played > 4)
07087 break;
07088 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07089 break;
07090 }
07091
07092
07093 if (ast_strlen_zero(username))
07094 continue;
07095 stringp = username;
07096 s = strsep(&stringp, "*");
07097
07098 valid_extensions = 1;
07099 while (s) {
07100 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07101 int oldmsgs;
07102 int newmsgs;
07103 int capacity;
07104 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07105 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07106
07107 res = ast_play_and_wait(chan, "pbx-invalid");
07108 valid_extensions = 0;
07109 break;
07110 }
07111 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07112 if ((newmsgs + oldmsgs) >= capacity) {
07113 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07114 res = ast_play_and_wait(chan, "vm-mailboxfull");
07115 valid_extensions = 0;
07116 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07117 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07118 free_user(vmtmp);
07119 }
07120 inprocess_count(receiver->mailbox, receiver->context, -1);
07121 break;
07122 }
07123 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07124 } else {
07125
07126
07127
07128
07129
07130 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07131 free_user(receiver);
07132 }
07133 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07134
07135 res = ast_play_and_wait(chan, "pbx-invalid");
07136 valid_extensions = 0;
07137 break;
07138 }
07139
07140
07141 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07142 RETRIEVE(fn, -1, s, receiver->context);
07143 if (ast_fileexists(fn, NULL, NULL) > 0) {
07144 res = ast_stream_and_wait(chan, fn, ecodes);
07145 if (res) {
07146 DISPOSE(fn, -1);
07147 return res;
07148 }
07149 } else {
07150 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07151 }
07152 DISPOSE(fn, -1);
07153
07154 s = strsep(&stringp, "*");
07155 }
07156
07157 if (valid_extensions)
07158 break;
07159 }
07160
07161 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07162 return res;
07163 if (is_new_message == 1) {
07164 struct leave_vm_options leave_options;
07165 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07166 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07167
07168
07169 memset(&leave_options, 0, sizeof(leave_options));
07170 leave_options.record_gain = record_gain;
07171 cmd = leave_voicemail(chan, mailbox, &leave_options);
07172 } else {
07173
07174 long duration = 0;
07175 struct vm_state vmstmp;
07176 int copy_msg_result = 0;
07177 memcpy(&vmstmp, vms, sizeof(vmstmp));
07178
07179 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07180
07181 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07182 if (!cmd) {
07183 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07184 #ifdef IMAP_STORAGE
07185 int attach_user_voicemail;
07186 char *myserveremail = serveremail;
07187
07188
07189 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07190 if (!dstvms) {
07191 dstvms = create_vm_state_from_user(vmtmp);
07192 }
07193 if (dstvms) {
07194 init_mailstream(dstvms, 0);
07195 if (!dstvms->mailstream) {
07196 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07197 } else {
07198 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07199 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07200 }
07201 } else {
07202 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07203 }
07204 if (!ast_strlen_zero(vmtmp->serveremail))
07205 myserveremail = vmtmp->serveremail;
07206 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07207
07208 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07209 dstvms->curbox,
07210 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07211 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07212 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07213 NULL, urgent_str);
07214 #else
07215 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07216 #endif
07217 saved_messages++;
07218 AST_LIST_REMOVE_CURRENT(list);
07219 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07220 free_user(vmtmp);
07221 if (res)
07222 break;
07223 }
07224 AST_LIST_TRAVERSE_SAFE_END;
07225 if (saved_messages > 0 && !copy_msg_result) {
07226
07227
07228
07229
07230
07231
07232
07233
07234 #ifdef IMAP_STORAGE
07235
07236 if (ast_strlen_zero(vmstmp.introfn))
07237 #endif
07238 res = ast_play_and_wait(chan, "vm-msgsaved");
07239 }
07240 #ifndef IMAP_STORAGE
07241 else {
07242
07243 res = ast_play_and_wait(chan, "vm-mailboxfull");
07244 }
07245
07246 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07247 strcpy(textfile, msgfile);
07248 strcpy(backup, msgfile);
07249 strcpy(backup_textfile, msgfile);
07250 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07251 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07252 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07253 if (ast_fileexists(backup, NULL, NULL) > 0) {
07254 ast_filerename(backup, msgfile, NULL);
07255 rename(backup_textfile, textfile);
07256 }
07257 #endif
07258 }
07259 DISPOSE(dir, curmsg);
07260 #ifndef IMAP_STORAGE
07261 if (cmd) {
07262 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07263 strcpy(textfile, msgfile);
07264 strcpy(backup_textfile, msgfile);
07265 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07266 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07267 rename(backup_textfile, textfile);
07268 }
07269 #endif
07270 }
07271
07272
07273 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07274 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07275 free_user(vmtmp);
07276 }
07277 return res ? res : cmd;
07278 }
07279
07280 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07281 {
07282 int res;
07283 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07284 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07285 return res;
07286 }
07287
07288 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07289 {
07290 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);
07291 }
07292
07293 static int play_message_category(struct ast_channel *chan, const char *category)
07294 {
07295 int res = 0;
07296
07297 if (!ast_strlen_zero(category))
07298 res = ast_play_and_wait(chan, category);
07299
07300 if (res) {
07301 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07302 res = 0;
07303 }
07304
07305 return res;
07306 }
07307
07308 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07309 {
07310 int res = 0;
07311 struct vm_zone *the_zone = NULL;
07312 time_t t;
07313
07314 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07315 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07316 return 0;
07317 }
07318
07319
07320 if (!ast_strlen_zero(vmu->zonetag)) {
07321
07322 struct vm_zone *z;
07323 AST_LIST_LOCK(&zones);
07324 AST_LIST_TRAVERSE(&zones, z, list) {
07325 if (!strcmp(z->name, vmu->zonetag)) {
07326 the_zone = z;
07327 break;
07328 }
07329 }
07330 AST_LIST_UNLOCK(&zones);
07331 }
07332
07333
07334 #if 0
07335
07336 ast_localtime(&t, &time_now, NULL);
07337 tv_now = ast_tvnow();
07338 ast_localtime(&tv_now, &time_then, NULL);
07339
07340
07341 if (time_now.tm_year == time_then.tm_year)
07342 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07343 else
07344 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07345 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07346
07347
07348 #endif
07349 if (the_zone) {
07350 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07351 } else if (!strncasecmp(chan->language, "de", 2)) {
07352 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07353 } else if (!strncasecmp(chan->language, "gr", 2)) {
07354 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07355 } else if (!strncasecmp(chan->language, "it", 2)) {
07356 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);
07357 } else if (!strncasecmp(chan->language, "nl", 2)) {
07358 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07359 } else if (!strncasecmp(chan->language, "no", 2)) {
07360 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07361 } else if (!strncasecmp(chan->language, "pl", 2)) {
07362 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07363 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07364 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);
07365 } else if (!strncasecmp(chan->language, "se", 2)) {
07366 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07367 } else if (!strncasecmp(chan->language, "zh", 2)) {
07368 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07369 } else if (!strncasecmp(chan->language, "vi", 2)) {
07370 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);
07371 } else {
07372 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07373 }
07374 #if 0
07375 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07376 #endif
07377 return res;
07378 }
07379
07380
07381
07382 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07383 {
07384 int res = 0;
07385 int i;
07386 char *callerid, *name;
07387 char prefile[PATH_MAX] = "";
07388
07389
07390
07391
07392
07393
07394
07395
07396
07397 if ((cid == NULL)||(context == NULL))
07398 return res;
07399
07400
07401 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07402 ast_callerid_parse(cid, &name, &callerid);
07403 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07404
07405
07406 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07407 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07408 if ((strcmp(cidinternalcontexts[i], context) == 0))
07409 break;
07410 }
07411 if (i != MAX_NUM_CID_CONTEXTS){
07412 if (!res) {
07413 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07414 if (!ast_strlen_zero(prefile)) {
07415
07416 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07417 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07418 if (!callback)
07419 res = wait_file2(chan, vms, "vm-from");
07420 res = ast_stream_and_wait(chan, prefile, "");
07421 } else {
07422 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07423
07424 if (!callback)
07425 res = wait_file2(chan, vms, "vm-from-extension");
07426 res = ast_say_digit_str(chan, callerid, "", chan->language);
07427 }
07428 }
07429 }
07430 } else if (!res) {
07431 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07432
07433 if (!callback)
07434 res = wait_file2(chan, vms, "vm-from-phonenumber");
07435 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07436 }
07437 } else {
07438
07439 ast_debug(1, "VM-CID: From an unknown number\n");
07440
07441 res = wait_file2(chan, vms, "vm-unknown-caller");
07442 }
07443 return res;
07444 }
07445
07446 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07447 {
07448 int res = 0;
07449 int durationm;
07450 int durations;
07451
07452 if (duration == NULL)
07453 return res;
07454
07455
07456 durations = atoi(duration);
07457 durationm = (durations / 60);
07458
07459 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07460
07461 if ((!res) && (durationm >= minduration)) {
07462 res = wait_file2(chan, vms, "vm-duration");
07463
07464
07465 if (!strncasecmp(chan->language, "pl", 2)) {
07466 div_t num = div(durationm, 10);
07467
07468 if (durationm == 1) {
07469 res = ast_play_and_wait(chan, "digits/1z");
07470 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07471 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07472 if (num.rem == 2) {
07473 if (!num.quot) {
07474 res = ast_play_and_wait(chan, "digits/2-ie");
07475 } else {
07476 res = say_and_wait(chan, durationm - 2 , chan->language);
07477 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07478 }
07479 } else {
07480 res = say_and_wait(chan, durationm, chan->language);
07481 }
07482 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07483 } else {
07484 res = say_and_wait(chan, durationm, chan->language);
07485 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07486 }
07487
07488 } else {
07489 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07490 res = wait_file2(chan, vms, "vm-minutes");
07491 }
07492 }
07493 return res;
07494 }
07495
07496 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07497 {
07498 int res = 0;
07499 char filename[256], *cid;
07500 const char *origtime, *context, *category, *duration, *flag;
07501 struct ast_config *msg_cfg;
07502 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07503
07504 vms->starting = 0;
07505 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07506 adsi_message(chan, vms);
07507 if (!vms->curmsg)
07508 res = wait_file2(chan, vms, "vm-first");
07509 else if (vms->curmsg == vms->lastmsg)
07510 res = wait_file2(chan, vms, "vm-last");
07511
07512 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07513 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07514 msg_cfg = ast_config_load(filename, config_flags);
07515 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07516 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07517 return 0;
07518 }
07519 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07520
07521
07522 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07523 res = wait_file2(chan, vms, "vm-Urgent");
07524 }
07525
07526 if (!res) {
07527
07528
07529 if (!strncasecmp(chan->language, "pl", 2)) {
07530 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07531 int ten, one;
07532 char nextmsg[256];
07533 ten = (vms->curmsg + 1) / 10;
07534 one = (vms->curmsg + 1) % 10;
07535
07536 if (vms->curmsg < 20) {
07537 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07538 res = wait_file2(chan, vms, nextmsg);
07539 } else {
07540 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07541 res = wait_file2(chan, vms, nextmsg);
07542 if (one > 0) {
07543 if (!res) {
07544 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07545 res = wait_file2(chan, vms, nextmsg);
07546 }
07547 }
07548 }
07549 }
07550 if (!res)
07551 res = wait_file2(chan, vms, "vm-message");
07552
07553 } else if (!strncasecmp(chan->language, "he", 2)) {
07554 if (!vms->curmsg) {
07555 res = wait_file2(chan, vms, "vm-message");
07556 res = wait_file2(chan, vms, "vm-first");
07557 } else if (vms->curmsg == vms->lastmsg) {
07558 res = wait_file2(chan, vms, "vm-message");
07559 res = wait_file2(chan, vms, "vm-last");
07560 } else {
07561 res = wait_file2(chan, vms, "vm-message");
07562 res = wait_file2(chan, vms, "vm-number");
07563 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07564 }
07565
07566 } else if (!strncasecmp(chan->language, "vi", 2)) {
07567 if (!vms->curmsg) {
07568 res = wait_file2(chan, vms, "vm-message");
07569 res = wait_file2(chan, vms, "vm-first");
07570 } else if (vms->curmsg == vms->lastmsg) {
07571 res = wait_file2(chan, vms, "vm-message");
07572 res = wait_file2(chan, vms, "vm-last");
07573 } else {
07574 res = wait_file2(chan, vms, "vm-message");
07575 res = wait_file2(chan, vms, "vm-number");
07576 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07577 }
07578 } else {
07579 if (!strncasecmp(chan->language, "se", 2)) {
07580 res = wait_file2(chan, vms, "vm-meddelandet");
07581 } else {
07582 res = wait_file2(chan, vms, "vm-message");
07583 }
07584 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07585 if (!res) {
07586 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07587 }
07588 }
07589 }
07590 }
07591
07592 if (!msg_cfg) {
07593 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07594 return 0;
07595 }
07596
07597 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07598 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07599 DISPOSE(vms->curdir, vms->curmsg);
07600 ast_config_destroy(msg_cfg);
07601 return 0;
07602 }
07603
07604 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07605 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07606 category = ast_variable_retrieve(msg_cfg, "message", "category");
07607
07608 context = ast_variable_retrieve(msg_cfg, "message", "context");
07609 if (!strncasecmp("macro", context, 5))
07610 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07611 if (!res) {
07612 res = play_message_category(chan, category);
07613 }
07614 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
07615 res = play_message_datetime(chan, vmu, origtime, filename);
07616 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
07617 res = play_message_callerid(chan, vms, cid, context, 0);
07618 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
07619 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07620
07621 if (res == '1')
07622 res = 0;
07623 ast_config_destroy(msg_cfg);
07624
07625 if (!res) {
07626 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07627 vms->heard[vms->curmsg] = 1;
07628 #ifdef IMAP_STORAGE
07629
07630
07631
07632 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07633 wait_file(chan, vms, vms->introfn);
07634 }
07635 #endif
07636 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07637 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07638 res = 0;
07639 }
07640 }
07641 DISPOSE(vms->curdir, vms->curmsg);
07642 return res;
07643 }
07644
07645 #ifdef IMAP_STORAGE
07646 static int imap_remove_file(char *dir, int msgnum)
07647 {
07648 char fn[PATH_MAX];
07649 char full_fn[PATH_MAX];
07650 char intro[PATH_MAX] = {0,};
07651
07652 if (msgnum > -1) {
07653 make_file(fn, sizeof(fn), dir, msgnum);
07654 snprintf(intro, sizeof(intro), "%sintro", fn);
07655 } else
07656 ast_copy_string(fn, dir, sizeof(fn));
07657
07658 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07659 ast_filedelete(fn, NULL);
07660 if (!ast_strlen_zero(intro)) {
07661 ast_filedelete(intro, NULL);
07662 }
07663 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07664 unlink(full_fn);
07665 }
07666 return 0;
07667 }
07668
07669
07670
07671 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07672 {
07673 char *file, *filename;
07674 char *attachment;
07675 char arg[10];
07676 int i;
07677 BODY* body;
07678
07679 file = strrchr(ast_strdupa(dir), '/');
07680 if (file) {
07681 *file++ = '\0';
07682 } else {
07683 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07684 return -1;
07685 }
07686
07687 ast_mutex_lock(&vms->lock);
07688 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07689 mail_fetchstructure(vms->mailstream, i + 1, &body);
07690
07691 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07692 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07693 } else {
07694 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07695 ast_mutex_unlock(&vms->lock);
07696 return -1;
07697 }
07698 filename = strsep(&attachment, ".");
07699 if (!strcmp(filename, file)) {
07700 sprintf(arg, "%d", i + 1);
07701 mail_setflag(vms->mailstream, arg, "\\DELETED");
07702 }
07703 }
07704 mail_expunge(vms->mailstream);
07705 ast_mutex_unlock(&vms->lock);
07706 return 0;
07707 }
07708
07709 #elif !defined(IMAP_STORAGE)
07710 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07711 {
07712 int count_msg, last_msg;
07713
07714 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07715
07716
07717
07718
07719 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07720
07721
07722 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07723
07724
07725 count_msg = count_messages(vmu, vms->curdir);
07726 if (count_msg < 0) {
07727 return count_msg;
07728 } else {
07729 vms->lastmsg = count_msg - 1;
07730 }
07731
07732 if (vm_allocate_dh(vms, vmu, count_msg)) {
07733 return -1;
07734 }
07735
07736
07737
07738
07739
07740
07741
07742
07743 if (vm_lock_path(vms->curdir)) {
07744 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07745 return ERROR_LOCK_PATH;
07746 }
07747
07748
07749 last_msg = last_message_index(vmu, vms->curdir);
07750 ast_unlock_path(vms->curdir);
07751
07752 if (last_msg < -1) {
07753 return last_msg;
07754 #ifndef ODBC_STORAGE
07755 } else if (vms->lastmsg != last_msg) {
07756 ast_log(LOG_NOTICE, "Resequencing mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
07757 resequence_mailbox(vmu, vms->curdir, count_msg);
07758 #endif
07759 }
07760
07761 return 0;
07762 }
07763 #endif
07764
07765 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07766 {
07767 int x = 0;
07768 #ifndef IMAP_STORAGE
07769 int res = 0, nummsg;
07770 char fn2[PATH_MAX];
07771 #endif
07772
07773 if (vms->lastmsg <= -1) {
07774 goto done;
07775 }
07776
07777 vms->curmsg = -1;
07778 #ifndef IMAP_STORAGE
07779
07780 if (vm_lock_path(vms->curdir)) {
07781 return ERROR_LOCK_PATH;
07782 }
07783
07784
07785 for (x = 0; x < vms->lastmsg + 1; x++) {
07786 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07787
07788 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07789 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07790 break;
07791 }
07792 vms->curmsg++;
07793 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07794 if (strcmp(vms->fn, fn2)) {
07795 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07796 }
07797 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07798
07799 res = save_to_folder(vmu, vms, x, 1);
07800 if (res == ERROR_LOCK_PATH) {
07801
07802 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07803 vms->deleted[x] = 0;
07804 vms->heard[x] = 0;
07805 --x;
07806 }
07807 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07808
07809 res = save_to_folder(vmu, vms, x, 10);
07810 if (res == ERROR_LOCK_PATH) {
07811
07812 vms->deleted[x] = 0;
07813 vms->heard[x] = 0;
07814 --x;
07815 }
07816 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07817
07818
07819 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07820 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07821 DELETE(vms->curdir, x, vms->fn, vmu);
07822 }
07823 }
07824 }
07825
07826
07827 nummsg = x - 1;
07828 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07829 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07830 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07831 DELETE(vms->curdir, x, vms->fn, vmu);
07832 }
07833 }
07834 ast_unlock_path(vms->curdir);
07835 #else
07836 if (vms->deleted) {
07837
07838
07839 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
07840 if (vms->deleted[x]) {
07841 ast_debug(3, "IMAP delete of %d\n", x);
07842 DELETE(vms->curdir, x, vms->fn, vmu);
07843 }
07844 }
07845 }
07846 #endif
07847
07848 done:
07849 if (vms->deleted && vmu->maxmsg) {
07850 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
07851 }
07852 if (vms->heard && vmu->maxmsg) {
07853 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
07854 }
07855
07856 return 0;
07857 }
07858
07859
07860
07861
07862
07863
07864
07865 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
07866 {
07867 int cmd;
07868 char *buf;
07869
07870 buf = alloca(strlen(box) + 2);
07871 strcpy(buf, box);
07872 strcat(buf, "s");
07873
07874 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
07875 cmd = ast_play_and_wait(chan, buf);
07876 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07877 } else {
07878 cmd = ast_play_and_wait(chan, "vm-messages");
07879 return cmd ? cmd : ast_play_and_wait(chan, box);
07880 }
07881 }
07882
07883 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
07884 {
07885 int cmd;
07886
07887 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
07888 if (!strcasecmp(box, "vm-INBOX"))
07889 cmd = ast_play_and_wait(chan, "vm-new-e");
07890 else
07891 cmd = ast_play_and_wait(chan, "vm-old-e");
07892 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07893 } else {
07894 cmd = ast_play_and_wait(chan, "vm-messages");
07895 return cmd ? cmd : ast_play_and_wait(chan, box);
07896 }
07897 }
07898
07899 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
07900 {
07901 int cmd;
07902
07903 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
07904 cmd = ast_play_and_wait(chan, "vm-messages");
07905 return cmd ? cmd : ast_play_and_wait(chan, box);
07906 } else {
07907 cmd = ast_play_and_wait(chan, box);
07908 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07909 }
07910 }
07911
07912 static int vm_play_folder_name(struct ast_channel *chan, char *box)
07913 {
07914 int cmd;
07915
07916 if ( !strncasecmp(chan->language, "it", 2) ||
07917 !strncasecmp(chan->language, "es", 2) ||
07918 !strncasecmp(chan->language, "pt", 2)) {
07919 cmd = ast_play_and_wait(chan, "vm-messages");
07920 return cmd ? cmd : ast_play_and_wait(chan, box);
07921 } else if (!strncasecmp(chan->language, "gr", 2)) {
07922 return vm_play_folder_name_gr(chan, box);
07923 } else if (!strncasecmp(chan->language, "he", 2)) {
07924 return ast_play_and_wait(chan, box);
07925 } else if (!strncasecmp(chan->language, "pl", 2)) {
07926 return vm_play_folder_name_pl(chan, box);
07927 } else if (!strncasecmp(chan->language, "ua", 2)) {
07928 return vm_play_folder_name_ua(chan, box);
07929 } else if (!strncasecmp(chan->language, "vi", 2)) {
07930 return ast_play_and_wait(chan, box);
07931 } else {
07932 cmd = ast_play_and_wait(chan, box);
07933 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07934 }
07935 }
07936
07937
07938
07939
07940
07941
07942
07943
07944
07945
07946
07947
07948
07949 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
07950 {
07951 int res = 0;
07952
07953 if (vms->newmessages) {
07954 res = ast_play_and_wait(chan, "vm-youhave");
07955 if (!res)
07956 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
07957 if (!res) {
07958 if ((vms->newmessages == 1)) {
07959 res = ast_play_and_wait(chan, "vm-INBOX");
07960 if (!res)
07961 res = ast_play_and_wait(chan, "vm-message");
07962 } else {
07963 res = ast_play_and_wait(chan, "vm-INBOXs");
07964 if (!res)
07965 res = ast_play_and_wait(chan, "vm-messages");
07966 }
07967 }
07968 } else if (vms->oldmessages){
07969 res = ast_play_and_wait(chan, "vm-youhave");
07970 if (!res)
07971 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
07972 if ((vms->oldmessages == 1)){
07973 res = ast_play_and_wait(chan, "vm-Old");
07974 if (!res)
07975 res = ast_play_and_wait(chan, "vm-message");
07976 } else {
07977 res = ast_play_and_wait(chan, "vm-Olds");
07978 if (!res)
07979 res = ast_play_and_wait(chan, "vm-messages");
07980 }
07981 } else if (!vms->oldmessages && !vms->newmessages)
07982 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
07983 return res;
07984 }
07985
07986
07987
07988
07989
07990
07991
07992
07993
07994
07995
07996
07997
07998
07999
08000
08001
08002
08003
08004
08005
08006
08007
08008
08009
08010
08011
08012
08013
08014
08015
08016
08017
08018
08019
08020
08021
08022
08023
08024
08025
08026
08027
08028
08029
08030
08031
08032
08033
08034
08035
08036
08037
08038
08039
08040
08041
08042
08043 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08044 {
08045 int res;
08046 int lastnum = 0;
08047
08048 res = ast_play_and_wait(chan, "vm-youhave");
08049
08050 if (!res && vms->newmessages) {
08051 lastnum = vms->newmessages;
08052
08053 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08054 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08055 }
08056
08057 if (!res && vms->oldmessages) {
08058 res = ast_play_and_wait(chan, "vm-and");
08059 }
08060 }
08061
08062 if (!res && vms->oldmessages) {
08063 lastnum = vms->oldmessages;
08064
08065 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08066 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08067 }
08068 }
08069
08070 if (!res) {
08071 if (lastnum == 0) {
08072 res = ast_play_and_wait(chan, "vm-no");
08073 }
08074 if (!res) {
08075 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08076 }
08077 }
08078
08079 return res;
08080 }
08081
08082
08083 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08084 {
08085 int res = 0;
08086
08087
08088 if (!res) {
08089 if ((vms->newmessages) || (vms->oldmessages)) {
08090 res = ast_play_and_wait(chan, "vm-youhave");
08091 }
08092
08093
08094
08095
08096
08097 if (vms->newmessages) {
08098 if (!res) {
08099 if (vms->newmessages == 1) {
08100 res = ast_play_and_wait(chan, "vm-INBOX1");
08101 } else {
08102 if (vms->newmessages == 2) {
08103 res = ast_play_and_wait(chan, "vm-shtei");
08104 } else {
08105 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08106 }
08107 res = ast_play_and_wait(chan, "vm-INBOX");
08108 }
08109 }
08110 if (vms->oldmessages && !res) {
08111 res = ast_play_and_wait(chan, "vm-and");
08112 if (vms->oldmessages == 1) {
08113 res = ast_play_and_wait(chan, "vm-Old1");
08114 } else {
08115 if (vms->oldmessages == 2) {
08116 res = ast_play_and_wait(chan, "vm-shtei");
08117 } else {
08118 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08119 }
08120 res = ast_play_and_wait(chan, "vm-Old");
08121 }
08122 }
08123 }
08124 if (!res && vms->oldmessages && !vms->newmessages) {
08125 if (!res) {
08126 if (vms->oldmessages == 1) {
08127 res = ast_play_and_wait(chan, "vm-Old1");
08128 } else {
08129 if (vms->oldmessages == 2) {
08130 res = ast_play_and_wait(chan, "vm-shtei");
08131 } else {
08132 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08133 }
08134 res = ast_play_and_wait(chan, "vm-Old");
08135 }
08136 }
08137 }
08138 if (!res) {
08139 if (!vms->oldmessages && !vms->newmessages) {
08140 if (!res) {
08141 res = ast_play_and_wait(chan, "vm-nomessages");
08142 }
08143 }
08144 }
08145 }
08146 return res;
08147 }
08148
08149
08150 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08151 {
08152 int res;
08153
08154
08155 res = ast_play_and_wait(chan, "vm-youhave");
08156 if (!res) {
08157 if (vms->urgentmessages) {
08158 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08159 if (!res)
08160 res = ast_play_and_wait(chan, "vm-Urgent");
08161 if ((vms->oldmessages || vms->newmessages) && !res) {
08162 res = ast_play_and_wait(chan, "vm-and");
08163 } else if (!res) {
08164 if ((vms->urgentmessages == 1))
08165 res = ast_play_and_wait(chan, "vm-message");
08166 else
08167 res = ast_play_and_wait(chan, "vm-messages");
08168 }
08169 }
08170 if (vms->newmessages) {
08171 res = say_and_wait(chan, vms->newmessages, chan->language);
08172 if (!res)
08173 res = ast_play_and_wait(chan, "vm-INBOX");
08174 if (vms->oldmessages && !res)
08175 res = ast_play_and_wait(chan, "vm-and");
08176 else if (!res) {
08177 if ((vms->newmessages == 1))
08178 res = ast_play_and_wait(chan, "vm-message");
08179 else
08180 res = ast_play_and_wait(chan, "vm-messages");
08181 }
08182
08183 }
08184 if (!res && vms->oldmessages) {
08185 res = say_and_wait(chan, vms->oldmessages, chan->language);
08186 if (!res)
08187 res = ast_play_and_wait(chan, "vm-Old");
08188 if (!res) {
08189 if (vms->oldmessages == 1)
08190 res = ast_play_and_wait(chan, "vm-message");
08191 else
08192 res = ast_play_and_wait(chan, "vm-messages");
08193 }
08194 }
08195 if (!res) {
08196 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08197 res = ast_play_and_wait(chan, "vm-no");
08198 if (!res)
08199 res = ast_play_and_wait(chan, "vm-messages");
08200 }
08201 }
08202 }
08203 return res;
08204 }
08205
08206
08207 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08208 {
08209
08210 int res;
08211 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08212 res = ast_play_and_wait(chan, "vm-no") ||
08213 ast_play_and_wait(chan, "vm-message");
08214 else
08215 res = ast_play_and_wait(chan, "vm-youhave");
08216 if (!res && vms->newmessages) {
08217 res = (vms->newmessages == 1) ?
08218 ast_play_and_wait(chan, "digits/un") ||
08219 ast_play_and_wait(chan, "vm-nuovo") ||
08220 ast_play_and_wait(chan, "vm-message") :
08221
08222 say_and_wait(chan, vms->newmessages, chan->language) ||
08223 ast_play_and_wait(chan, "vm-nuovi") ||
08224 ast_play_and_wait(chan, "vm-messages");
08225 if (!res && vms->oldmessages)
08226 res = ast_play_and_wait(chan, "vm-and");
08227 }
08228 if (!res && vms->oldmessages) {
08229 res = (vms->oldmessages == 1) ?
08230 ast_play_and_wait(chan, "digits/un") ||
08231 ast_play_and_wait(chan, "vm-vecchio") ||
08232 ast_play_and_wait(chan, "vm-message") :
08233
08234 say_and_wait(chan, vms->oldmessages, chan->language) ||
08235 ast_play_and_wait(chan, "vm-vecchi") ||
08236 ast_play_and_wait(chan, "vm-messages");
08237 }
08238 return res;
08239 }
08240
08241
08242 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08243 {
08244
08245 int res;
08246 div_t num;
08247
08248 if (!vms->oldmessages && !vms->newmessages) {
08249 res = ast_play_and_wait(chan, "vm-no");
08250 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08251 return res;
08252 } else {
08253 res = ast_play_and_wait(chan, "vm-youhave");
08254 }
08255
08256 if (vms->newmessages) {
08257 num = div(vms->newmessages, 10);
08258 if (vms->newmessages == 1) {
08259 res = ast_play_and_wait(chan, "digits/1-a");
08260 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08261 res = res ? res : ast_play_and_wait(chan, "vm-message");
08262 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08263 if (num.rem == 2) {
08264 if (!num.quot) {
08265 res = ast_play_and_wait(chan, "digits/2-ie");
08266 } else {
08267 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08268 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08269 }
08270 } else {
08271 res = say_and_wait(chan, vms->newmessages, chan->language);
08272 }
08273 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08274 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08275 } else {
08276 res = say_and_wait(chan, vms->newmessages, chan->language);
08277 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08278 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08279 }
08280 if (!res && vms->oldmessages)
08281 res = ast_play_and_wait(chan, "vm-and");
08282 }
08283 if (!res && vms->oldmessages) {
08284 num = div(vms->oldmessages, 10);
08285 if (vms->oldmessages == 1) {
08286 res = ast_play_and_wait(chan, "digits/1-a");
08287 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08288 res = res ? res : ast_play_and_wait(chan, "vm-message");
08289 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08290 if (num.rem == 2) {
08291 if (!num.quot) {
08292 res = ast_play_and_wait(chan, "digits/2-ie");
08293 } else {
08294 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08295 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08296 }
08297 } else {
08298 res = say_and_wait(chan, vms->oldmessages, chan->language);
08299 }
08300 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08301 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08302 } else {
08303 res = say_and_wait(chan, vms->oldmessages, chan->language);
08304 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08305 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08306 }
08307 }
08308
08309 return res;
08310 }
08311
08312
08313 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08314 {
08315
08316 int res;
08317
08318 res = ast_play_and_wait(chan, "vm-youhave");
08319 if (res)
08320 return res;
08321
08322 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08323 res = ast_play_and_wait(chan, "vm-no");
08324 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08325 return res;
08326 }
08327
08328 if (vms->newmessages) {
08329 if ((vms->newmessages == 1)) {
08330 res = ast_play_and_wait(chan, "digits/ett");
08331 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08332 res = res ? res : ast_play_and_wait(chan, "vm-message");
08333 } else {
08334 res = say_and_wait(chan, vms->newmessages, chan->language);
08335 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08336 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08337 }
08338 if (!res && vms->oldmessages)
08339 res = ast_play_and_wait(chan, "vm-and");
08340 }
08341 if (!res && vms->oldmessages) {
08342 if (vms->oldmessages == 1) {
08343 res = ast_play_and_wait(chan, "digits/ett");
08344 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08345 res = res ? res : ast_play_and_wait(chan, "vm-message");
08346 } else {
08347 res = say_and_wait(chan, vms->oldmessages, chan->language);
08348 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08349 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08350 }
08351 }
08352
08353 return res;
08354 }
08355
08356
08357 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08358 {
08359
08360 int res;
08361
08362 res = ast_play_and_wait(chan, "vm-youhave");
08363 if (res)
08364 return res;
08365
08366 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08367 res = ast_play_and_wait(chan, "vm-no");
08368 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08369 return res;
08370 }
08371
08372 if (vms->newmessages) {
08373 if ((vms->newmessages == 1)) {
08374 res = ast_play_and_wait(chan, "digits/1");
08375 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08376 res = res ? res : ast_play_and_wait(chan, "vm-message");
08377 } else {
08378 res = say_and_wait(chan, vms->newmessages, chan->language);
08379 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08380 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08381 }
08382 if (!res && vms->oldmessages)
08383 res = ast_play_and_wait(chan, "vm-and");
08384 }
08385 if (!res && vms->oldmessages) {
08386 if (vms->oldmessages == 1) {
08387 res = ast_play_and_wait(chan, "digits/1");
08388 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08389 res = res ? res : ast_play_and_wait(chan, "vm-message");
08390 } else {
08391 res = say_and_wait(chan, vms->oldmessages, chan->language);
08392 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08393 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08394 }
08395 }
08396
08397 return res;
08398 }
08399
08400
08401 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08402 {
08403
08404 int res;
08405 res = ast_play_and_wait(chan, "vm-youhave");
08406 if (!res) {
08407 if (vms->newmessages) {
08408 if ((vms->newmessages == 1))
08409 res = ast_play_and_wait(chan, "digits/1F");
08410 else
08411 res = say_and_wait(chan, vms->newmessages, chan->language);
08412 if (!res)
08413 res = ast_play_and_wait(chan, "vm-INBOX");
08414 if (vms->oldmessages && !res)
08415 res = ast_play_and_wait(chan, "vm-and");
08416 else if (!res) {
08417 if ((vms->newmessages == 1))
08418 res = ast_play_and_wait(chan, "vm-message");
08419 else
08420 res = ast_play_and_wait(chan, "vm-messages");
08421 }
08422
08423 }
08424 if (!res && vms->oldmessages) {
08425 if (vms->oldmessages == 1)
08426 res = ast_play_and_wait(chan, "digits/1F");
08427 else
08428 res = say_and_wait(chan, vms->oldmessages, chan->language);
08429 if (!res)
08430 res = ast_play_and_wait(chan, "vm-Old");
08431 if (!res) {
08432 if (vms->oldmessages == 1)
08433 res = ast_play_and_wait(chan, "vm-message");
08434 else
08435 res = ast_play_and_wait(chan, "vm-messages");
08436 }
08437 }
08438 if (!res) {
08439 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08440 res = ast_play_and_wait(chan, "vm-no");
08441 if (!res)
08442 res = ast_play_and_wait(chan, "vm-messages");
08443 }
08444 }
08445 }
08446 return res;
08447 }
08448
08449
08450 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08451 {
08452
08453 int res;
08454 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08455 res = ast_play_and_wait(chan, "vm-youhaveno");
08456 if (!res)
08457 res = ast_play_and_wait(chan, "vm-messages");
08458 } else {
08459 res = ast_play_and_wait(chan, "vm-youhave");
08460 }
08461 if (!res) {
08462 if (vms->newmessages) {
08463 if (!res) {
08464 if ((vms->newmessages == 1)) {
08465 res = ast_play_and_wait(chan, "digits/1M");
08466 if (!res)
08467 res = ast_play_and_wait(chan, "vm-message");
08468 if (!res)
08469 res = ast_play_and_wait(chan, "vm-INBOXs");
08470 } else {
08471 res = say_and_wait(chan, vms->newmessages, chan->language);
08472 if (!res)
08473 res = ast_play_and_wait(chan, "vm-messages");
08474 if (!res)
08475 res = ast_play_and_wait(chan, "vm-INBOX");
08476 }
08477 }
08478 if (vms->oldmessages && !res)
08479 res = ast_play_and_wait(chan, "vm-and");
08480 }
08481 if (vms->oldmessages) {
08482 if (!res) {
08483 if (vms->oldmessages == 1) {
08484 res = ast_play_and_wait(chan, "digits/1M");
08485 if (!res)
08486 res = ast_play_and_wait(chan, "vm-message");
08487 if (!res)
08488 res = ast_play_and_wait(chan, "vm-Olds");
08489 } else {
08490 res = say_and_wait(chan, vms->oldmessages, chan->language);
08491 if (!res)
08492 res = ast_play_and_wait(chan, "vm-messages");
08493 if (!res)
08494 res = ast_play_and_wait(chan, "vm-Old");
08495 }
08496 }
08497 }
08498 }
08499 return res;
08500 }
08501
08502
08503 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08504
08505 int res;
08506 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08507 res = ast_play_and_wait(chan, "vm-nomessages");
08508 return res;
08509 } else {
08510 res = ast_play_and_wait(chan, "vm-youhave");
08511 }
08512 if (vms->newmessages) {
08513 if (!res)
08514 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08515 if ((vms->newmessages == 1)) {
08516 if (!res)
08517 res = ast_play_and_wait(chan, "vm-message");
08518 if (!res)
08519 res = ast_play_and_wait(chan, "vm-INBOXs");
08520 } else {
08521 if (!res)
08522 res = ast_play_and_wait(chan, "vm-messages");
08523 if (!res)
08524 res = ast_play_and_wait(chan, "vm-INBOX");
08525 }
08526 if (vms->oldmessages && !res)
08527 res = ast_play_and_wait(chan, "vm-and");
08528 }
08529 if (vms->oldmessages) {
08530 if (!res)
08531 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08532 if (vms->oldmessages == 1) {
08533 if (!res)
08534 res = ast_play_and_wait(chan, "vm-message");
08535 if (!res)
08536 res = ast_play_and_wait(chan, "vm-Olds");
08537 } else {
08538 if (!res)
08539 res = ast_play_and_wait(chan, "vm-messages");
08540 if (!res)
08541 res = ast_play_and_wait(chan, "vm-Old");
08542 }
08543 }
08544 return res;
08545 }
08546
08547
08548 static int vm_intro_fr(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 res = ast_play_and_wait(chan, "vm-INBOX");
08558 if (vms->oldmessages && !res)
08559 res = ast_play_and_wait(chan, "vm-and");
08560 else if (!res) {
08561 if ((vms->newmessages == 1))
08562 res = ast_play_and_wait(chan, "vm-message");
08563 else
08564 res = ast_play_and_wait(chan, "vm-messages");
08565 }
08566
08567 }
08568 if (!res && vms->oldmessages) {
08569 res = say_and_wait(chan, vms->oldmessages, chan->language);
08570 if (!res)
08571 res = ast_play_and_wait(chan, "vm-Old");
08572 if (!res) {
08573 if (vms->oldmessages == 1)
08574 res = ast_play_and_wait(chan, "vm-message");
08575 else
08576 res = ast_play_and_wait(chan, "vm-messages");
08577 }
08578 }
08579 if (!res) {
08580 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08581 res = ast_play_and_wait(chan, "vm-no");
08582 if (!res)
08583 res = ast_play_and_wait(chan, "vm-messages");
08584 }
08585 }
08586 }
08587 return res;
08588 }
08589
08590
08591 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08592 {
08593
08594 int res;
08595 res = ast_play_and_wait(chan, "vm-youhave");
08596 if (!res) {
08597 if (vms->newmessages) {
08598 res = say_and_wait(chan, vms->newmessages, chan->language);
08599 if (!res) {
08600 if (vms->newmessages == 1)
08601 res = ast_play_and_wait(chan, "vm-INBOXs");
08602 else
08603 res = ast_play_and_wait(chan, "vm-INBOX");
08604 }
08605 if (vms->oldmessages && !res)
08606 res = ast_play_and_wait(chan, "vm-and");
08607 else if (!res) {
08608 if ((vms->newmessages == 1))
08609 res = ast_play_and_wait(chan, "vm-message");
08610 else
08611 res = ast_play_and_wait(chan, "vm-messages");
08612 }
08613
08614 }
08615 if (!res && vms->oldmessages) {
08616 res = say_and_wait(chan, vms->oldmessages, chan->language);
08617 if (!res) {
08618 if (vms->oldmessages == 1)
08619 res = ast_play_and_wait(chan, "vm-Olds");
08620 else
08621 res = ast_play_and_wait(chan, "vm-Old");
08622 }
08623 if (!res) {
08624 if (vms->oldmessages == 1)
08625 res = ast_play_and_wait(chan, "vm-message");
08626 else
08627 res = ast_play_and_wait(chan, "vm-messages");
08628 }
08629 }
08630 if (!res) {
08631 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08632 res = ast_play_and_wait(chan, "vm-no");
08633 if (!res)
08634 res = ast_play_and_wait(chan, "vm-messages");
08635 }
08636 }
08637 }
08638 return res;
08639 }
08640
08641
08642 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08643 {
08644
08645 int res;
08646 res = ast_play_and_wait(chan, "vm-youhave");
08647 if (!res) {
08648 if (vms->newmessages) {
08649 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08650 if (!res) {
08651 if ((vms->newmessages == 1)) {
08652 res = ast_play_and_wait(chan, "vm-message");
08653 if (!res)
08654 res = ast_play_and_wait(chan, "vm-INBOXs");
08655 } else {
08656 res = ast_play_and_wait(chan, "vm-messages");
08657 if (!res)
08658 res = ast_play_and_wait(chan, "vm-INBOX");
08659 }
08660 }
08661 if (vms->oldmessages && !res)
08662 res = ast_play_and_wait(chan, "vm-and");
08663 }
08664 if (!res && vms->oldmessages) {
08665 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08666 if (!res) {
08667 if (vms->oldmessages == 1) {
08668 res = ast_play_and_wait(chan, "vm-message");
08669 if (!res)
08670 res = ast_play_and_wait(chan, "vm-Olds");
08671 } else {
08672 res = ast_play_and_wait(chan, "vm-messages");
08673 if (!res)
08674 res = ast_play_and_wait(chan, "vm-Old");
08675 }
08676 }
08677 }
08678 if (!res) {
08679 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08680 res = ast_play_and_wait(chan, "vm-no");
08681 if (!res)
08682 res = ast_play_and_wait(chan, "vm-messages");
08683 }
08684 }
08685 }
08686 return res;
08687 }
08688
08689
08690
08691
08692
08693
08694
08695
08696
08697
08698
08699
08700
08701
08702
08703
08704
08705 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08706 {
08707 int res;
08708 res = ast_play_and_wait(chan, "vm-youhave");
08709 if (!res) {
08710 if (vms->newmessages) {
08711 if (vms->newmessages == 1) {
08712 res = ast_play_and_wait(chan, "digits/jednu");
08713 } else {
08714 res = say_and_wait(chan, vms->newmessages, chan->language);
08715 }
08716 if (!res) {
08717 if ((vms->newmessages == 1))
08718 res = ast_play_and_wait(chan, "vm-novou");
08719 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08720 res = ast_play_and_wait(chan, "vm-nove");
08721 if (vms->newmessages > 4)
08722 res = ast_play_and_wait(chan, "vm-novych");
08723 }
08724 if (vms->oldmessages && !res)
08725 res = ast_play_and_wait(chan, "vm-and");
08726 else if (!res) {
08727 if ((vms->newmessages == 1))
08728 res = ast_play_and_wait(chan, "vm-zpravu");
08729 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08730 res = ast_play_and_wait(chan, "vm-zpravy");
08731 if (vms->newmessages > 4)
08732 res = ast_play_and_wait(chan, "vm-zprav");
08733 }
08734 }
08735 if (!res && vms->oldmessages) {
08736 res = say_and_wait(chan, vms->oldmessages, chan->language);
08737 if (!res) {
08738 if ((vms->oldmessages == 1))
08739 res = ast_play_and_wait(chan, "vm-starou");
08740 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08741 res = ast_play_and_wait(chan, "vm-stare");
08742 if (vms->oldmessages > 4)
08743 res = ast_play_and_wait(chan, "vm-starych");
08744 }
08745 if (!res) {
08746 if ((vms->oldmessages == 1))
08747 res = ast_play_and_wait(chan, "vm-zpravu");
08748 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08749 res = ast_play_and_wait(chan, "vm-zpravy");
08750 if (vms->oldmessages > 4)
08751 res = ast_play_and_wait(chan, "vm-zprav");
08752 }
08753 }
08754 if (!res) {
08755 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08756 res = ast_play_and_wait(chan, "vm-no");
08757 if (!res)
08758 res = ast_play_and_wait(chan, "vm-zpravy");
08759 }
08760 }
08761 }
08762 return res;
08763 }
08764
08765
08766 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08767 {
08768 int res;
08769
08770 res = ast_play_and_wait(chan, "vm-you");
08771
08772 if (!res && vms->newmessages) {
08773 res = ast_play_and_wait(chan, "vm-have");
08774 if (!res)
08775 res = say_and_wait(chan, vms->newmessages, chan->language);
08776 if (!res)
08777 res = ast_play_and_wait(chan, "vm-tong");
08778 if (!res)
08779 res = ast_play_and_wait(chan, "vm-INBOX");
08780 if (vms->oldmessages && !res)
08781 res = ast_play_and_wait(chan, "vm-and");
08782 else if (!res)
08783 res = ast_play_and_wait(chan, "vm-messages");
08784 }
08785 if (!res && vms->oldmessages) {
08786 res = ast_play_and_wait(chan, "vm-have");
08787 if (!res)
08788 res = say_and_wait(chan, vms->oldmessages, chan->language);
08789 if (!res)
08790 res = ast_play_and_wait(chan, "vm-tong");
08791 if (!res)
08792 res = ast_play_and_wait(chan, "vm-Old");
08793 if (!res)
08794 res = ast_play_and_wait(chan, "vm-messages");
08795 }
08796 if (!res && !vms->oldmessages && !vms->newmessages) {
08797 res = ast_play_and_wait(chan, "vm-haveno");
08798 if (!res)
08799 res = ast_play_and_wait(chan, "vm-messages");
08800 }
08801 return res;
08802 }
08803
08804
08805 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08806 {
08807 int res;
08808
08809
08810 res = ast_play_and_wait(chan, "vm-youhave");
08811 if (!res) {
08812 if (vms->newmessages) {
08813 res = say_and_wait(chan, vms->newmessages, chan->language);
08814 if (!res)
08815 res = ast_play_and_wait(chan, "vm-INBOX");
08816 if (vms->oldmessages && !res)
08817 res = ast_play_and_wait(chan, "vm-and");
08818 }
08819 if (!res && vms->oldmessages) {
08820 res = say_and_wait(chan, vms->oldmessages, chan->language);
08821 if (!res)
08822 res = ast_play_and_wait(chan, "vm-Old");
08823 }
08824 if (!res) {
08825 if (!vms->oldmessages && !vms->newmessages) {
08826 res = ast_play_and_wait(chan, "vm-no");
08827 if (!res)
08828 res = ast_play_and_wait(chan, "vm-message");
08829 }
08830 }
08831 }
08832 return res;
08833 }
08834
08835 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08836 {
08837 char prefile[256];
08838
08839
08840 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08841 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08842 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08843 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08844 ast_play_and_wait(chan, "vm-tempgreetactive");
08845 }
08846 DISPOSE(prefile, -1);
08847 }
08848
08849
08850 if (0) {
08851 return 0;
08852 } else if (!strncasecmp(chan->language, "cs", 2)) {
08853 return vm_intro_cs(chan, vms);
08854 } else if (!strncasecmp(chan->language, "cz", 2)) {
08855 static int deprecation_warning = 0;
08856 if (deprecation_warning++ % 10 == 0) {
08857 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
08858 }
08859 return vm_intro_cs(chan, vms);
08860 } else if (!strncasecmp(chan->language, "de", 2)) {
08861 return vm_intro_de(chan, vms);
08862 } else if (!strncasecmp(chan->language, "es", 2)) {
08863 return vm_intro_es(chan, vms);
08864 } else if (!strncasecmp(chan->language, "fr", 2)) {
08865 return vm_intro_fr(chan, vms);
08866 } else if (!strncasecmp(chan->language, "gr", 2)) {
08867 return vm_intro_gr(chan, vms);
08868 } else if (!strncasecmp(chan->language, "he", 2)) {
08869 return vm_intro_he(chan, vms);
08870 } else if (!strncasecmp(chan->language, "it", 2)) {
08871 return vm_intro_it(chan, vms);
08872 } else if (!strncasecmp(chan->language, "nl", 2)) {
08873 return vm_intro_nl(chan, vms);
08874 } else if (!strncasecmp(chan->language, "no", 2)) {
08875 return vm_intro_no(chan, vms);
08876 } else if (!strncasecmp(chan->language, "pl", 2)) {
08877 return vm_intro_pl(chan, vms);
08878 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
08879 return vm_intro_pt_BR(chan, vms);
08880 } else if (!strncasecmp(chan->language, "pt", 2)) {
08881 return vm_intro_pt(chan, vms);
08882 } else if (!strncasecmp(chan->language, "ru", 2)) {
08883 return vm_intro_multilang(chan, vms, "n");
08884 } else if (!strncasecmp(chan->language, "se", 2)) {
08885 return vm_intro_se(chan, vms);
08886 } else if (!strncasecmp(chan->language, "ua", 2)) {
08887 return vm_intro_multilang(chan, vms, "n");
08888 } else if (!strncasecmp(chan->language, "vi", 2)) {
08889 return vm_intro_vi(chan, vms);
08890 } else if (!strncasecmp(chan->language, "zh", 2)) {
08891 return vm_intro_zh(chan, vms);
08892 } else {
08893 return vm_intro_en(chan, vms);
08894 }
08895 }
08896
08897 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08898 {
08899 int res = 0;
08900
08901 while (!res) {
08902 if (vms->starting) {
08903 if (vms->lastmsg > -1) {
08904 if (skipadvanced)
08905 res = ast_play_and_wait(chan, "vm-onefor-full");
08906 else
08907 res = ast_play_and_wait(chan, "vm-onefor");
08908 if (!res)
08909 res = vm_play_folder_name(chan, vms->vmbox);
08910 }
08911 if (!res) {
08912 if (skipadvanced)
08913 res = ast_play_and_wait(chan, "vm-opts-full");
08914 else
08915 res = ast_play_and_wait(chan, "vm-opts");
08916 }
08917 } else {
08918
08919 if (skipadvanced) {
08920 res = ast_play_and_wait(chan, "vm-onefor-full");
08921 if (!res)
08922 res = vm_play_folder_name(chan, vms->vmbox);
08923 res = ast_play_and_wait(chan, "vm-opts-full");
08924 }
08925
08926
08927
08928
08929
08930
08931 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
08932 res = ast_play_and_wait(chan, "vm-prev");
08933 }
08934 if (!res && !skipadvanced)
08935 res = ast_play_and_wait(chan, "vm-advopts");
08936 if (!res)
08937 res = ast_play_and_wait(chan, "vm-repeat");
08938
08939
08940
08941
08942
08943
08944 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
08945 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
08946 res = ast_play_and_wait(chan, "vm-next");
08947 }
08948 if (!res) {
08949 if (!vms->deleted[vms->curmsg])
08950 res = ast_play_and_wait(chan, "vm-delete");
08951 else
08952 res = ast_play_and_wait(chan, "vm-undelete");
08953 if (!res)
08954 res = ast_play_and_wait(chan, "vm-toforward");
08955 if (!res)
08956 res = ast_play_and_wait(chan, "vm-savemessage");
08957 }
08958 }
08959 if (!res) {
08960 res = ast_play_and_wait(chan, "vm-helpexit");
08961 }
08962 if (!res)
08963 res = ast_waitfordigit(chan, 6000);
08964 if (!res) {
08965 vms->repeats++;
08966 if (vms->repeats > 2) {
08967 res = 't';
08968 }
08969 }
08970 }
08971 return res;
08972 }
08973
08974 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08975 {
08976 int res = 0;
08977
08978 while (!res) {
08979 if (vms->lastmsg > -1) {
08980 res = ast_play_and_wait(chan, "vm-listen");
08981 if (!res)
08982 res = vm_play_folder_name(chan, vms->vmbox);
08983 if (!res)
08984 res = ast_play_and_wait(chan, "press");
08985 if (!res)
08986 res = ast_play_and_wait(chan, "digits/1");
08987 }
08988 if (!res)
08989 res = ast_play_and_wait(chan, "vm-opts");
08990 if (!res) {
08991 vms->starting = 0;
08992 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08993 }
08994 }
08995 return res;
08996 }
08997
08998 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08999 {
09000 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09001 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09002 } else {
09003 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09004 }
09005 }
09006
09007
09008 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09009 {
09010 int cmd = 0;
09011 int duration = 0;
09012 int tries = 0;
09013 char newpassword[80] = "";
09014 char newpassword2[80] = "";
09015 char prefile[PATH_MAX] = "";
09016 unsigned char buf[256];
09017 int bytes = 0;
09018
09019 if (ast_adsi_available(chan)) {
09020 bytes += adsi_logo(buf + bytes);
09021 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09022 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09023 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09024 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09025 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09026 }
09027
09028
09029
09030 for (;;) {
09031 newpassword[1] = '\0';
09032 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09033 if (cmd == '#')
09034 newpassword[0] = '\0';
09035 if (cmd < 0 || cmd == 't' || cmd == '#')
09036 return cmd;
09037 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09038 if (cmd < 0 || cmd == 't' || cmd == '#')
09039 return cmd;
09040 cmd = check_password(vmu, newpassword);
09041 if (cmd != 0) {
09042 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09043 cmd = ast_play_and_wait(chan, vm_invalid_password);
09044 } else {
09045 newpassword2[1] = '\0';
09046 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09047 if (cmd == '#')
09048 newpassword2[0] = '\0';
09049 if (cmd < 0 || cmd == 't' || cmd == '#')
09050 return cmd;
09051 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09052 if (cmd < 0 || cmd == 't' || cmd == '#')
09053 return cmd;
09054 if (!strcmp(newpassword, newpassword2))
09055 break;
09056 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09057 cmd = ast_play_and_wait(chan, vm_mismatch);
09058 }
09059 if (++tries == 3)
09060 return -1;
09061 if (cmd != 0) {
09062 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09063 }
09064 }
09065 if (pwdchange & PWDCHANGE_INTERNAL)
09066 vm_change_password(vmu, newpassword);
09067 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09068 vm_change_password_shell(vmu, newpassword);
09069
09070 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09071 cmd = ast_play_and_wait(chan, vm_passchanged);
09072
09073
09074 if (ast_test_flag(vmu, VM_FORCENAME)) {
09075 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09076 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09077 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09078 if (cmd < 0 || cmd == 't' || cmd == '#')
09079 return cmd;
09080 }
09081 }
09082
09083
09084 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09085 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09086 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09087 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09088 if (cmd < 0 || cmd == 't' || cmd == '#')
09089 return cmd;
09090 }
09091
09092 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09093 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09094 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09095 if (cmd < 0 || cmd == 't' || cmd == '#')
09096 return cmd;
09097 }
09098 }
09099
09100 return cmd;
09101 }
09102
09103 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09104 {
09105 int cmd = 0;
09106 int retries = 0;
09107 int duration = 0;
09108 char newpassword[80] = "";
09109 char newpassword2[80] = "";
09110 char prefile[PATH_MAX] = "";
09111 unsigned char buf[256];
09112 int bytes = 0;
09113
09114 if (ast_adsi_available(chan)) {
09115 bytes += adsi_logo(buf + bytes);
09116 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09117 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09118 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09119 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09120 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09121 }
09122 while ((cmd >= 0) && (cmd != 't')) {
09123 if (cmd)
09124 retries = 0;
09125 switch (cmd) {
09126 case '1':
09127 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09128 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09129 break;
09130 case '2':
09131 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09132 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09133 break;
09134 case '3':
09135 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09136 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09137 break;
09138 case '4':
09139 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09140 break;
09141 case '5':
09142 if (vmu->password[0] == '-') {
09143 cmd = ast_play_and_wait(chan, "vm-no");
09144 break;
09145 }
09146 newpassword[1] = '\0';
09147 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09148 if (cmd == '#')
09149 newpassword[0] = '\0';
09150 else {
09151 if (cmd < 0)
09152 break;
09153 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09154 break;
09155 }
09156 }
09157 cmd = check_password(vmu, newpassword);
09158 if (cmd != 0) {
09159 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09160 cmd = ast_play_and_wait(chan, vm_invalid_password);
09161 if (!cmd) {
09162 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09163 }
09164 break;
09165 }
09166 newpassword2[1] = '\0';
09167 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09168 if (cmd == '#')
09169 newpassword2[0] = '\0';
09170 else {
09171 if (cmd < 0)
09172 break;
09173
09174 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09175 break;
09176 }
09177 }
09178 if (strcmp(newpassword, newpassword2)) {
09179 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09180 cmd = ast_play_and_wait(chan, vm_mismatch);
09181 if (!cmd) {
09182 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09183 }
09184 break;
09185 }
09186 if (pwdchange & PWDCHANGE_INTERNAL)
09187 vm_change_password(vmu, newpassword);
09188 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09189 vm_change_password_shell(vmu, newpassword);
09190
09191 ast_debug(1, "User %s set password to %s of length %d\n",
09192 vms->username, newpassword, (int) strlen(newpassword));
09193 cmd = ast_play_and_wait(chan, vm_passchanged);
09194 break;
09195 case '*':
09196 cmd = 't';
09197 break;
09198 default:
09199 cmd = 0;
09200 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09201 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09202 if (ast_fileexists(prefile, NULL, NULL)) {
09203 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09204 }
09205 DISPOSE(prefile, -1);
09206 if (!cmd) {
09207 cmd = ast_play_and_wait(chan, "vm-options");
09208 }
09209 if (!cmd) {
09210 cmd = ast_waitfordigit(chan, 6000);
09211 }
09212 if (!cmd) {
09213 retries++;
09214 }
09215 if (retries > 3) {
09216 cmd = 't';
09217 }
09218 }
09219 }
09220 if (cmd == 't')
09221 cmd = 0;
09222 return cmd;
09223 }
09224
09225
09226
09227
09228
09229
09230
09231
09232
09233
09234
09235
09236
09237
09238
09239
09240
09241 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09242 {
09243 int cmd = 0;
09244 int retries = 0;
09245 int duration = 0;
09246 char prefile[PATH_MAX] = "";
09247 unsigned char buf[256];
09248 int bytes = 0;
09249
09250 if (ast_adsi_available(chan)) {
09251 bytes += adsi_logo(buf + bytes);
09252 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09253 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09254 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09255 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09256 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09257 }
09258
09259 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09260 while ((cmd >= 0) && (cmd != 't')) {
09261 if (cmd)
09262 retries = 0;
09263 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09264 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09265 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09266 cmd = 't';
09267 } else {
09268 switch (cmd) {
09269 case '1':
09270 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09271 break;
09272 case '2':
09273 DELETE(prefile, -1, prefile, vmu);
09274 ast_play_and_wait(chan, "vm-tempremoved");
09275 cmd = 't';
09276 break;
09277 case '*':
09278 cmd = 't';
09279 break;
09280 default:
09281 cmd = ast_play_and_wait(chan,
09282 ast_fileexists(prefile, NULL, NULL) > 0 ?
09283 "vm-tempgreeting2" : "vm-tempgreeting");
09284 if (!cmd)
09285 cmd = ast_waitfordigit(chan, 6000);
09286 if (!cmd)
09287 retries++;
09288 if (retries > 3)
09289 cmd = 't';
09290 }
09291 }
09292 DISPOSE(prefile, -1);
09293 }
09294 if (cmd == 't')
09295 cmd = 0;
09296 return cmd;
09297 }
09298
09299
09300
09301
09302
09303
09304
09305
09306
09307 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09308 {
09309 int cmd = 0;
09310
09311 if (vms->lastmsg > -1) {
09312 cmd = play_message(chan, vmu, vms);
09313 } else {
09314 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09315 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09316 if (!cmd) {
09317 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09318 cmd = ast_play_and_wait(chan, vms->fn);
09319 }
09320 if (!cmd)
09321 cmd = ast_play_and_wait(chan, "vm-messages");
09322 } else {
09323 if (!cmd)
09324 cmd = ast_play_and_wait(chan, "vm-messages");
09325 if (!cmd) {
09326 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09327 cmd = ast_play_and_wait(chan, vms->fn);
09328 }
09329 }
09330 }
09331 return cmd;
09332 }
09333
09334
09335 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09336 {
09337 int cmd = 0;
09338
09339 if (vms->lastmsg > -1) {
09340 cmd = play_message(chan, vmu, vms);
09341 } else {
09342 if (!strcasecmp(vms->fn, "INBOX")) {
09343 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09344 } else {
09345 cmd = ast_play_and_wait(chan, "vm-nomessages");
09346 }
09347 }
09348 return cmd;
09349 }
09350
09351
09352
09353
09354
09355
09356
09357
09358
09359 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09360 {
09361 int cmd = 0;
09362
09363 if (vms->lastmsg > -1) {
09364 cmd = play_message(chan, vmu, vms);
09365 } else {
09366 cmd = ast_play_and_wait(chan, "vm-youhave");
09367 if (!cmd)
09368 cmd = ast_play_and_wait(chan, "vm-no");
09369 if (!cmd) {
09370 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09371 cmd = ast_play_and_wait(chan, vms->fn);
09372 }
09373 if (!cmd)
09374 cmd = ast_play_and_wait(chan, "vm-messages");
09375 }
09376 return cmd;
09377 }
09378
09379
09380
09381
09382
09383
09384
09385
09386
09387 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09388 {
09389 int cmd;
09390
09391 if (vms->lastmsg > -1) {
09392 cmd = play_message(chan, vmu, vms);
09393 } else {
09394 cmd = ast_play_and_wait(chan, "vm-no");
09395 if (!cmd)
09396 cmd = ast_play_and_wait(chan, "vm-message");
09397 if (!cmd) {
09398 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09399 cmd = ast_play_and_wait(chan, vms->fn);
09400 }
09401 }
09402 return cmd;
09403 }
09404
09405
09406
09407
09408
09409
09410
09411
09412
09413 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09414 {
09415 int cmd;
09416
09417 if (vms->lastmsg > -1) {
09418 cmd = play_message(chan, vmu, vms);
09419 } else {
09420 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09421 if (!cmd)
09422 cmd = ast_play_and_wait(chan, "vm-messages");
09423 if (!cmd) {
09424 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09425 cmd = ast_play_and_wait(chan, vms->fn);
09426 }
09427 }
09428 return cmd;
09429 }
09430
09431
09432
09433
09434
09435
09436
09437
09438
09439 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09440 {
09441 int cmd;
09442
09443 if (vms->lastmsg > -1) {
09444 cmd = play_message(chan, vmu, vms);
09445 } else {
09446 cmd = ast_play_and_wait(chan, "vm-no");
09447 if (!cmd) {
09448 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09449 cmd = ast_play_and_wait(chan, vms->fn);
09450 }
09451 if (!cmd)
09452 cmd = ast_play_and_wait(chan, "vm-messages");
09453 }
09454 return cmd;
09455 }
09456
09457
09458
09459
09460
09461
09462
09463
09464
09465 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09466 {
09467 int cmd;
09468
09469 if (vms->lastmsg > -1) {
09470 cmd = play_message(chan, vmu, vms);
09471 } else {
09472 cmd = ast_play_and_wait(chan, "vm-you");
09473 if (!cmd)
09474 cmd = ast_play_and_wait(chan, "vm-haveno");
09475 if (!cmd)
09476 cmd = ast_play_and_wait(chan, "vm-messages");
09477 if (!cmd) {
09478 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09479 cmd = ast_play_and_wait(chan, vms->fn);
09480 }
09481 }
09482 return cmd;
09483 }
09484
09485
09486
09487
09488
09489
09490
09491
09492
09493 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09494 {
09495 int cmd = 0;
09496
09497 if (vms->lastmsg > -1) {
09498 cmd = play_message(chan, vmu, vms);
09499 } else {
09500 cmd = ast_play_and_wait(chan, "vm-no");
09501 if (!cmd) {
09502 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09503 cmd = ast_play_and_wait(chan, vms->fn);
09504 }
09505 }
09506 return cmd;
09507 }
09508
09509
09510
09511
09512
09513
09514
09515
09516
09517
09518
09519
09520 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09521 {
09522 if (!strncasecmp(chan->language, "es", 2)) {
09523 return vm_browse_messages_es(chan, vms, vmu);
09524 } else if (!strncasecmp(chan->language, "gr", 2)) {
09525 return vm_browse_messages_gr(chan, vms, vmu);
09526 } else if (!strncasecmp(chan->language, "he", 2)) {
09527 return vm_browse_messages_he(chan, vms, vmu);
09528 } else if (!strncasecmp(chan->language, "it", 2)) {
09529 return vm_browse_messages_it(chan, vms, vmu);
09530 } else if (!strncasecmp(chan->language, "pt", 2)) {
09531 return vm_browse_messages_pt(chan, vms, vmu);
09532 } else if (!strncasecmp(chan->language, "vi", 2)) {
09533 return vm_browse_messages_vi(chan, vms, vmu);
09534 } else if (!strncasecmp(chan->language, "zh", 2)) {
09535 return vm_browse_messages_zh(chan, vms, vmu);
09536 } else {
09537 return vm_browse_messages_en(chan, vms, vmu);
09538 }
09539 }
09540
09541 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09542 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09543 int skipuser, int max_logins, int silent)
09544 {
09545 int useadsi = 0, valid = 0, logretries = 0;
09546 char password[AST_MAX_EXTENSION]="", *passptr;
09547 struct ast_vm_user vmus, *vmu = NULL;
09548
09549
09550 adsi_begin(chan, &useadsi);
09551 if (!skipuser && useadsi)
09552 adsi_login(chan);
09553 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09554 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09555 return -1;
09556 }
09557
09558
09559
09560 while (!valid && (logretries < max_logins)) {
09561
09562 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09563 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09564 return -1;
09565 }
09566 if (ast_strlen_zero(mailbox)) {
09567 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09568 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09569 } else {
09570 ast_verb(3, "Username not entered\n");
09571 return -1;
09572 }
09573 } else if (mailbox[0] == '*') {
09574
09575 if (ast_exists_extension(chan, chan->context, "a", 1,
09576 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09577 return -1;
09578 }
09579 mailbox[0] = '\0';
09580 }
09581
09582 if (useadsi)
09583 adsi_password(chan);
09584
09585 if (!ast_strlen_zero(prefix)) {
09586 char fullusername[80] = "";
09587 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09588 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09589 ast_copy_string(mailbox, fullusername, mailbox_size);
09590 }
09591
09592 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09593 vmu = find_user(&vmus, context, mailbox);
09594 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09595
09596 password[0] = '\0';
09597 } else {
09598 if (ast_streamfile(chan, vm_password, chan->language)) {
09599 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09600 return -1;
09601 }
09602 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09603 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09604 return -1;
09605 } else if (password[0] == '*') {
09606
09607 if (ast_exists_extension(chan, chan->context, "a", 1,
09608 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09609 mailbox[0] = '*';
09610 return -1;
09611 }
09612 mailbox[0] = '\0';
09613 }
09614 }
09615
09616 if (vmu) {
09617 passptr = vmu->password;
09618 if (passptr[0] == '-') passptr++;
09619 }
09620 if (vmu && !strcmp(passptr, password))
09621 valid++;
09622 else {
09623 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09624 if (!ast_strlen_zero(prefix))
09625 mailbox[0] = '\0';
09626 }
09627 logretries++;
09628 if (!valid) {
09629 if (skipuser || logretries >= max_logins) {
09630 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09631 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09632 return -1;
09633 }
09634 } else {
09635 if (useadsi)
09636 adsi_login(chan);
09637 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09638 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09639 return -1;
09640 }
09641 }
09642 if (ast_waitstream(chan, ""))
09643 return -1;
09644 }
09645 }
09646 if (!valid && (logretries >= max_logins)) {
09647 ast_stopstream(chan);
09648 ast_play_and_wait(chan, "vm-goodbye");
09649 return -1;
09650 }
09651 if (vmu && !skipuser) {
09652 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09653 }
09654 return 0;
09655 }
09656
09657 static int vm_execmain(struct ast_channel *chan, const char *data)
09658 {
09659
09660
09661
09662 int res = -1;
09663 int cmd = 0;
09664 int valid = 0;
09665 char prefixstr[80] ="";
09666 char ext_context[256]="";
09667 int box;
09668 int useadsi = 0;
09669 int skipuser = 0;
09670 struct vm_state vms;
09671 struct ast_vm_user *vmu = NULL, vmus;
09672 char *context = NULL;
09673 int silentexit = 0;
09674 struct ast_flags flags = { 0 };
09675 signed char record_gain = 0;
09676 int play_auto = 0;
09677 int play_folder = 0;
09678 int in_urgent = 0;
09679 #ifdef IMAP_STORAGE
09680 int deleted = 0;
09681 #endif
09682
09683
09684 memset(&vms, 0, sizeof(vms));
09685
09686 vms.lastmsg = -1;
09687
09688 memset(&vmus, 0, sizeof(vmus));
09689
09690 if (chan->_state != AST_STATE_UP) {
09691 ast_debug(1, "Before ast_answer\n");
09692 ast_answer(chan);
09693 }
09694
09695 if (!ast_strlen_zero(data)) {
09696 char *opts[OPT_ARG_ARRAY_SIZE];
09697 char *parse;
09698 AST_DECLARE_APP_ARGS(args,
09699 AST_APP_ARG(argv0);
09700 AST_APP_ARG(argv1);
09701 );
09702
09703 parse = ast_strdupa(data);
09704
09705 AST_STANDARD_APP_ARGS(args, parse);
09706
09707 if (args.argc == 2) {
09708 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09709 return -1;
09710 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09711 int gain;
09712 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09713 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09714 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09715 return -1;
09716 } else {
09717 record_gain = (signed char) gain;
09718 }
09719 } else {
09720 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09721 }
09722 }
09723 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09724 play_auto = 1;
09725 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09726
09727 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09728 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09729 play_folder = -1;
09730 }
09731 } else {
09732 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09733 }
09734 } else {
09735 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09736 }
09737 if (play_folder > 9 || play_folder < 0) {
09738 ast_log(AST_LOG_WARNING,
09739 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09740 opts[OPT_ARG_PLAYFOLDER]);
09741 play_folder = 0;
09742 }
09743 }
09744 } else {
09745
09746 while (*(args.argv0)) {
09747 if (*(args.argv0) == 's')
09748 ast_set_flag(&flags, OPT_SILENT);
09749 else if (*(args.argv0) == 'p')
09750 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09751 else
09752 break;
09753 (args.argv0)++;
09754 }
09755
09756 }
09757
09758 valid = ast_test_flag(&flags, OPT_SILENT);
09759
09760 if ((context = strchr(args.argv0, '@')))
09761 *context++ = '\0';
09762
09763 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09764 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09765 else
09766 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09767
09768 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09769 skipuser++;
09770 else
09771 valid = 0;
09772 }
09773
09774 if (!valid)
09775 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09776
09777 ast_debug(1, "After vm_authenticate\n");
09778
09779 if (vms.username[0] == '*') {
09780 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09781
09782
09783 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09784 res = 0;
09785 goto out;
09786 }
09787 }
09788
09789 if (!res) {
09790 valid = 1;
09791 if (!skipuser)
09792 vmu = &vmus;
09793 } else {
09794 res = 0;
09795 }
09796
09797
09798 adsi_begin(chan, &useadsi);
09799
09800 if (!valid) {
09801 goto out;
09802 }
09803
09804 #ifdef IMAP_STORAGE
09805 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
09806 pthread_setspecific(ts_vmstate.key, &vms);
09807
09808 vms.interactive = 1;
09809 vms.updated = 1;
09810 if (vmu)
09811 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
09812 vmstate_insert(&vms);
09813 init_vm_state(&vms);
09814 #endif
09815
09816 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09817 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
09818 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09819 return -1;
09820 }
09821 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09822 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
09823 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09824 return -1;
09825 }
09826
09827
09828 if (!ast_strlen_zero(vmu->language))
09829 ast_string_field_set(chan, language, vmu->language);
09830
09831
09832 ast_debug(1, "Before open_mailbox\n");
09833 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09834 if (res < 0)
09835 goto out;
09836 vms.oldmessages = vms.lastmsg + 1;
09837 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
09838
09839 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09840 if (res < 0)
09841 goto out;
09842 vms.newmessages = vms.lastmsg + 1;
09843 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
09844
09845 in_urgent = 1;
09846 res = open_mailbox(&vms, vmu, 11);
09847 if (res < 0)
09848 goto out;
09849 vms.urgentmessages = vms.lastmsg + 1;
09850 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
09851
09852
09853 if (play_auto) {
09854 if (vms.urgentmessages) {
09855 in_urgent = 1;
09856 res = open_mailbox(&vms, vmu, 11);
09857 } else {
09858 in_urgent = 0;
09859 res = open_mailbox(&vms, vmu, play_folder);
09860 }
09861 if (res < 0)
09862 goto out;
09863
09864
09865 if (vms.lastmsg == -1) {
09866 in_urgent = 0;
09867 cmd = vm_browse_messages(chan, &vms, vmu);
09868 res = 0;
09869 goto out;
09870 }
09871 } else {
09872 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
09873
09874 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09875 in_urgent = 0;
09876 play_folder = 1;
09877 if (res < 0)
09878 goto out;
09879 } else if (!vms.urgentmessages && vms.newmessages) {
09880
09881 in_urgent = 0;
09882 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09883 if (res < 0)
09884 goto out;
09885 }
09886 }
09887
09888 if (useadsi)
09889 adsi_status(chan, &vms);
09890 res = 0;
09891
09892
09893 if (!strcasecmp(vmu->mailbox, vmu->password) &&
09894 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
09895 if (ast_play_and_wait(chan, "vm-newuser") == -1)
09896 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
09897 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
09898 if ((cmd == 't') || (cmd == '#')) {
09899
09900 res = 0;
09901 goto out;
09902 } else if (cmd < 0) {
09903
09904 res = -1;
09905 goto out;
09906 }
09907 }
09908 #ifdef IMAP_STORAGE
09909 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
09910 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
09911 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
09912 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09913 }
09914 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09915 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
09916 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09917 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09918 }
09919 #endif
09920 if (play_auto) {
09921 cmd = '1';
09922 } else {
09923 cmd = vm_intro(chan, vmu, &vms);
09924 }
09925
09926 vms.repeats = 0;
09927 vms.starting = 1;
09928 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09929
09930 switch (cmd) {
09931 case '1':
09932 vms.curmsg = 0;
09933
09934 case '5':
09935 cmd = vm_browse_messages(chan, &vms, vmu);
09936 break;
09937 case '2':
09938 if (useadsi)
09939 adsi_folders(chan, 0, "Change to folder...");
09940 cmd = get_folder2(chan, "vm-changeto", 0);
09941 if (cmd == '#') {
09942 cmd = 0;
09943 } else if (cmd > 0) {
09944 cmd = cmd - '0';
09945 res = close_mailbox(&vms, vmu);
09946 if (res == ERROR_LOCK_PATH)
09947 goto out;
09948
09949 if (cmd != 11) in_urgent = 0;
09950 res = open_mailbox(&vms, vmu, cmd);
09951 if (res < 0)
09952 goto out;
09953 play_folder = cmd;
09954 cmd = 0;
09955 }
09956 if (useadsi)
09957 adsi_status2(chan, &vms);
09958
09959 if (!cmd)
09960 cmd = vm_play_folder_name(chan, vms.vmbox);
09961
09962 vms.starting = 1;
09963 break;
09964 case '3':
09965 cmd = 0;
09966 vms.repeats = 0;
09967 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09968 switch (cmd) {
09969 case '1':
09970 if (vms.lastmsg > -1 && !vms.starting) {
09971 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
09972 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09973 res = cmd;
09974 goto out;
09975 }
09976 } else
09977 cmd = ast_play_and_wait(chan, "vm-sorry");
09978 cmd = 't';
09979 break;
09980 case '2':
09981 if (!vms.starting)
09982 ast_verb(3, "Callback Requested\n");
09983 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
09984 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
09985 if (cmd == 9) {
09986 silentexit = 1;
09987 goto out;
09988 } else if (cmd == ERROR_LOCK_PATH) {
09989 res = cmd;
09990 goto out;
09991 }
09992 } else
09993 cmd = ast_play_and_wait(chan, "vm-sorry");
09994 cmd = 't';
09995 break;
09996 case '3':
09997 if (vms.lastmsg > -1 && !vms.starting) {
09998 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
09999 if (cmd == ERROR_LOCK_PATH) {
10000 res = cmd;
10001 goto out;
10002 }
10003 } else
10004 cmd = ast_play_and_wait(chan, "vm-sorry");
10005 cmd = 't';
10006 break;
10007 case '4':
10008 if (!ast_strlen_zero(vmu->dialout)) {
10009 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10010 if (cmd == 9) {
10011 silentexit = 1;
10012 goto out;
10013 }
10014 } else
10015 cmd = ast_play_and_wait(chan, "vm-sorry");
10016 cmd = 't';
10017 break;
10018
10019 case '5':
10020 if (ast_test_flag(vmu, VM_SVMAIL)) {
10021 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10022 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10023 res = cmd;
10024 goto out;
10025 }
10026 } else
10027 cmd = ast_play_and_wait(chan, "vm-sorry");
10028 cmd = 't';
10029 break;
10030
10031 case '*':
10032 cmd = 't';
10033 break;
10034
10035 default:
10036 cmd = 0;
10037 if (!vms.starting) {
10038 cmd = ast_play_and_wait(chan, "vm-toreply");
10039 }
10040 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10041 cmd = ast_play_and_wait(chan, "vm-tocallback");
10042 }
10043 if (!cmd && !vms.starting) {
10044 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10045 }
10046 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10047 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10048 }
10049 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
10050 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10051 if (!cmd)
10052 cmd = ast_play_and_wait(chan, "vm-starmain");
10053 if (!cmd)
10054 cmd = ast_waitfordigit(chan, 6000);
10055 if (!cmd)
10056 vms.repeats++;
10057 if (vms.repeats > 3)
10058 cmd = 't';
10059 }
10060 }
10061 if (cmd == 't') {
10062 cmd = 0;
10063 vms.repeats = 0;
10064 }
10065 break;
10066 case '4':
10067 if (vms.curmsg > 0) {
10068 vms.curmsg--;
10069 cmd = play_message(chan, vmu, &vms);
10070 } else {
10071
10072
10073
10074
10075 if (in_urgent == 0 && vms.urgentmessages > 0) {
10076
10077 in_urgent = 1;
10078 res = close_mailbox(&vms, vmu);
10079 if (res == ERROR_LOCK_PATH)
10080 goto out;
10081 res = open_mailbox(&vms, vmu, 11);
10082 if (res < 0)
10083 goto out;
10084 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10085 vms.curmsg = vms.lastmsg;
10086 if (vms.lastmsg < 0)
10087 cmd = ast_play_and_wait(chan, "vm-nomore");
10088 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10089 vms.curmsg = vms.lastmsg;
10090 cmd = play_message(chan, vmu, &vms);
10091 } else {
10092 cmd = ast_play_and_wait(chan, "vm-nomore");
10093 }
10094 }
10095 break;
10096 case '6':
10097 if (vms.curmsg < vms.lastmsg) {
10098 vms.curmsg++;
10099 cmd = play_message(chan, vmu, &vms);
10100 } else {
10101 if (in_urgent && vms.newmessages > 0) {
10102
10103
10104
10105
10106 in_urgent = 0;
10107 res = close_mailbox(&vms, vmu);
10108 if (res == ERROR_LOCK_PATH)
10109 goto out;
10110 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10111 if (res < 0)
10112 goto out;
10113 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10114 vms.curmsg = -1;
10115 if (vms.lastmsg < 0) {
10116 cmd = ast_play_and_wait(chan, "vm-nomore");
10117 }
10118 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10119 vms.curmsg = 0;
10120 cmd = play_message(chan, vmu, &vms);
10121 } else {
10122 cmd = ast_play_and_wait(chan, "vm-nomore");
10123 }
10124 }
10125 break;
10126 case '7':
10127 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10128 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10129 if (useadsi)
10130 adsi_delete(chan, &vms);
10131 if (vms.deleted[vms.curmsg]) {
10132 if (play_folder == 0) {
10133 if (in_urgent) {
10134 vms.urgentmessages--;
10135 } else {
10136 vms.newmessages--;
10137 }
10138 }
10139 else if (play_folder == 1)
10140 vms.oldmessages--;
10141 cmd = ast_play_and_wait(chan, "vm-deleted");
10142 } else {
10143 if (play_folder == 0) {
10144 if (in_urgent) {
10145 vms.urgentmessages++;
10146 } else {
10147 vms.newmessages++;
10148 }
10149 }
10150 else if (play_folder == 1)
10151 vms.oldmessages++;
10152 cmd = ast_play_and_wait(chan, "vm-undeleted");
10153 }
10154 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10155 if (vms.curmsg < vms.lastmsg) {
10156 vms.curmsg++;
10157 cmd = play_message(chan, vmu, &vms);
10158 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10159 vms.curmsg = 0;
10160 cmd = play_message(chan, vmu, &vms);
10161 } else {
10162
10163
10164
10165
10166 if (in_urgent == 1) {
10167
10168 in_urgent = 0;
10169 res = close_mailbox(&vms, vmu);
10170 if (res == ERROR_LOCK_PATH)
10171 goto out;
10172 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10173 if (res < 0)
10174 goto out;
10175 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10176 vms.curmsg = -1;
10177 if (vms.lastmsg < 0)
10178 cmd = ast_play_and_wait(chan, "vm-nomore");
10179 } else {
10180 cmd = ast_play_and_wait(chan, "vm-nomore");
10181 }
10182 }
10183 }
10184 } else
10185 cmd = 0;
10186 #ifdef IMAP_STORAGE
10187 deleted = 1;
10188 #endif
10189 break;
10190
10191 case '8':
10192 if (vms.lastmsg > -1) {
10193 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10194 if (cmd == ERROR_LOCK_PATH) {
10195 res = cmd;
10196 goto out;
10197 }
10198 } else {
10199
10200
10201
10202
10203 if (in_urgent == 1 && vms.newmessages > 0) {
10204
10205 in_urgent = 0;
10206 res = close_mailbox(&vms, vmu);
10207 if (res == ERROR_LOCK_PATH)
10208 goto out;
10209 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10210 if (res < 0)
10211 goto out;
10212 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10213 vms.curmsg = -1;
10214 if (vms.lastmsg < 0)
10215 cmd = ast_play_and_wait(chan, "vm-nomore");
10216 } else {
10217 cmd = ast_play_and_wait(chan, "vm-nomore");
10218 }
10219 }
10220 break;
10221 case '9':
10222 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10223
10224 cmd = 0;
10225 break;
10226 }
10227 if (useadsi)
10228 adsi_folders(chan, 1, "Save to folder...");
10229 cmd = get_folder2(chan, "vm-savefolder", 1);
10230 box = 0;
10231 if (cmd == '#') {
10232 cmd = 0;
10233 break;
10234 } else if (cmd > 0) {
10235 box = cmd = cmd - '0';
10236 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10237 if (cmd == ERROR_LOCK_PATH) {
10238 res = cmd;
10239 goto out;
10240 #ifndef IMAP_STORAGE
10241 } else if (!cmd) {
10242 vms.deleted[vms.curmsg] = 1;
10243 #endif
10244 } else {
10245 vms.deleted[vms.curmsg] = 0;
10246 vms.heard[vms.curmsg] = 0;
10247 }
10248 }
10249 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10250 if (useadsi)
10251 adsi_message(chan, &vms);
10252 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10253 if (!cmd) {
10254 cmd = ast_play_and_wait(chan, "vm-message");
10255 if (!cmd)
10256 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10257 if (!cmd)
10258 cmd = ast_play_and_wait(chan, "vm-savedto");
10259 if (!cmd)
10260 cmd = vm_play_folder_name(chan, vms.fn);
10261 } else {
10262 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10263 }
10264 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10265 if (vms.curmsg < vms.lastmsg) {
10266 vms.curmsg++;
10267 cmd = play_message(chan, vmu, &vms);
10268 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10269 vms.curmsg = 0;
10270 cmd = play_message(chan, vmu, &vms);
10271 } else {
10272
10273
10274
10275
10276 if (in_urgent == 1 && vms.newmessages > 0) {
10277
10278 in_urgent = 0;
10279 res = close_mailbox(&vms, vmu);
10280 if (res == ERROR_LOCK_PATH)
10281 goto out;
10282 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10283 if (res < 0)
10284 goto out;
10285 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10286 vms.curmsg = -1;
10287 if (vms.lastmsg < 0)
10288 cmd = ast_play_and_wait(chan, "vm-nomore");
10289 } else {
10290 cmd = ast_play_and_wait(chan, "vm-nomore");
10291 }
10292 }
10293 }
10294 break;
10295 case '*':
10296 if (!vms.starting) {
10297 cmd = ast_play_and_wait(chan, "vm-onefor");
10298 if (!strncasecmp(chan->language, "he", 2)) {
10299 cmd = ast_play_and_wait(chan, "vm-for");
10300 }
10301 if (!cmd)
10302 cmd = vm_play_folder_name(chan, vms.vmbox);
10303 if (!cmd)
10304 cmd = ast_play_and_wait(chan, "vm-opts");
10305 if (!cmd)
10306 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10307 } else
10308 cmd = 0;
10309 break;
10310 case '0':
10311 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10312 if (useadsi)
10313 adsi_status(chan, &vms);
10314 break;
10315 default:
10316 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10317 break;
10318 }
10319 }
10320 if ((cmd == 't') || (cmd == '#')) {
10321
10322 res = 0;
10323 } else {
10324
10325 res = -1;
10326 }
10327
10328 out:
10329 if (res > -1) {
10330 ast_stopstream(chan);
10331 adsi_goodbye(chan);
10332 if (valid && res != OPERATOR_EXIT) {
10333 if (silentexit)
10334 res = ast_play_and_wait(chan, "vm-dialout");
10335 else
10336 res = ast_play_and_wait(chan, "vm-goodbye");
10337 }
10338 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10339 res = 0;
10340 }
10341 if (useadsi)
10342 ast_adsi_unload_session(chan);
10343 }
10344 if (vmu)
10345 close_mailbox(&vms, vmu);
10346 if (valid) {
10347 int new = 0, old = 0, urgent = 0;
10348 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10349 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10350
10351 run_externnotify(vmu->context, vmu->mailbox, NULL);
10352 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10353 queue_mwi_event(ext_context, urgent, new, old);
10354 }
10355 #ifdef IMAP_STORAGE
10356
10357 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10358 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10359 ast_mutex_lock(&vms.lock);
10360 #ifdef HAVE_IMAP_TK2006
10361 if (LEVELUIDPLUS (vms.mailstream)) {
10362 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10363 } else
10364 #endif
10365 mail_expunge(vms.mailstream);
10366 ast_mutex_unlock(&vms.lock);
10367 }
10368
10369
10370 if (vmu) {
10371 vmstate_delete(&vms);
10372 }
10373 #endif
10374 if (vmu)
10375 free_user(vmu);
10376 if (vms.deleted)
10377 ast_free(vms.deleted);
10378 if (vms.heard)
10379 ast_free(vms.heard);
10380
10381 #ifdef IMAP_STORAGE
10382 pthread_setspecific(ts_vmstate.key, NULL);
10383 #endif
10384 return res;
10385 }
10386
10387 static int vm_exec(struct ast_channel *chan, const char *data)
10388 {
10389 int res = 0;
10390 char *tmp;
10391 struct leave_vm_options leave_options;
10392 struct ast_flags flags = { 0 };
10393 char *opts[OPT_ARG_ARRAY_SIZE];
10394 AST_DECLARE_APP_ARGS(args,
10395 AST_APP_ARG(argv0);
10396 AST_APP_ARG(argv1);
10397 );
10398
10399 memset(&leave_options, 0, sizeof(leave_options));
10400
10401 if (chan->_state != AST_STATE_UP)
10402 ast_answer(chan);
10403
10404 if (!ast_strlen_zero(data)) {
10405 tmp = ast_strdupa(data);
10406 AST_STANDARD_APP_ARGS(args, tmp);
10407 if (args.argc == 2) {
10408 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10409 return -1;
10410 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10411 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10412 int gain;
10413
10414 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10415 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10416 return -1;
10417 } else {
10418 leave_options.record_gain = (signed char) gain;
10419 }
10420 }
10421 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10422 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10423 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10424 }
10425 }
10426 } else {
10427 char temp[256];
10428 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10429 if (res < 0)
10430 return res;
10431 if (ast_strlen_zero(temp))
10432 return 0;
10433 args.argv0 = ast_strdupa(temp);
10434 }
10435
10436 res = leave_voicemail(chan, args.argv0, &leave_options);
10437 if (res == 't') {
10438 ast_play_and_wait(chan, "vm-goodbye");
10439 res = 0;
10440 }
10441
10442 if (res == OPERATOR_EXIT) {
10443 res = 0;
10444 }
10445
10446 if (res == ERROR_LOCK_PATH) {
10447 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10448 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10449 res = 0;
10450 }
10451
10452 return res;
10453 }
10454
10455 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10456 {
10457 struct ast_vm_user *vmu;
10458
10459 AST_LIST_TRAVERSE(&users, vmu, list) {
10460 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10461 if (strcasecmp(vmu->context, context)) {
10462 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10463 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10464 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10465 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10466 }
10467 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10468 return NULL;
10469 }
10470 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10471 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10472 return NULL;
10473 }
10474 }
10475
10476 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10477 return NULL;
10478
10479 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10480 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10481
10482 AST_LIST_INSERT_TAIL(&users, vmu, list);
10483
10484 return vmu;
10485 }
10486
10487 static int append_mailbox(const char *context, const char *box, const char *data)
10488 {
10489
10490 char *tmp;
10491 char *stringp;
10492 char *s;
10493 struct ast_vm_user *vmu;
10494 char *mailbox_full;
10495 int new = 0, old = 0, urgent = 0;
10496 char secretfn[PATH_MAX] = "";
10497
10498 tmp = ast_strdupa(data);
10499
10500 if (!(vmu = find_or_create(context, box)))
10501 return -1;
10502
10503 populate_defaults(vmu);
10504
10505 stringp = tmp;
10506 if ((s = strsep(&stringp, ","))) {
10507 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10508 }
10509 if (stringp && (s = strsep(&stringp, ","))) {
10510 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10511 }
10512 if (stringp && (s = strsep(&stringp, ","))) {
10513 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10514 }
10515 if (stringp && (s = strsep(&stringp, ","))) {
10516 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10517 }
10518 if (stringp && (s = strsep(&stringp, ","))) {
10519 apply_options(vmu, s);
10520 }
10521
10522 switch (vmu->passwordlocation) {
10523 case OPT_PWLOC_SPOOLDIR:
10524 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10525 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10526 }
10527
10528 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10529 strcpy(mailbox_full, box);
10530 strcat(mailbox_full, "@");
10531 strcat(mailbox_full, context);
10532
10533 inboxcount2(mailbox_full, &urgent, &new, &old);
10534 queue_mwi_event(mailbox_full, urgent, new, old);
10535
10536 return 0;
10537 }
10538
10539 AST_TEST_DEFINE(test_voicemail_vmuser)
10540 {
10541 int res = 0;
10542 struct ast_vm_user *vmu;
10543
10544 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10545 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10546 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10547 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10548 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10549 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10550 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir";
10551 #ifdef IMAP_STORAGE
10552 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10553 "imapfolder=INBOX|imapvmshareid=6000";
10554 #endif
10555
10556 switch (cmd) {
10557 case TEST_INIT:
10558 info->name = "vmuser";
10559 info->category = "/apps/app_voicemail/";
10560 info->summary = "Vmuser unit test";
10561 info->description =
10562 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10563 return AST_TEST_NOT_RUN;
10564 case TEST_EXECUTE:
10565 break;
10566 }
10567
10568 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10569 return AST_TEST_NOT_RUN;
10570 }
10571 ast_set_flag(vmu, VM_ALLOCED);
10572
10573 apply_options(vmu, options_string);
10574
10575 if (!ast_test_flag(vmu, VM_ATTACH)) {
10576 ast_test_status_update(test, "Parse failure for attach option\n");
10577 res = 1;
10578 }
10579 if (strcasecmp(vmu->attachfmt, "wav49")) {
10580 ast_test_status_update(test, "Parse failure for attachftm option\n");
10581 res = 1;
10582 }
10583 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10584 ast_test_status_update(test, "Parse failure for serveremail option\n");
10585 res = 1;
10586 }
10587 if (strcasecmp(vmu->zonetag, "central")) {
10588 ast_test_status_update(test, "Parse failure for tz option\n");
10589 res = 1;
10590 }
10591 if (!ast_test_flag(vmu, VM_DELETE)) {
10592 ast_test_status_update(test, "Parse failure for delete option\n");
10593 res = 1;
10594 }
10595 if (!ast_test_flag(vmu, VM_SAYCID)) {
10596 ast_test_status_update(test, "Parse failure for saycid option\n");
10597 res = 1;
10598 }
10599 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10600 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10601 res = 1;
10602 }
10603 if (!ast_test_flag(vmu, VM_REVIEW)) {
10604 ast_test_status_update(test, "Parse failure for review option\n");
10605 res = 1;
10606 }
10607 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10608 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10609 res = 1;
10610 }
10611 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10612 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10613 res = 1;
10614 }
10615 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10616 ast_test_status_update(test, "Parse failure for operator option\n");
10617 res = 1;
10618 }
10619 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10620 ast_test_status_update(test, "Parse failure for envelope option\n");
10621 res = 1;
10622 }
10623 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10624 ast_test_status_update(test, "Parse failure for moveheard option\n");
10625 res = 1;
10626 }
10627 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10628 ast_test_status_update(test, "Parse failure for sayduration option\n");
10629 res = 1;
10630 }
10631 if (vmu->saydurationm != 5) {
10632 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10633 res = 1;
10634 }
10635 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10636 ast_test_status_update(test, "Parse failure for forcename option\n");
10637 res = 1;
10638 }
10639 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10640 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10641 res = 1;
10642 }
10643 if (strcasecmp(vmu->callback, "somecontext")) {
10644 ast_test_status_update(test, "Parse failure for callbacks option\n");
10645 res = 1;
10646 }
10647 if (strcasecmp(vmu->dialout, "somecontext2")) {
10648 ast_test_status_update(test, "Parse failure for dialout option\n");
10649 res = 1;
10650 }
10651 if (strcasecmp(vmu->exit, "somecontext3")) {
10652 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10653 res = 1;
10654 }
10655 if (vmu->minsecs != 10) {
10656 ast_test_status_update(test, "Parse failure for minsecs option\n");
10657 res = 1;
10658 }
10659 if (vmu->maxsecs != 100) {
10660 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10661 res = 1;
10662 }
10663 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10664 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10665 res = 1;
10666 }
10667 if (vmu->maxdeletedmsg != 50) {
10668 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10669 res = 1;
10670 }
10671 if (vmu->volgain != 1.3) {
10672 ast_test_status_update(test, "Parse failure for volgain option\n");
10673 res = 1;
10674 }
10675 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10676 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10677 res = 1;
10678 }
10679 #ifdef IMAP_STORAGE
10680 apply_options(vmu, option_string2);
10681
10682 if (strcasecmp(vmu->imapuser, "imapuser")) {
10683 ast_test_status_update(test, "Parse failure for imapuser option\n");
10684 res = 1;
10685 }
10686 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10687 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10688 res = 1;
10689 }
10690 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10691 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10692 res = 1;
10693 }
10694 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10695 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10696 res = 1;
10697 }
10698 #endif
10699
10700 free_user(vmu);
10701 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10702 }
10703
10704 static int vm_box_exists(struct ast_channel *chan, const char *data)
10705 {
10706 struct ast_vm_user svm;
10707 char *context, *box;
10708 AST_DECLARE_APP_ARGS(args,
10709 AST_APP_ARG(mbox);
10710 AST_APP_ARG(options);
10711 );
10712 static int dep_warning = 0;
10713
10714 if (ast_strlen_zero(data)) {
10715 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10716 return -1;
10717 }
10718
10719 if (!dep_warning) {
10720 dep_warning = 1;
10721 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10722 }
10723
10724 box = ast_strdupa(data);
10725
10726 AST_STANDARD_APP_ARGS(args, box);
10727
10728 if (args.options) {
10729 }
10730
10731 if ((context = strchr(args.mbox, '@'))) {
10732 *context = '\0';
10733 context++;
10734 }
10735
10736 if (find_user(&svm, context, args.mbox)) {
10737 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10738 } else
10739 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10740
10741 return 0;
10742 }
10743
10744 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10745 {
10746 struct ast_vm_user svm;
10747 AST_DECLARE_APP_ARGS(arg,
10748 AST_APP_ARG(mbox);
10749 AST_APP_ARG(context);
10750 );
10751
10752 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
10753
10754 if (ast_strlen_zero(arg.mbox)) {
10755 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
10756 return -1;
10757 }
10758
10759 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
10760 return 0;
10761 }
10762
10763 static struct ast_custom_function mailbox_exists_acf = {
10764 .name = "MAILBOX_EXISTS",
10765 .read = acf_mailbox_exists,
10766 };
10767
10768 static int vmauthenticate(struct ast_channel *chan, const char *data)
10769 {
10770 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
10771 struct ast_vm_user vmus;
10772 char *options = NULL;
10773 int silent = 0, skipuser = 0;
10774 int res = -1;
10775
10776 if (data) {
10777 s = ast_strdupa(data);
10778 user = strsep(&s, ",");
10779 options = strsep(&s, ",");
10780 if (user) {
10781 s = user;
10782 user = strsep(&s, "@");
10783 context = strsep(&s, "");
10784 if (!ast_strlen_zero(user))
10785 skipuser++;
10786 ast_copy_string(mailbox, user, sizeof(mailbox));
10787 }
10788 }
10789
10790 if (options) {
10791 silent = (strchr(options, 's')) != NULL;
10792 }
10793
10794 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
10795 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
10796 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
10797 ast_play_and_wait(chan, "auth-thankyou");
10798 res = 0;
10799 } else if (mailbox[0] == '*') {
10800
10801 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10802 res = 0;
10803 }
10804 }
10805
10806 return res;
10807 }
10808
10809 static char *show_users_realtime(int fd, const char *context)
10810 {
10811 struct ast_config *cfg;
10812 const char *cat = NULL;
10813
10814 if (!(cfg = ast_load_realtime_multientry("voicemail",
10815 "context", context, SENTINEL))) {
10816 return CLI_FAILURE;
10817 }
10818
10819 ast_cli(fd,
10820 "\n"
10821 "=============================================================\n"
10822 "=== Configured Voicemail Users ==============================\n"
10823 "=============================================================\n"
10824 "===\n");
10825
10826 while ((cat = ast_category_browse(cfg, cat))) {
10827 struct ast_variable *var = NULL;
10828 ast_cli(fd,
10829 "=== Mailbox ...\n"
10830 "===\n");
10831 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
10832 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
10833 ast_cli(fd,
10834 "===\n"
10835 "=== ---------------------------------------------------------\n"
10836 "===\n");
10837 }
10838
10839 ast_cli(fd,
10840 "=============================================================\n"
10841 "\n");
10842
10843 ast_config_destroy(cfg);
10844
10845 return CLI_SUCCESS;
10846 }
10847
10848 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
10849 {
10850 int which = 0;
10851 int wordlen;
10852 struct ast_vm_user *vmu;
10853 const char *context = "";
10854
10855
10856 if (pos > 4)
10857 return NULL;
10858 if (pos == 3)
10859 return (state == 0) ? ast_strdup("for") : NULL;
10860 wordlen = strlen(word);
10861 AST_LIST_TRAVERSE(&users, vmu, list) {
10862 if (!strncasecmp(word, vmu->context, wordlen)) {
10863 if (context && strcmp(context, vmu->context) && ++which > state)
10864 return ast_strdup(vmu->context);
10865
10866 context = vmu->context;
10867 }
10868 }
10869 return NULL;
10870 }
10871
10872
10873 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10874 {
10875 struct ast_vm_user *vmu;
10876 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
10877 const char *context = NULL;
10878 int users_counter = 0;
10879
10880 switch (cmd) {
10881 case CLI_INIT:
10882 e->command = "voicemail show users";
10883 e->usage =
10884 "Usage: voicemail show users [for <context>]\n"
10885 " Lists all mailboxes currently set up\n";
10886 return NULL;
10887 case CLI_GENERATE:
10888 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
10889 }
10890
10891 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
10892 return CLI_SHOWUSAGE;
10893 if (a->argc == 5) {
10894 if (strcmp(a->argv[3],"for"))
10895 return CLI_SHOWUSAGE;
10896 context = a->argv[4];
10897 }
10898
10899 if (ast_check_realtime("voicemail")) {
10900 if (!context) {
10901 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
10902 return CLI_SHOWUSAGE;
10903 }
10904 return show_users_realtime(a->fd, context);
10905 }
10906
10907 AST_LIST_LOCK(&users);
10908 if (AST_LIST_EMPTY(&users)) {
10909 ast_cli(a->fd, "There are no voicemail users currently defined\n");
10910 AST_LIST_UNLOCK(&users);
10911 return CLI_FAILURE;
10912 }
10913 if (a->argc == 3)
10914 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10915 else {
10916 int count = 0;
10917 AST_LIST_TRAVERSE(&users, vmu, list) {
10918 if (!strcmp(context, vmu->context))
10919 count++;
10920 }
10921 if (count) {
10922 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10923 } else {
10924 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
10925 AST_LIST_UNLOCK(&users);
10926 return CLI_FAILURE;
10927 }
10928 }
10929 AST_LIST_TRAVERSE(&users, vmu, list) {
10930 int newmsgs = 0, oldmsgs = 0;
10931 char count[12], tmp[256] = "";
10932
10933 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
10934 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
10935 inboxcount(tmp, &newmsgs, &oldmsgs);
10936 snprintf(count, sizeof(count), "%d", newmsgs);
10937 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
10938 users_counter++;
10939 }
10940 }
10941 AST_LIST_UNLOCK(&users);
10942 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
10943 return CLI_SUCCESS;
10944 }
10945
10946
10947 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10948 {
10949 struct vm_zone *zone;
10950 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
10951 char *res = CLI_SUCCESS;
10952
10953 switch (cmd) {
10954 case CLI_INIT:
10955 e->command = "voicemail show zones";
10956 e->usage =
10957 "Usage: voicemail show zones\n"
10958 " Lists zone message formats\n";
10959 return NULL;
10960 case CLI_GENERATE:
10961 return NULL;
10962 }
10963
10964 if (a->argc != 3)
10965 return CLI_SHOWUSAGE;
10966
10967 AST_LIST_LOCK(&zones);
10968 if (!AST_LIST_EMPTY(&zones)) {
10969 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
10970 AST_LIST_TRAVERSE(&zones, zone, list) {
10971 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
10972 }
10973 } else {
10974 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
10975 res = CLI_FAILURE;
10976 }
10977 AST_LIST_UNLOCK(&zones);
10978
10979 return res;
10980 }
10981
10982
10983 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10984 {
10985 switch (cmd) {
10986 case CLI_INIT:
10987 e->command = "voicemail reload";
10988 e->usage =
10989 "Usage: voicemail reload\n"
10990 " Reload voicemail configuration\n";
10991 return NULL;
10992 case CLI_GENERATE:
10993 return NULL;
10994 }
10995
10996 if (a->argc != 2)
10997 return CLI_SHOWUSAGE;
10998
10999 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11000 load_config(1);
11001
11002 return CLI_SUCCESS;
11003 }
11004
11005 static struct ast_cli_entry cli_voicemail[] = {
11006 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11007 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11008 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11009 };
11010
11011 #ifdef IMAP_STORAGE
11012 #define DATA_EXPORT_VM_USERS(USER) \
11013 USER(ast_vm_user, context, AST_DATA_STRING) \
11014 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11015 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11016 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11017 USER(ast_vm_user, email, AST_DATA_STRING) \
11018 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11019 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11020 USER(ast_vm_user, pager, AST_DATA_STRING) \
11021 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11022 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11023 USER(ast_vm_user, language, AST_DATA_STRING) \
11024 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11025 USER(ast_vm_user, callback, AST_DATA_STRING) \
11026 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11027 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11028 USER(ast_vm_user, exit, AST_DATA_STRING) \
11029 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11030 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11031 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11032 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11033 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11034 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11035 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11036 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11037 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11038 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11039 #else
11040 #define DATA_EXPORT_VM_USERS(USER) \
11041 USER(ast_vm_user, context, AST_DATA_STRING) \
11042 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11043 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11044 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11045 USER(ast_vm_user, email, AST_DATA_STRING) \
11046 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11047 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11048 USER(ast_vm_user, pager, AST_DATA_STRING) \
11049 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11050 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11051 USER(ast_vm_user, language, AST_DATA_STRING) \
11052 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11053 USER(ast_vm_user, callback, AST_DATA_STRING) \
11054 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11055 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11056 USER(ast_vm_user, exit, AST_DATA_STRING) \
11057 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11058 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11059 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11060 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11061 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11062 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11063 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11064 #endif
11065
11066 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11067
11068 #define DATA_EXPORT_VM_ZONES(ZONE) \
11069 ZONE(vm_zone, name, AST_DATA_STRING) \
11070 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11071 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11072
11073 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11074
11075
11076
11077
11078
11079
11080
11081
11082 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11083 struct ast_data *data_root, struct ast_vm_user *user)
11084 {
11085 struct ast_data *data_user, *data_zone;
11086 struct ast_data *data_state;
11087 struct vm_zone *zone = NULL;
11088 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11089 char ext_context[256] = "";
11090
11091 data_user = ast_data_add_node(data_root, "user");
11092 if (!data_user) {
11093 return -1;
11094 }
11095
11096 ast_data_add_structure(ast_vm_user, data_user, user);
11097
11098 AST_LIST_LOCK(&zones);
11099 AST_LIST_TRAVERSE(&zones, zone, list) {
11100 if (!strcmp(zone->name, user->zonetag)) {
11101 break;
11102 }
11103 }
11104 AST_LIST_UNLOCK(&zones);
11105
11106
11107 data_state = ast_data_add_node(data_user, "state");
11108 if (!data_state) {
11109 return -1;
11110 }
11111 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11112 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11113 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11114 ast_data_add_int(data_state, "newmsg", newmsg);
11115 ast_data_add_int(data_state, "oldmsg", oldmsg);
11116
11117 if (zone) {
11118 data_zone = ast_data_add_node(data_user, "zone");
11119 ast_data_add_structure(vm_zone, data_zone, zone);
11120 }
11121
11122 if (!ast_data_search_match(search, data_user)) {
11123 ast_data_remove_node(data_root, data_user);
11124 }
11125
11126 return 0;
11127 }
11128
11129 static int vm_users_data_provider_get(const struct ast_data_search *search,
11130 struct ast_data *data_root)
11131 {
11132 struct ast_vm_user *user;
11133
11134 AST_LIST_LOCK(&users);
11135 AST_LIST_TRAVERSE(&users, user, list) {
11136 vm_users_data_provider_get_helper(search, data_root, user);
11137 }
11138 AST_LIST_UNLOCK(&users);
11139
11140 return 0;
11141 }
11142
11143 static const struct ast_data_handler vm_users_data_provider = {
11144 .version = AST_DATA_HANDLER_VERSION,
11145 .get = vm_users_data_provider_get
11146 };
11147
11148 static const struct ast_data_entry vm_data_providers[] = {
11149 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11150 };
11151
11152 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11153 {
11154 int new = 0, old = 0, urgent = 0;
11155
11156 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11157
11158 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11159 mwi_sub->old_urgent = urgent;
11160 mwi_sub->old_new = new;
11161 mwi_sub->old_old = old;
11162 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11163 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11164 }
11165 }
11166
11167 static void poll_subscribed_mailboxes(void)
11168 {
11169 struct mwi_sub *mwi_sub;
11170
11171 AST_RWLIST_RDLOCK(&mwi_subs);
11172 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11173 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11174 poll_subscribed_mailbox(mwi_sub);
11175 }
11176 }
11177 AST_RWLIST_UNLOCK(&mwi_subs);
11178 }
11179
11180 static void *mb_poll_thread(void *data)
11181 {
11182 while (poll_thread_run) {
11183 struct timespec ts = { 0, };
11184 struct timeval wait;
11185
11186 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11187 ts.tv_sec = wait.tv_sec;
11188 ts.tv_nsec = wait.tv_usec * 1000;
11189
11190 ast_mutex_lock(&poll_lock);
11191 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11192 ast_mutex_unlock(&poll_lock);
11193
11194 if (!poll_thread_run)
11195 break;
11196
11197 poll_subscribed_mailboxes();
11198 }
11199
11200 return NULL;
11201 }
11202
11203 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11204 {
11205 ast_free(mwi_sub);
11206 }
11207
11208 static int handle_unsubscribe(void *datap)
11209 {
11210 struct mwi_sub *mwi_sub;
11211 uint32_t *uniqueid = datap;
11212
11213 AST_RWLIST_WRLOCK(&mwi_subs);
11214 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11215 if (mwi_sub->uniqueid == *uniqueid) {
11216 AST_LIST_REMOVE_CURRENT(entry);
11217 break;
11218 }
11219 }
11220 AST_RWLIST_TRAVERSE_SAFE_END
11221 AST_RWLIST_UNLOCK(&mwi_subs);
11222
11223 if (mwi_sub)
11224 mwi_sub_destroy(mwi_sub);
11225
11226 ast_free(uniqueid);
11227 return 0;
11228 }
11229
11230 static int handle_subscribe(void *datap)
11231 {
11232 unsigned int len;
11233 struct mwi_sub *mwi_sub;
11234 struct mwi_sub_task *p = datap;
11235
11236 len = sizeof(*mwi_sub);
11237 if (!ast_strlen_zero(p->mailbox))
11238 len += strlen(p->mailbox);
11239
11240 if (!ast_strlen_zero(p->context))
11241 len += strlen(p->context) + 1;
11242
11243 if (!(mwi_sub = ast_calloc(1, len)))
11244 return -1;
11245
11246 mwi_sub->uniqueid = p->uniqueid;
11247 if (!ast_strlen_zero(p->mailbox))
11248 strcpy(mwi_sub->mailbox, p->mailbox);
11249
11250 if (!ast_strlen_zero(p->context)) {
11251 strcat(mwi_sub->mailbox, "@");
11252 strcat(mwi_sub->mailbox, p->context);
11253 }
11254
11255 AST_RWLIST_WRLOCK(&mwi_subs);
11256 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11257 AST_RWLIST_UNLOCK(&mwi_subs);
11258 ast_free((void *) p->mailbox);
11259 ast_free((void *) p->context);
11260 ast_free(p);
11261 poll_subscribed_mailbox(mwi_sub);
11262 return 0;
11263 }
11264
11265 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11266 {
11267 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11268 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11269 return;
11270
11271 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11272 return;
11273
11274 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11275 *uniqueid = u;
11276 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11277 ast_free(uniqueid);
11278 }
11279 }
11280
11281 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11282 {
11283 struct mwi_sub_task *mwist;
11284
11285 if (ast_event_get_type(event) != AST_EVENT_SUB)
11286 return;
11287
11288 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11289 return;
11290
11291 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11292 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11293 return;
11294 }
11295 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11296 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11297 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11298
11299 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11300 ast_free(mwist);
11301 }
11302 }
11303
11304 static void start_poll_thread(void)
11305 {
11306 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11307 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11308 AST_EVENT_IE_END);
11309
11310 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11311 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11312 AST_EVENT_IE_END);
11313
11314 if (mwi_sub_sub)
11315 ast_event_report_subs(mwi_sub_sub);
11316
11317 poll_thread_run = 1;
11318
11319 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11320 }
11321
11322 static void stop_poll_thread(void)
11323 {
11324 poll_thread_run = 0;
11325
11326 if (mwi_sub_sub) {
11327 ast_event_unsubscribe(mwi_sub_sub);
11328 mwi_sub_sub = NULL;
11329 }
11330
11331 if (mwi_unsub_sub) {
11332 ast_event_unsubscribe(mwi_unsub_sub);
11333 mwi_unsub_sub = NULL;
11334 }
11335
11336 ast_mutex_lock(&poll_lock);
11337 ast_cond_signal(&poll_cond);
11338 ast_mutex_unlock(&poll_lock);
11339
11340 pthread_join(poll_thread, NULL);
11341
11342 poll_thread = AST_PTHREADT_NULL;
11343 }
11344
11345
11346 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11347 {
11348 struct ast_vm_user *vmu = NULL;
11349 const char *id = astman_get_header(m, "ActionID");
11350 char actionid[128] = "";
11351
11352 if (!ast_strlen_zero(id))
11353 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11354
11355 AST_LIST_LOCK(&users);
11356
11357 if (AST_LIST_EMPTY(&users)) {
11358 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11359 AST_LIST_UNLOCK(&users);
11360 return RESULT_SUCCESS;
11361 }
11362
11363 astman_send_ack(s, m, "Voicemail user list will follow");
11364
11365 AST_LIST_TRAVERSE(&users, vmu, list) {
11366 char dirname[256];
11367
11368 #ifdef IMAP_STORAGE
11369 int new, old;
11370 inboxcount(vmu->mailbox, &new, &old);
11371 #endif
11372
11373 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11374 astman_append(s,
11375 "%s"
11376 "Event: VoicemailUserEntry\r\n"
11377 "VMContext: %s\r\n"
11378 "VoiceMailbox: %s\r\n"
11379 "Fullname: %s\r\n"
11380 "Email: %s\r\n"
11381 "Pager: %s\r\n"
11382 "ServerEmail: %s\r\n"
11383 "MailCommand: %s\r\n"
11384 "Language: %s\r\n"
11385 "TimeZone: %s\r\n"
11386 "Callback: %s\r\n"
11387 "Dialout: %s\r\n"
11388 "UniqueID: %s\r\n"
11389 "ExitContext: %s\r\n"
11390 "SayDurationMinimum: %d\r\n"
11391 "SayEnvelope: %s\r\n"
11392 "SayCID: %s\r\n"
11393 "AttachMessage: %s\r\n"
11394 "AttachmentFormat: %s\r\n"
11395 "DeleteMessage: %s\r\n"
11396 "VolumeGain: %.2f\r\n"
11397 "CanReview: %s\r\n"
11398 "CallOperator: %s\r\n"
11399 "MaxMessageCount: %d\r\n"
11400 "MaxMessageLength: %d\r\n"
11401 "NewMessageCount: %d\r\n"
11402 #ifdef IMAP_STORAGE
11403 "OldMessageCount: %d\r\n"
11404 "IMAPUser: %s\r\n"
11405 #endif
11406 "\r\n",
11407 actionid,
11408 vmu->context,
11409 vmu->mailbox,
11410 vmu->fullname,
11411 vmu->email,
11412 vmu->pager,
11413 vmu->serveremail,
11414 vmu->mailcmd,
11415 vmu->language,
11416 vmu->zonetag,
11417 vmu->callback,
11418 vmu->dialout,
11419 vmu->uniqueid,
11420 vmu->exit,
11421 vmu->saydurationm,
11422 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11423 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11424 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11425 vmu->attachfmt,
11426 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11427 vmu->volgain,
11428 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11429 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11430 vmu->maxmsg,
11431 vmu->maxsecs,
11432 #ifdef IMAP_STORAGE
11433 new, old, vmu->imapuser
11434 #else
11435 count_messages(vmu, dirname)
11436 #endif
11437 );
11438 }
11439 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11440
11441 AST_LIST_UNLOCK(&users);
11442
11443 return RESULT_SUCCESS;
11444 }
11445
11446
11447 static void free_vm_users(void)
11448 {
11449 struct ast_vm_user *current;
11450 AST_LIST_LOCK(&users);
11451 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11452 ast_set_flag(current, VM_ALLOCED);
11453 free_user(current);
11454 }
11455 AST_LIST_UNLOCK(&users);
11456 }
11457
11458
11459 static void free_vm_zones(void)
11460 {
11461 struct vm_zone *zcur;
11462 AST_LIST_LOCK(&zones);
11463 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11464 free_zone(zcur);
11465 AST_LIST_UNLOCK(&zones);
11466 }
11467
11468 static const char *substitute_escapes(const char *value)
11469 {
11470 char *current;
11471
11472
11473 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11474
11475 ast_str_reset(str);
11476
11477
11478 for (current = (char *) value; *current; current++) {
11479 if (*current == '\\') {
11480 current++;
11481 if (!*current) {
11482 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11483 break;
11484 }
11485 switch (*current) {
11486 case 'r':
11487 ast_str_append(&str, 0, "\r");
11488 break;
11489 case 'n':
11490 #ifdef IMAP_STORAGE
11491 if (!str->used || str->str[str->used - 1] != '\r') {
11492 ast_str_append(&str, 0, "\r");
11493 }
11494 #endif
11495 ast_str_append(&str, 0, "\n");
11496 break;
11497 case 't':
11498 ast_str_append(&str, 0, "\t");
11499 break;
11500 default:
11501 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11502 break;
11503 }
11504 } else {
11505 ast_str_append(&str, 0, "%c", *current);
11506 }
11507 }
11508
11509 return ast_str_buffer(str);
11510 }
11511
11512 static int load_config(int reload)
11513 {
11514 struct ast_vm_user *current;
11515 struct ast_config *cfg, *ucfg;
11516 char *cat;
11517 struct ast_variable *var;
11518 const char *val;
11519 char *q, *stringp, *tmp;
11520 int x;
11521 int tmpadsi[4];
11522 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11523 char secretfn[PATH_MAX] = "";
11524
11525 ast_unload_realtime("voicemail");
11526 ast_unload_realtime("voicemail_data");
11527
11528 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11529 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11530 return 0;
11531 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11532 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11533 ucfg = NULL;
11534 }
11535 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11536 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11537 ast_config_destroy(ucfg);
11538 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11539 return 0;
11540 }
11541 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11542 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11543 return 0;
11544 } else {
11545 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11546 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11547 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11548 ucfg = NULL;
11549 }
11550 }
11551 #ifdef IMAP_STORAGE
11552 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11553 #endif
11554
11555 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11556 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11557 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11558 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11559 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11560
11561
11562 free_vm_users();
11563
11564
11565 free_vm_zones();
11566
11567 AST_LIST_LOCK(&users);
11568
11569 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11570 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11571
11572 if (cfg) {
11573
11574
11575 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11576 val = "default";
11577 ast_copy_string(userscontext, val, sizeof(userscontext));
11578
11579 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11580 val = "yes";
11581 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11582
11583 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11584 val = "no";
11585 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11586
11587 volgain = 0.0;
11588 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11589 sscanf(val, "%30lf", &volgain);
11590
11591 #ifdef ODBC_STORAGE
11592 strcpy(odbc_database, "asterisk");
11593 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11594 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11595 }
11596 strcpy(odbc_table, "voicemessages");
11597 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11598 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11599 }
11600 #endif
11601
11602 strcpy(mailcmd, SENDMAIL);
11603 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11604 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11605
11606 maxsilence = 0;
11607 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11608 maxsilence = atoi(val);
11609 if (maxsilence > 0)
11610 maxsilence *= 1000;
11611 }
11612
11613 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11614 maxmsg = MAXMSG;
11615 } else {
11616 maxmsg = atoi(val);
11617 if (maxmsg < 0) {
11618 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11619 maxmsg = MAXMSG;
11620 } else if (maxmsg > MAXMSGLIMIT) {
11621 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11622 maxmsg = MAXMSGLIMIT;
11623 }
11624 }
11625
11626 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11627 maxdeletedmsg = 0;
11628 } else {
11629 if (sscanf(val, "%30d", &x) == 1)
11630 maxdeletedmsg = x;
11631 else if (ast_true(val))
11632 maxdeletedmsg = MAXMSG;
11633 else
11634 maxdeletedmsg = 0;
11635
11636 if (maxdeletedmsg < 0) {
11637 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11638 maxdeletedmsg = MAXMSG;
11639 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11640 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11641 maxdeletedmsg = MAXMSGLIMIT;
11642 }
11643 }
11644
11645
11646 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11647 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11648 }
11649
11650
11651 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11652 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11653 }
11654
11655
11656 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11657 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11658 pwdchange = PWDCHANGE_EXTERNAL;
11659 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11660 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11661 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11662 }
11663
11664
11665 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11666 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11667 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11668 }
11669
11670 #ifdef IMAP_STORAGE
11671
11672 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11673 ast_copy_string(imapserver, val, sizeof(imapserver));
11674 } else {
11675 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11676 }
11677
11678 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11679 ast_copy_string(imapport, val, sizeof(imapport));
11680 } else {
11681 ast_copy_string(imapport, "143", sizeof(imapport));
11682 }
11683
11684 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11685 ast_copy_string(imapflags, val, sizeof(imapflags));
11686 }
11687
11688 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11689 ast_copy_string(authuser, val, sizeof(authuser));
11690 }
11691
11692 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11693 ast_copy_string(authpassword, val, sizeof(authpassword));
11694 }
11695
11696 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11697 if (ast_false(val))
11698 expungeonhangup = 0;
11699 else
11700 expungeonhangup = 1;
11701 } else {
11702 expungeonhangup = 1;
11703 }
11704
11705 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11706 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11707 } else {
11708 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11709 }
11710 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11711 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11712 }
11713 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11714 imapgreetings = ast_true(val);
11715 } else {
11716 imapgreetings = 0;
11717 }
11718 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11719 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11720 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
11721
11722 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11723 } else {
11724 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
11725 }
11726
11727
11728
11729
11730
11731 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
11732 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
11733 } else {
11734 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
11735 }
11736
11737 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
11738 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
11739 } else {
11740 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
11741 }
11742
11743 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
11744 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
11745 } else {
11746 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
11747 }
11748
11749 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
11750 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
11751 } else {
11752 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
11753 }
11754
11755
11756 imapversion++;
11757 #endif
11758
11759 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
11760 ast_copy_string(externnotify, val, sizeof(externnotify));
11761 ast_debug(1, "found externnotify: %s\n", externnotify);
11762 } else {
11763 externnotify[0] = '\0';
11764 }
11765
11766
11767 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
11768 ast_debug(1, "Enabled SMDI voicemail notification\n");
11769 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
11770 smdi_iface = ast_smdi_interface_find(val);
11771 } else {
11772 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
11773 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
11774 }
11775 if (!smdi_iface) {
11776 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
11777 }
11778 }
11779
11780
11781 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
11782 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
11783 silencethreshold = atoi(val);
11784
11785 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
11786 val = ASTERISK_USERNAME;
11787 ast_copy_string(serveremail, val, sizeof(serveremail));
11788
11789 vmmaxsecs = 0;
11790 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
11791 if (sscanf(val, "%30d", &x) == 1) {
11792 vmmaxsecs = x;
11793 } else {
11794 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11795 }
11796 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
11797 static int maxmessage_deprecate = 0;
11798 if (maxmessage_deprecate == 0) {
11799 maxmessage_deprecate = 1;
11800 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
11801 }
11802 if (sscanf(val, "%30d", &x) == 1) {
11803 vmmaxsecs = x;
11804 } else {
11805 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11806 }
11807 }
11808
11809 vmminsecs = 0;
11810 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
11811 if (sscanf(val, "%30d", &x) == 1) {
11812 vmminsecs = x;
11813 if (maxsilence / 1000 >= vmminsecs) {
11814 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
11815 }
11816 } else {
11817 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11818 }
11819 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
11820 static int maxmessage_deprecate = 0;
11821 if (maxmessage_deprecate == 0) {
11822 maxmessage_deprecate = 1;
11823 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
11824 }
11825 if (sscanf(val, "%30d", &x) == 1) {
11826 vmminsecs = x;
11827 if (maxsilence / 1000 >= vmminsecs) {
11828 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
11829 }
11830 } else {
11831 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11832 }
11833 }
11834
11835 val = ast_variable_retrieve(cfg, "general", "format");
11836 if (!val) {
11837 val = "wav";
11838 } else {
11839 tmp = ast_strdupa(val);
11840 val = ast_format_str_reduce(tmp);
11841 if (!val) {
11842 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
11843 val = "wav";
11844 }
11845 }
11846 ast_copy_string(vmfmts, val, sizeof(vmfmts));
11847
11848 skipms = 3000;
11849 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
11850 if (sscanf(val, "%30d", &x) == 1) {
11851 maxgreet = x;
11852 } else {
11853 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
11854 }
11855 }
11856
11857 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
11858 if (sscanf(val, "%30d", &x) == 1) {
11859 skipms = x;
11860 } else {
11861 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
11862 }
11863 }
11864
11865 maxlogins = 3;
11866 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
11867 if (sscanf(val, "%30d", &x) == 1) {
11868 maxlogins = x;
11869 } else {
11870 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
11871 }
11872 }
11873
11874 minpassword = MINPASSWORD;
11875 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
11876 if (sscanf(val, "%30d", &x) == 1) {
11877 minpassword = x;
11878 } else {
11879 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
11880 }
11881 }
11882
11883
11884 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
11885 val = "no";
11886 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
11887
11888
11889 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
11890 val = "no";
11891 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
11892
11893 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
11894 ast_debug(1, "VM_CID Internal context string: %s\n", val);
11895 stringp = ast_strdupa(val);
11896 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
11897 if (!ast_strlen_zero(stringp)) {
11898 q = strsep(&stringp, ",");
11899 while ((*q == ' ')||(*q == '\t'))
11900 q++;
11901 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
11902 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
11903 } else {
11904 cidinternalcontexts[x][0] = '\0';
11905 }
11906 }
11907 }
11908 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
11909 ast_debug(1, "VM Review Option disabled globally\n");
11910 val = "no";
11911 }
11912 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
11913
11914
11915 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
11916 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
11917 val = "no";
11918 } else {
11919 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
11920 }
11921 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
11922 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
11923 ast_debug(1, "VM next message wrap disabled globally\n");
11924 val = "no";
11925 }
11926 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
11927
11928 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
11929 ast_debug(1, "VM Operator break disabled globally\n");
11930 val = "no";
11931 }
11932 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
11933
11934 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
11935 ast_debug(1, "VM CID Info before msg disabled globally\n");
11936 val = "no";
11937 }
11938 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
11939
11940 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
11941 ast_debug(1, "Send Voicemail msg disabled globally\n");
11942 val = "no";
11943 }
11944 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
11945
11946 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
11947 ast_debug(1, "ENVELOPE before msg enabled globally\n");
11948 val = "yes";
11949 }
11950 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
11951
11952 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
11953 ast_debug(1, "Move Heard enabled globally\n");
11954 val = "yes";
11955 }
11956 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
11957
11958 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
11959 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
11960 val = "no";
11961 }
11962 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
11963
11964 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
11965 ast_debug(1, "Duration info before msg enabled globally\n");
11966 val = "yes";
11967 }
11968 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
11969
11970 saydurationminfo = 2;
11971 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
11972 if (sscanf(val, "%30d", &x) == 1) {
11973 saydurationminfo = x;
11974 } else {
11975 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
11976 }
11977 }
11978
11979 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
11980 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
11981 val = "no";
11982 }
11983 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
11984
11985 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
11986 ast_copy_string(dialcontext, val, sizeof(dialcontext));
11987 ast_debug(1, "found dialout context: %s\n", dialcontext);
11988 } else {
11989 dialcontext[0] = '\0';
11990 }
11991
11992 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
11993 ast_copy_string(callcontext, val, sizeof(callcontext));
11994 ast_debug(1, "found callback context: %s\n", callcontext);
11995 } else {
11996 callcontext[0] = '\0';
11997 }
11998
11999 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12000 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12001 ast_debug(1, "found operator context: %s\n", exitcontext);
12002 } else {
12003 exitcontext[0] = '\0';
12004 }
12005
12006
12007 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12008 ast_copy_string(vm_password, val, sizeof(vm_password));
12009 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12010 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12011 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12012 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12013 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12014 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12015 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12016 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12017 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12018 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12019 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12020 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12021 }
12022
12023 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12024 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12025 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12026 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12027 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12028 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12029 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12030 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12031 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12032 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12033
12034 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12035 val = "no";
12036 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12037
12038 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12039 val = "voicemail.conf";
12040 }
12041 if (!(strcmp(val, "spooldir"))) {
12042 passwordlocation = OPT_PWLOC_SPOOLDIR;
12043 } else {
12044 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12045 }
12046
12047 poll_freq = DEFAULT_POLL_FREQ;
12048 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12049 if (sscanf(val, "%30u", &poll_freq) != 1) {
12050 poll_freq = DEFAULT_POLL_FREQ;
12051 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12052 }
12053 }
12054
12055 poll_mailboxes = 0;
12056 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12057 poll_mailboxes = ast_true(val);
12058
12059 if (ucfg) {
12060 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12061 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12062 continue;
12063 if ((current = find_or_create(userscontext, cat))) {
12064 populate_defaults(current);
12065 apply_options_full(current, ast_variable_browse(ucfg, cat));
12066 ast_copy_string(current->context, userscontext, sizeof(current->context));
12067 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12068 current->passwordlocation = OPT_PWLOC_USERSCONF;
12069 }
12070
12071 switch (current->passwordlocation) {
12072 case OPT_PWLOC_SPOOLDIR:
12073 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12074 read_password_from_file(secretfn, current->password, sizeof(current->password));
12075 }
12076 }
12077 }
12078 ast_config_destroy(ucfg);
12079 }
12080 cat = ast_category_browse(cfg, NULL);
12081 while (cat) {
12082 if (strcasecmp(cat, "general")) {
12083 var = ast_variable_browse(cfg, cat);
12084 if (strcasecmp(cat, "zonemessages")) {
12085
12086 while (var) {
12087 append_mailbox(cat, var->name, var->value);
12088 var = var->next;
12089 }
12090 } else {
12091
12092 while (var) {
12093 struct vm_zone *z;
12094 if ((z = ast_malloc(sizeof(*z)))) {
12095 char *msg_format, *tzone;
12096 msg_format = ast_strdupa(var->value);
12097 tzone = strsep(&msg_format, "|,");
12098 if (msg_format) {
12099 ast_copy_string(z->name, var->name, sizeof(z->name));
12100 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12101 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12102 AST_LIST_LOCK(&zones);
12103 AST_LIST_INSERT_HEAD(&zones, z, list);
12104 AST_LIST_UNLOCK(&zones);
12105 } else {
12106 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12107 ast_free(z);
12108 }
12109 } else {
12110 AST_LIST_UNLOCK(&users);
12111 ast_config_destroy(cfg);
12112 return -1;
12113 }
12114 var = var->next;
12115 }
12116 }
12117 }
12118 cat = ast_category_browse(cfg, cat);
12119 }
12120 memset(fromstring, 0, sizeof(fromstring));
12121 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12122 strcpy(charset, "ISO-8859-1");
12123 if (emailbody) {
12124 ast_free(emailbody);
12125 emailbody = NULL;
12126 }
12127 if (emailsubject) {
12128 ast_free(emailsubject);
12129 emailsubject = NULL;
12130 }
12131 if (pagerbody) {
12132 ast_free(pagerbody);
12133 pagerbody = NULL;
12134 }
12135 if (pagersubject) {
12136 ast_free(pagersubject);
12137 pagersubject = NULL;
12138 }
12139 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12140 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12141 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12142 ast_copy_string(fromstring, val, sizeof(fromstring));
12143 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12144 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12145 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12146 ast_copy_string(charset, val, sizeof(charset));
12147 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12148 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12149 for (x = 0; x < 4; x++) {
12150 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12151 }
12152 }
12153 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12154 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12155 for (x = 0; x < 4; x++) {
12156 memcpy(&adsisec[x], &tmpadsi[x], 1);
12157 }
12158 }
12159 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12160 if (atoi(val)) {
12161 adsiver = atoi(val);
12162 }
12163 }
12164 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12165 ast_copy_string(zonetag, val, sizeof(zonetag));
12166 }
12167 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12168 ast_copy_string(locale, val, sizeof(locale));
12169 }
12170 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12171 emailsubject = ast_strdup(val);
12172 }
12173 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12174 emailbody = ast_strdup(substitute_escapes(val));
12175 }
12176 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12177 pagersubject = ast_strdup(val);
12178 }
12179 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12180 pagerbody = ast_strdup(substitute_escapes(val));
12181 }
12182 AST_LIST_UNLOCK(&users);
12183 ast_config_destroy(cfg);
12184
12185 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12186 start_poll_thread();
12187 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12188 stop_poll_thread();;
12189
12190 return 0;
12191 } else {
12192 AST_LIST_UNLOCK(&users);
12193 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12194 if (ucfg)
12195 ast_config_destroy(ucfg);
12196 return 0;
12197 }
12198 }
12199
12200 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12201 {
12202 int res = -1;
12203 char dir[PATH_MAX];
12204 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12205 ast_debug(2, "About to try retrieving name file %s\n", dir);
12206 RETRIEVE(dir, -1, mailbox, context);
12207 if (ast_fileexists(dir, NULL, NULL)) {
12208 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12209 }
12210 DISPOSE(dir, -1);
12211 return res;
12212 }
12213
12214 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12215 struct ast_config *pwconf;
12216 struct ast_flags config_flags = { 0 };
12217
12218 pwconf = ast_config_load(secretfn, config_flags);
12219 if (pwconf) {
12220 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12221 if (val) {
12222 ast_copy_string(password, val, passwordlen);
12223 return;
12224 }
12225 }
12226 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12227 }
12228
12229 static int write_password_to_file(const char *secretfn, const char *password) {
12230 struct ast_config *conf;
12231 struct ast_category *cat;
12232 struct ast_variable *var;
12233
12234 if (!(conf=ast_config_new())) {
12235 ast_log(LOG_ERROR, "Error creating new config structure\n");
12236 return -1;
12237 }
12238 if (!(cat=ast_category_new("general","",1))) {
12239 ast_log(LOG_ERROR, "Error creating new category structure\n");
12240 return -1;
12241 }
12242 if (!(var=ast_variable_new("password",password,""))) {
12243 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12244 return -1;
12245 }
12246 ast_category_append(conf,cat);
12247 ast_variable_append(cat,var);
12248 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12249 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12250 return -1;
12251 }
12252 return 0;
12253 }
12254
12255 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12256 {
12257 char *context;
12258 char *args_copy;
12259 int res;
12260
12261 if (ast_strlen_zero(data)) {
12262 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12263 return -1;
12264 }
12265
12266 args_copy = ast_strdupa(data);
12267 if ((context = strchr(args_copy, '@'))) {
12268 *context++ = '\0';
12269 } else {
12270 context = "default";
12271 }
12272
12273 if ((res = sayname(chan, args_copy, context) < 0)) {
12274 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12275 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12276 if (!res) {
12277 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12278 }
12279 }
12280
12281 return res;
12282 }
12283
12284 #ifdef TEST_FRAMEWORK
12285 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12286 {
12287 return 0;
12288 }
12289
12290 static struct ast_frame *fake_read(struct ast_channel *ast)
12291 {
12292 return &ast_null_frame;
12293 }
12294
12295 AST_TEST_DEFINE(test_voicemail_vmsayname)
12296 {
12297 char dir[PATH_MAX];
12298 char dir2[PATH_MAX];
12299 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12300 static const char TEST_EXTENSION[] = "1234";
12301
12302 struct ast_channel *test_channel1 = NULL;
12303 int res = -1;
12304
12305 static const struct ast_channel_tech fake_tech = {
12306 .write = fake_write,
12307 .read = fake_read,
12308 };
12309
12310 switch (cmd) {
12311 case TEST_INIT:
12312 info->name = "vmsayname_exec";
12313 info->category = "/apps/app_voicemail/";
12314 info->summary = "Vmsayname unit test";
12315 info->description =
12316 "This tests passing various parameters to vmsayname";
12317 return AST_TEST_NOT_RUN;
12318 case TEST_EXECUTE:
12319 break;
12320 }
12321
12322 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12323 NULL, NULL, 0, 0, "TestChannel1"))) {
12324 goto exit_vmsayname_test;
12325 }
12326
12327
12328 test_channel1->nativeformats = AST_FORMAT_GSM;
12329 test_channel1->writeformat = AST_FORMAT_GSM;
12330 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12331 test_channel1->readformat = AST_FORMAT_GSM;
12332 test_channel1->rawreadformat = AST_FORMAT_GSM;
12333 test_channel1->tech = &fake_tech;
12334
12335 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12336 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12337 if (!(res = vmsayname_exec(test_channel1, dir))) {
12338 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12339 if (ast_fileexists(dir, NULL, NULL)) {
12340 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12341 res = -1;
12342 goto exit_vmsayname_test;
12343 } else {
12344
12345 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12346 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12347 goto exit_vmsayname_test;
12348 }
12349 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12350 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12351
12352 if ((res = symlink(dir, dir2))) {
12353 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12354 goto exit_vmsayname_test;
12355 }
12356 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12357 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12358 res = vmsayname_exec(test_channel1, dir);
12359
12360
12361 unlink(dir2);
12362 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12363 rmdir(dir2);
12364 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12365 rmdir(dir2);
12366 }
12367 }
12368
12369 exit_vmsayname_test:
12370
12371 if (test_channel1) {
12372 ast_hangup(test_channel1);
12373 }
12374
12375 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12376 }
12377
12378 AST_TEST_DEFINE(test_voicemail_msgcount)
12379 {
12380 int i, j, res = AST_TEST_PASS, syserr;
12381 struct ast_vm_user *vmu;
12382 struct vm_state vms;
12383 #ifdef IMAP_STORAGE
12384 struct ast_channel *chan = NULL;
12385 #endif
12386 struct {
12387 char dir[256];
12388 char file[256];
12389 char txtfile[256];
12390 } tmp[3];
12391 char syscmd[256];
12392 const char origweasels[] = "tt-weasels";
12393 const char testcontext[] = "test";
12394 const char testmailbox[] = "00000000";
12395 const char testspec[] = "00000000@test";
12396 FILE *txt;
12397 int new, old, urgent;
12398 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12399 const int folder2mbox[3] = { 1, 11, 0 };
12400 const int expected_results[3][12] = {
12401
12402 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12403 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12404 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12405 };
12406
12407 switch (cmd) {
12408 case TEST_INIT:
12409 info->name = "test_voicemail_msgcount";
12410 info->category = "/apps/app_voicemail/";
12411 info->summary = "Test Voicemail status checks";
12412 info->description =
12413 "Verify that message counts are correct when retrieved through the public API";
12414 return AST_TEST_NOT_RUN;
12415 case TEST_EXECUTE:
12416 break;
12417 }
12418
12419
12420 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12421 if ((syserr = ast_safe_system(syscmd))) {
12422 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12423 syserr > 0 ? strerror(syserr) : "unable to fork()");
12424 return AST_TEST_FAIL;
12425 }
12426
12427 #ifdef IMAP_STORAGE
12428 if (!(chan = ast_dummy_channel_alloc())) {
12429 ast_test_status_update(test, "Unable to create dummy channel\n");
12430 return AST_TEST_FAIL;
12431 }
12432 #endif
12433
12434 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12435 !(vmu = find_or_create(testcontext, testmailbox))) {
12436 ast_test_status_update(test, "Cannot create vmu structure\n");
12437 ast_unreplace_sigchld();
12438 return AST_TEST_FAIL;
12439 }
12440
12441 populate_defaults(vmu);
12442 memset(&vms, 0, sizeof(vms));
12443
12444
12445 for (i = 0; i < 3; i++) {
12446 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12447 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12448 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12449
12450 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12451 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12452 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12453 if ((syserr = ast_safe_system(syscmd))) {
12454 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12455 syserr > 0 ? strerror(syserr) : "unable to fork()");
12456 ast_unreplace_sigchld();
12457 return AST_TEST_FAIL;
12458 }
12459 }
12460
12461 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12462 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12463 fclose(txt);
12464 } else {
12465 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12466 res = AST_TEST_FAIL;
12467 break;
12468 }
12469 open_mailbox(&vms, vmu, folder2mbox[i]);
12470 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12471
12472
12473 for (j = 0; j < 3; j++) {
12474
12475 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12476 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12477 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12478 res = AST_TEST_FAIL;
12479 }
12480 }
12481
12482 new = old = urgent = 0;
12483 if (ast_app_inboxcount(testspec, &new, &old)) {
12484 ast_test_status_update(test, "inboxcount returned failure\n");
12485 res = AST_TEST_FAIL;
12486 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12487 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12488 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12489 res = AST_TEST_FAIL;
12490 }
12491
12492 new = old = urgent = 0;
12493 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12494 ast_test_status_update(test, "inboxcount2 returned failure\n");
12495 res = AST_TEST_FAIL;
12496 } else if (old != expected_results[i][6 + 0] ||
12497 urgent != expected_results[i][6 + 1] ||
12498 new != expected_results[i][6 + 2] ) {
12499 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12500 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12501 res = AST_TEST_FAIL;
12502 }
12503
12504 new = old = urgent = 0;
12505 for (j = 0; j < 3; j++) {
12506 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12507 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12508 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12509 res = AST_TEST_FAIL;
12510 }
12511 }
12512 }
12513
12514 for (i = 0; i < 3; i++) {
12515
12516
12517
12518 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12519 DISPOSE(tmp[i].dir, 0);
12520 }
12521
12522 if (vms.deleted) {
12523 ast_free(vms.deleted);
12524 }
12525 if (vms.heard) {
12526 ast_free(vms.heard);
12527 }
12528
12529 #ifdef IMAP_STORAGE
12530 chan = ast_channel_release(chan);
12531 #endif
12532
12533
12534 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12535 if ((syserr = ast_safe_system(syscmd))) {
12536 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12537 syserr > 0 ? strerror(syserr) : "unable to fork()");
12538 }
12539
12540 return res;
12541 }
12542
12543 AST_TEST_DEFINE(test_voicemail_notify_endl)
12544 {
12545 int res = AST_TEST_PASS;
12546 char testcontext[] = "test";
12547 char testmailbox[] = "00000000";
12548 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12549 char attach[256], attach2[256];
12550 char buf[256] = "";
12551 struct ast_channel *chan = NULL;
12552 struct ast_vm_user *vmu, vmus = {
12553 .flags = 0,
12554 };
12555 FILE *file;
12556 struct {
12557 char *name;
12558 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12559 void *location;
12560 union {
12561 int intval;
12562 char *strval;
12563 } u;
12564 } test_items[] = {
12565 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12566 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12567 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12568 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12569 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12570 { "attach2", STRPTR, attach2, .u.strval = "" },
12571 { "attach", STRPTR, attach, .u.strval = "" },
12572 };
12573 int which;
12574
12575 switch (cmd) {
12576 case TEST_INIT:
12577 info->name = "test_voicemail_notify_endl";
12578 info->category = "/apps/app_voicemail/";
12579 info->summary = "Test Voicemail notification end-of-line";
12580 info->description =
12581 "Verify that notification emails use a consistent end-of-line character";
12582 return AST_TEST_NOT_RUN;
12583 case TEST_EXECUTE:
12584 break;
12585 }
12586
12587 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12588 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12589
12590 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12591 !(vmu = find_or_create(testcontext, testmailbox))) {
12592 ast_test_status_update(test, "Cannot create vmu structure\n");
12593 return AST_TEST_NOT_RUN;
12594 }
12595
12596 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12597 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12598 return AST_TEST_NOT_RUN;
12599 }
12600
12601 populate_defaults(vmu);
12602 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12603 #ifdef IMAP_STORAGE
12604
12605 #endif
12606
12607 file = tmpfile();
12608 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12609
12610 rewind(file);
12611 if (ftruncate(fileno(file), 0)) {
12612 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12613 res = AST_TEST_FAIL;
12614 break;
12615 }
12616
12617
12618 if (test_items[which].type == INT) {
12619 *((int *) test_items[which].location) = test_items[which].u.intval;
12620 } else if (test_items[which].type == FLAGVAL) {
12621 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12622 ast_clear_flag(vmu, test_items[which].u.intval);
12623 } else {
12624 ast_set_flag(vmu, test_items[which].u.intval);
12625 }
12626 } else if (test_items[which].type == STATIC) {
12627 strcpy(test_items[which].location, test_items[which].u.strval);
12628 } else if (test_items[which].type == STRPTR) {
12629 test_items[which].location = test_items[which].u.strval;
12630 }
12631
12632 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12633 rewind(file);
12634 while (fgets(buf, sizeof(buf), file)) {
12635 if (
12636 #ifdef IMAP_STORAGE
12637 buf[strlen(buf) - 2] != '\r'
12638 #else
12639 buf[strlen(buf) - 2] == '\r'
12640 #endif
12641 || buf[strlen(buf) - 1] != '\n') {
12642 res = AST_TEST_FAIL;
12643 }
12644 }
12645 }
12646 fclose(file);
12647 return res;
12648 }
12649 #endif
12650
12651 static int reload(void)
12652 {
12653 return load_config(1);
12654 }
12655
12656 static int unload_module(void)
12657 {
12658 int res;
12659
12660 res = ast_unregister_application(app);
12661 res |= ast_unregister_application(app2);
12662 res |= ast_unregister_application(app3);
12663 res |= ast_unregister_application(app4);
12664 res |= ast_unregister_application(sayname_app);
12665 res |= ast_custom_function_unregister(&mailbox_exists_acf);
12666 res |= ast_manager_unregister("VoicemailUsersList");
12667 res |= ast_data_unregister(NULL);
12668 #ifdef TEST_FRAMEWORK
12669 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
12670 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
12671 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
12672 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
12673 #endif
12674 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12675 ast_uninstall_vm_functions();
12676 ao2_ref(inprocess_container, -1);
12677
12678 if (poll_thread != AST_PTHREADT_NULL)
12679 stop_poll_thread();
12680
12681 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
12682 ast_unload_realtime("voicemail");
12683 ast_unload_realtime("voicemail_data");
12684
12685 free_vm_users();
12686 free_vm_zones();
12687 return res;
12688 }
12689
12690 static int load_module(void)
12691 {
12692 int res;
12693 my_umask = umask(0);
12694 umask(my_umask);
12695
12696 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
12697 return AST_MODULE_LOAD_DECLINE;
12698 }
12699
12700
12701 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
12702
12703 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
12704 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
12705 }
12706
12707 if ((res = load_config(0)))
12708 return res;
12709
12710 res = ast_register_application_xml(app, vm_exec);
12711 res |= ast_register_application_xml(app2, vm_execmain);
12712 res |= ast_register_application_xml(app3, vm_box_exists);
12713 res |= ast_register_application_xml(app4, vmauthenticate);
12714 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
12715 res |= ast_custom_function_register(&mailbox_exists_acf);
12716 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
12717 #ifdef TEST_FRAMEWORK
12718 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
12719 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
12720 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
12721 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
12722 #endif
12723
12724 if (res)
12725 return res;
12726
12727 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12728 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
12729
12730 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
12731 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
12732 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
12733
12734 return res;
12735 }
12736
12737 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
12738 {
12739 int cmd = 0;
12740 char destination[80] = "";
12741 int retries = 0;
12742
12743 if (!num) {
12744 ast_verb(3, "Destination number will be entered manually\n");
12745 while (retries < 3 && cmd != 't') {
12746 destination[1] = '\0';
12747 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
12748 if (!cmd)
12749 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
12750 if (!cmd)
12751 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
12752 if (!cmd) {
12753 cmd = ast_waitfordigit(chan, 6000);
12754 if (cmd)
12755 destination[0] = cmd;
12756 }
12757 if (!cmd) {
12758 retries++;
12759 } else {
12760
12761 if (cmd < 0)
12762 return 0;
12763 if (cmd == '*') {
12764 ast_verb(3, "User hit '*' to cancel outgoing call\n");
12765 return 0;
12766 }
12767 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
12768 retries++;
12769 else
12770 cmd = 't';
12771 }
12772 }
12773 if (retries >= 3) {
12774 return 0;
12775 }
12776
12777 } else {
12778 if (option_verbose > 2)
12779 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
12780 ast_copy_string(destination, num, sizeof(destination));
12781 }
12782
12783 if (!ast_strlen_zero(destination)) {
12784 if (destination[strlen(destination) -1 ] == '*')
12785 return 0;
12786 if (option_verbose > 2)
12787 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
12788 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
12789 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
12790 chan->priority = 0;
12791 return 9;
12792 }
12793 return 0;
12794 }
12795
12796
12797
12798
12799
12800
12801
12802
12803
12804
12805
12806
12807
12808
12809 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)
12810 {
12811 int res = 0;
12812 char filename[PATH_MAX];
12813 struct ast_config *msg_cfg = NULL;
12814 const char *origtime, *context;
12815 char *name, *num;
12816 int retries = 0;
12817 char *cid;
12818 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
12819
12820 vms->starting = 0;
12821
12822 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12823
12824
12825 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
12826 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
12827 msg_cfg = ast_config_load(filename, config_flags);
12828 DISPOSE(vms->curdir, vms->curmsg);
12829 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
12830 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
12831 return 0;
12832 }
12833
12834 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
12835 ast_config_destroy(msg_cfg);
12836 return 0;
12837 }
12838
12839 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
12840
12841 context = ast_variable_retrieve(msg_cfg, "message", "context");
12842 if (!strncasecmp("macro", context, 5))
12843 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
12844 switch (option) {
12845 case 3:
12846 if (!res)
12847 res = play_message_datetime(chan, vmu, origtime, filename);
12848 if (!res)
12849 res = play_message_callerid(chan, vms, cid, context, 0);
12850
12851 res = 't';
12852 break;
12853
12854 case 2:
12855
12856 if (ast_strlen_zero(cid))
12857 break;
12858
12859 ast_callerid_parse(cid, &name, &num);
12860 while ((res > -1) && (res != 't')) {
12861 switch (res) {
12862 case '1':
12863 if (num) {
12864
12865 res = dialout(chan, vmu, num, vmu->callback);
12866 if (res) {
12867 ast_config_destroy(msg_cfg);
12868 return 9;
12869 }
12870 } else {
12871 res = '2';
12872 }
12873 break;
12874
12875 case '2':
12876
12877 if (!ast_strlen_zero(vmu->dialout)) {
12878 res = dialout(chan, vmu, NULL, vmu->dialout);
12879 if (res) {
12880 ast_config_destroy(msg_cfg);
12881 return 9;
12882 }
12883 } else {
12884 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
12885 res = ast_play_and_wait(chan, "vm-sorry");
12886 }
12887 ast_config_destroy(msg_cfg);
12888 return res;
12889 case '*':
12890 res = 't';
12891 break;
12892 case '3':
12893 case '4':
12894 case '5':
12895 case '6':
12896 case '7':
12897 case '8':
12898 case '9':
12899 case '0':
12900
12901 res = ast_play_and_wait(chan, "vm-sorry");
12902 retries++;
12903 break;
12904 default:
12905 if (num) {
12906 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
12907 res = ast_play_and_wait(chan, "vm-num-i-have");
12908 if (!res)
12909 res = play_message_callerid(chan, vms, num, vmu->context, 1);
12910 if (!res)
12911 res = ast_play_and_wait(chan, "vm-tocallnum");
12912
12913 if (!ast_strlen_zero(vmu->dialout)) {
12914 if (!res)
12915 res = ast_play_and_wait(chan, "vm-calldiffnum");
12916 }
12917 } else {
12918 res = ast_play_and_wait(chan, "vm-nonumber");
12919 if (!ast_strlen_zero(vmu->dialout)) {
12920 if (!res)
12921 res = ast_play_and_wait(chan, "vm-toenternumber");
12922 }
12923 }
12924 if (!res)
12925 res = ast_play_and_wait(chan, "vm-star-cancel");
12926 if (!res)
12927 res = ast_waitfordigit(chan, 6000);
12928 if (!res) {
12929 retries++;
12930 if (retries > 3)
12931 res = 't';
12932 }
12933 break;
12934
12935 }
12936 if (res == 't')
12937 res = 0;
12938 else if (res == '*')
12939 res = -1;
12940 }
12941 break;
12942
12943 case 1:
12944
12945 if (ast_strlen_zero(cid))
12946 break;
12947
12948 ast_callerid_parse(cid, &name, &num);
12949 if (!num) {
12950 ast_verb(3, "No CID number available, no reply sent\n");
12951 if (!res)
12952 res = ast_play_and_wait(chan, "vm-nonumber");
12953 ast_config_destroy(msg_cfg);
12954 return res;
12955 } else {
12956 struct ast_vm_user vmu2;
12957 if (find_user(&vmu2, vmu->context, num)) {
12958 struct leave_vm_options leave_options;
12959 char mailbox[AST_MAX_EXTENSION * 2 + 2];
12960 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
12961
12962 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
12963
12964 memset(&leave_options, 0, sizeof(leave_options));
12965 leave_options.record_gain = record_gain;
12966 res = leave_voicemail(chan, mailbox, &leave_options);
12967 if (!res)
12968 res = 't';
12969 ast_config_destroy(msg_cfg);
12970 return res;
12971 } else {
12972
12973 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
12974 ast_play_and_wait(chan, "vm-nobox");
12975 res = 't';
12976 ast_config_destroy(msg_cfg);
12977 return res;
12978 }
12979 }
12980 res = 0;
12981
12982 break;
12983 }
12984
12985 #ifndef IMAP_STORAGE
12986 ast_config_destroy(msg_cfg);
12987
12988 if (!res) {
12989 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12990 vms->heard[msg] = 1;
12991 res = wait_file(chan, vms, vms->fn);
12992 }
12993 #endif
12994 return res;
12995 }
12996
12997 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
12998 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
12999 signed char record_gain, struct vm_state *vms, char *flag)
13000 {
13001
13002 int res = 0;
13003 int cmd = 0;
13004 int max_attempts = 3;
13005 int attempts = 0;
13006 int recorded = 0;
13007 int msg_exists = 0;
13008 signed char zero_gain = 0;
13009 char tempfile[PATH_MAX];
13010 char *acceptdtmf = "#";
13011 char *canceldtmf = "";
13012 int canceleddtmf = 0;
13013
13014
13015
13016
13017 if (duration == NULL) {
13018 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13019 return -1;
13020 }
13021
13022 if (!outsidecaller)
13023 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13024 else
13025 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13026
13027 cmd = '3';
13028
13029 while ((cmd >= 0) && (cmd != 't')) {
13030 switch (cmd) {
13031 case '1':
13032 if (!msg_exists) {
13033
13034 cmd = '3';
13035 break;
13036 } else {
13037
13038 ast_verb(3, "Saving message as is\n");
13039 if (!outsidecaller)
13040 ast_filerename(tempfile, recordfile, NULL);
13041 ast_stream_and_wait(chan, "vm-msgsaved", "");
13042 if (!outsidecaller) {
13043
13044 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13045 DISPOSE(recordfile, -1);
13046 }
13047 cmd = 't';
13048 return res;
13049 }
13050 case '2':
13051
13052 ast_verb(3, "Reviewing the message\n");
13053 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13054 break;
13055 case '3':
13056 msg_exists = 0;
13057
13058 if (recorded == 1)
13059 ast_verb(3, "Re-recording the message\n");
13060 else
13061 ast_verb(3, "Recording the message\n");
13062
13063 if (recorded && outsidecaller) {
13064 cmd = ast_play_and_wait(chan, INTRO);
13065 cmd = ast_play_and_wait(chan, "beep");
13066 }
13067 recorded = 1;
13068
13069 if (record_gain)
13070 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13071 if (ast_test_flag(vmu, VM_OPERATOR))
13072 canceldtmf = "0";
13073 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13074 if (strchr(canceldtmf, cmd)) {
13075
13076 canceleddtmf = 1;
13077 }
13078 if (record_gain)
13079 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13080 if (cmd == -1) {
13081
13082 if (!outsidecaller) {
13083
13084 ast_filedelete(tempfile, NULL);
13085 }
13086 return cmd;
13087 }
13088 if (cmd == '0') {
13089 break;
13090 } else if (cmd == '*') {
13091 break;
13092 #if 0
13093 } else if (vmu->review && (*duration < 5)) {
13094
13095 ast_verb(3, "Message too short\n");
13096 cmd = ast_play_and_wait(chan, "vm-tooshort");
13097 cmd = ast_filedelete(tempfile, NULL);
13098 break;
13099 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
13100
13101 ast_verb(3, "Nothing recorded\n");
13102 cmd = ast_filedelete(tempfile, NULL);
13103 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13104 if (!cmd)
13105 cmd = ast_play_and_wait(chan, "vm-speakup");
13106 break;
13107 #endif
13108 } else {
13109
13110 msg_exists = 1;
13111 cmd = 0;
13112 }
13113 break;
13114 case '4':
13115 if (outsidecaller) {
13116
13117 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13118 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13119 res = ast_play_and_wait(chan, "vm-marked-urgent");
13120 strcpy(flag, "Urgent");
13121 } else if (flag) {
13122 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13123 res = ast_play_and_wait(chan, "vm-urgent-removed");
13124 strcpy(flag, "");
13125 } else {
13126 ast_play_and_wait(chan, "vm-sorry");
13127 }
13128 cmd = 0;
13129 } else {
13130 cmd = ast_play_and_wait(chan, "vm-sorry");
13131 }
13132 break;
13133 case '5':
13134 case '6':
13135 case '7':
13136 case '8':
13137 case '9':
13138 case '*':
13139 case '#':
13140 cmd = ast_play_and_wait(chan, "vm-sorry");
13141 break;
13142 #if 0
13143
13144
13145 case '*':
13146
13147 cmd = ast_play_and_wait(chan, "vm-deleted");
13148 cmd = ast_filedelete(tempfile, NULL);
13149 if (outsidecaller) {
13150 res = vm_exec(chan, NULL);
13151 return res;
13152 }
13153 else
13154 return 1;
13155 #endif
13156 case '0':
13157 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13158 cmd = ast_play_and_wait(chan, "vm-sorry");
13159 break;
13160 }
13161 if (msg_exists || recorded) {
13162 cmd = ast_play_and_wait(chan, "vm-saveoper");
13163 if (!cmd)
13164 cmd = ast_waitfordigit(chan, 3000);
13165 if (cmd == '1') {
13166 ast_filerename(tempfile, recordfile, NULL);
13167 ast_play_and_wait(chan, "vm-msgsaved");
13168 cmd = '0';
13169 } else if (cmd == '4') {
13170 if (flag) {
13171 ast_play_and_wait(chan, "vm-marked-urgent");
13172 strcpy(flag, "Urgent");
13173 }
13174 ast_play_and_wait(chan, "vm-msgsaved");
13175 cmd = '0';
13176 } else {
13177 ast_play_and_wait(chan, "vm-deleted");
13178 DELETE(tempfile, -1, tempfile, vmu);
13179 cmd = '0';
13180 }
13181 }
13182 return cmd;
13183 default:
13184
13185
13186
13187 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13188 return cmd;
13189 if (msg_exists) {
13190 cmd = ast_play_and_wait(chan, "vm-review");
13191 if (!cmd && outsidecaller) {
13192 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13193 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13194 } else if (flag) {
13195 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13196 }
13197 }
13198 } else {
13199 cmd = ast_play_and_wait(chan, "vm-torerecord");
13200 if (!cmd)
13201 cmd = ast_waitfordigit(chan, 600);
13202 }
13203
13204 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13205 cmd = ast_play_and_wait(chan, "vm-reachoper");
13206 if (!cmd)
13207 cmd = ast_waitfordigit(chan, 600);
13208 }
13209 #if 0
13210 if (!cmd)
13211 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13212 #endif
13213 if (!cmd)
13214 cmd = ast_waitfordigit(chan, 6000);
13215 if (!cmd) {
13216 attempts++;
13217 }
13218 if (attempts > max_attempts) {
13219 cmd = 't';
13220 }
13221 }
13222 }
13223 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13224
13225 ast_filedelete(tempfile, NULL);
13226 }
13227
13228 if (cmd != 't' && outsidecaller)
13229 ast_play_and_wait(chan, "vm-goodbye");
13230
13231 return cmd;
13232 }
13233
13234
13235
13236
13237
13238 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13239 .load = load_module,
13240 .unload = unload_module,
13241 .reload = reload,
13242 .nonoptreq = "res_adsi,res_smdi",
13243 );