00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #include "asterisk.h"
00063
00064 #ifdef IMAP_STORAGE
00065 #include <ctype.h>
00066 #include <signal.h>
00067 #include <pwd.h>
00068 #ifdef USE_SYSTEM_IMAP
00069 #include <imap/c-client.h>
00070 #include <imap/imap4r1.h>
00071 #include <imap/linkage.h>
00072 #elif defined (USE_SYSTEM_CCLIENT)
00073 #include <c-client/c-client.h>
00074 #include <c-client/imap4r1.h>
00075 #include <c-client/linkage.h>
00076 #else
00077 #include "c-client.h"
00078 #include "imap4r1.h"
00079 #include "linkage.h"
00080 #endif
00081 #endif
00082
00083 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 301047 $")
00084
00085 #include "asterisk/paths.h"
00086 #include <sys/time.h>
00087 #include <sys/stat.h>
00088 #include <sys/mman.h>
00089 #include <time.h>
00090 #include <dirent.h>
00091 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00092 #include <sys/wait.h>
00093 #endif
00094
00095 #include "asterisk/logger.h"
00096 #include "asterisk/lock.h"
00097 #include "asterisk/file.h"
00098 #include "asterisk/channel.h"
00099 #include "asterisk/pbx.h"
00100 #include "asterisk/config.h"
00101 #include "asterisk/say.h"
00102 #include "asterisk/module.h"
00103 #include "asterisk/adsi.h"
00104 #include "asterisk/app.h"
00105 #include "asterisk/manager.h"
00106 #include "asterisk/dsp.h"
00107 #include "asterisk/localtime.h"
00108 #include "asterisk/cli.h"
00109 #include "asterisk/utils.h"
00110 #include "asterisk/stringfields.h"
00111 #include "asterisk/smdi.h"
00112 #include "asterisk/astobj2.h"
00113 #include "asterisk/event.h"
00114 #include "asterisk/taskprocessor.h"
00115 #include "asterisk/test.h"
00116
00117 #ifdef ODBC_STORAGE
00118 #include "asterisk/res_odbc.h"
00119 #endif
00120
00121 #ifdef IMAP_STORAGE
00122 #include "asterisk/threadstorage.h"
00123 #endif
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
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 #ifdef IMAP_STORAGE
00358 static char imapserver[48];
00359 static char imapport[8];
00360 static char imapflags[128];
00361 static char imapfolder[64];
00362 static char imapparentfolder[64] = "\0";
00363 static char greetingfolder[64];
00364 static char authuser[32];
00365 static char authpassword[42];
00366 static int imapversion = 1;
00367
00368 static int expungeonhangup = 1;
00369 static int imapgreetings = 0;
00370 static char delimiter = '\0';
00371
00372 struct vm_state;
00373 struct ast_vm_user;
00374
00375 AST_THREADSTORAGE(ts_vmstate);
00376
00377
00378 static int init_mailstream(struct vm_state *vms, int box);
00379 static void write_file(char *filename, char *buffer, unsigned long len);
00380 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00381 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00382 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00383 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00384 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00385 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00386 static void vmstate_insert(struct vm_state *vms);
00387 static void vmstate_delete(struct vm_state *vms);
00388 static void set_update(MAILSTREAM * stream);
00389 static void init_vm_state(struct vm_state *vms);
00390 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00391 static void get_mailbox_delimiter(MAILSTREAM *stream);
00392 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00393 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00394 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);
00395 static void update_messages_by_imapuser(const char *user, unsigned long number);
00396 static int vm_delete(char *file);
00397
00398 static int imap_remove_file (char *dir, int msgnum);
00399 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00400 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00401 static void check_quota(struct vm_state *vms, char *mailbox);
00402 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00403 struct vmstate {
00404 struct vm_state *vms;
00405 AST_LIST_ENTRY(vmstate) list;
00406 };
00407
00408 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00409
00410 #endif
00411
00412 #define SMDI_MWI_WAIT_TIMEOUT 1000
00413
00414 #define COMMAND_TIMEOUT 5000
00415
00416 #define VOICEMAIL_DIR_MODE 0777
00417 #define VOICEMAIL_FILE_MODE 0666
00418 #define CHUNKSIZE 65536
00419
00420 #define VOICEMAIL_CONFIG "voicemail.conf"
00421 #define ASTERISK_USERNAME "asterisk"
00422
00423
00424
00425
00426 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00427 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00428 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00429 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00430 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00431 #define VALID_DTMF "1234567890*#"
00432
00433
00434
00435 #define SENDMAIL "/usr/sbin/sendmail -t"
00436
00437 #define INTRO "vm-intro"
00438
00439 #define MAXMSG 100
00440 #define MAXMSGLIMIT 9999
00441
00442 #define MINPASSWORD 0
00443
00444 #define BASELINELEN 72
00445 #define BASEMAXINLINE 256
00446 #ifdef IMAP_STORAGE
00447 #define ENDL "\r\n"
00448 #else
00449 #define ENDL "\n"
00450 #endif
00451
00452 #define MAX_DATETIME_FORMAT 512
00453 #define MAX_NUM_CID_CONTEXTS 10
00454
00455 #define VM_REVIEW (1 << 0)
00456 #define VM_OPERATOR (1 << 1)
00457 #define VM_SAYCID (1 << 2)
00458 #define VM_SVMAIL (1 << 3)
00459 #define VM_ENVELOPE (1 << 4)
00460 #define VM_SAYDURATION (1 << 5)
00461 #define VM_SKIPAFTERCMD (1 << 6)
00462 #define VM_FORCENAME (1 << 7)
00463 #define VM_FORCEGREET (1 << 8)
00464 #define VM_PBXSKIP (1 << 9)
00465 #define VM_DIRECFORWARD (1 << 10)
00466 #define VM_ATTACH (1 << 11)
00467 #define VM_DELETE (1 << 12)
00468 #define VM_ALLOCED (1 << 13)
00469 #define VM_SEARCH (1 << 14)
00470 #define VM_TEMPGREETWARN (1 << 15)
00471 #define VM_MOVEHEARD (1 << 16)
00472 #define VM_MESSAGEWRAP (1 << 17)
00473 #define VM_FWDURGAUTO (1 << 18)
00474 #define ERROR_LOCK_PATH -100
00475 #define OPERATOR_EXIT 300
00476
00477
00478 enum vm_box {
00479 NEW_FOLDER,
00480 OLD_FOLDER,
00481 WORK_FOLDER,
00482 FAMILY_FOLDER,
00483 FRIENDS_FOLDER,
00484 GREETINGS_FOLDER
00485 };
00486
00487 enum vm_option_flags {
00488 OPT_SILENT = (1 << 0),
00489 OPT_BUSY_GREETING = (1 << 1),
00490 OPT_UNAVAIL_GREETING = (1 << 2),
00491 OPT_RECORDGAIN = (1 << 3),
00492 OPT_PREPEND_MAILBOX = (1 << 4),
00493 OPT_AUTOPLAY = (1 << 6),
00494 OPT_DTMFEXIT = (1 << 7),
00495 OPT_MESSAGE_Urgent = (1 << 8),
00496 OPT_MESSAGE_PRIORITY = (1 << 9)
00497 };
00498
00499 enum vm_option_args {
00500 OPT_ARG_RECORDGAIN = 0,
00501 OPT_ARG_PLAYFOLDER = 1,
00502 OPT_ARG_DTMFEXIT = 2,
00503
00504 OPT_ARG_ARRAY_SIZE = 3,
00505 };
00506
00507 enum vm_passwordlocation {
00508 OPT_PWLOC_VOICEMAILCONF = 0,
00509 OPT_PWLOC_SPOOLDIR = 1,
00510 OPT_PWLOC_USERSCONF = 2,
00511 };
00512
00513 AST_APP_OPTIONS(vm_app_options, {
00514 AST_APP_OPTION('s', OPT_SILENT),
00515 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00516 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00517 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00518 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00519 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00520 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00521 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00522 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00523 });
00524
00525 static int load_config(int reload);
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
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 struct baseio {
00611 int iocp;
00612 int iolen;
00613 int linelength;
00614 int ateof;
00615 unsigned char iobuf[BASEMAXINLINE];
00616 };
00617
00618
00619
00620 struct ast_vm_user {
00621 char context[AST_MAX_CONTEXT];
00622 char mailbox[AST_MAX_EXTENSION];
00623 char password[80];
00624 char fullname[80];
00625 char email[80];
00626 char *emailsubject;
00627 char *emailbody;
00628 char pager[80];
00629 char serveremail[80];
00630 char mailcmd[160];
00631 char language[MAX_LANGUAGE];
00632 char zonetag[80];
00633 char locale[20];
00634 char callback[80];
00635 char dialout[80];
00636 char uniqueid[80];
00637 char exit[80];
00638 char attachfmt[20];
00639 unsigned int flags;
00640 int saydurationm;
00641 int minsecs;
00642 int maxmsg;
00643 int maxdeletedmsg;
00644 int maxsecs;
00645 int passwordlocation;
00646 #ifdef IMAP_STORAGE
00647 char imapuser[80];
00648 char imappassword[80];
00649 char imapfolder[64];
00650 char imapvmshareid[80];
00651 int imapversion;
00652 #endif
00653 double volgain;
00654 AST_LIST_ENTRY(ast_vm_user) list;
00655 };
00656
00657
00658 struct vm_zone {
00659 AST_LIST_ENTRY(vm_zone) list;
00660 char name[80];
00661 char timezone[80];
00662 char msg_format[512];
00663 };
00664
00665 #define VMSTATE_MAX_MSG_ARRAY 256
00666
00667
00668 struct vm_state {
00669 char curbox[80];
00670 char username[80];
00671 char context[80];
00672 char curdir[PATH_MAX];
00673 char vmbox[PATH_MAX];
00674 char fn[PATH_MAX];
00675 char intro[PATH_MAX];
00676 int *deleted;
00677 int *heard;
00678 int dh_arraysize;
00679 int curmsg;
00680 int lastmsg;
00681 int newmessages;
00682 int oldmessages;
00683 int urgentmessages;
00684 int starting;
00685 int repeats;
00686 #ifdef IMAP_STORAGE
00687 ast_mutex_t lock;
00688 int updated;
00689 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00690 MAILSTREAM *mailstream;
00691 int vmArrayIndex;
00692 char imapuser[80];
00693 char imapfolder[64];
00694 int imapversion;
00695 int interactive;
00696 char introfn[PATH_MAX];
00697 unsigned int quota_limit;
00698 unsigned int quota_usage;
00699 struct vm_state *persist_vms;
00700 #endif
00701 };
00702
00703 #ifdef ODBC_STORAGE
00704 static char odbc_database[80];
00705 static char odbc_table[80];
00706 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00707 #define DISPOSE(a,b) remove_file(a,b)
00708 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00709 #define EXISTS(a,b,c,d) (message_exists(a,b))
00710 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00711 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00712 #define DELETE(a,b,c,d) (delete_file(a,b))
00713 #else
00714 #ifdef IMAP_STORAGE
00715 #define DISPOSE(a,b) (imap_remove_file(a,b))
00716 #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))
00717 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00718 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00719 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00720 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00721 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00722 #else
00723 #define RETRIEVE(a,b,c,d)
00724 #define DISPOSE(a,b)
00725 #define STORE(a,b,c,d,e,f,g,h,i,j)
00726 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00727 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00728 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00729 #define DELETE(a,b,c,d) (vm_delete(c))
00730 #endif
00731 #endif
00732
00733 static char VM_SPOOL_DIR[PATH_MAX];
00734
00735 static char ext_pass_cmd[128];
00736 static char ext_pass_check_cmd[128];
00737
00738 static int my_umask;
00739
00740 #define PWDCHANGE_INTERNAL (1 << 1)
00741 #define PWDCHANGE_EXTERNAL (1 << 2)
00742 static int pwdchange = PWDCHANGE_INTERNAL;
00743
00744 #ifdef ODBC_STORAGE
00745 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00746 #else
00747 # ifdef IMAP_STORAGE
00748 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00749 # else
00750 # define tdesc "Comedian Mail (Voicemail System)"
00751 # endif
00752 #endif
00753
00754 static char userscontext[AST_MAX_EXTENSION] = "default";
00755
00756 static char *addesc = "Comedian Mail";
00757
00758
00759 static char *app = "VoiceMail";
00760
00761
00762 static char *app2 = "VoiceMailMain";
00763
00764 static char *app3 = "MailboxExists";
00765 static char *app4 = "VMAuthenticate";
00766
00767 static char *sayname_app = "VMSayName";
00768
00769 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00770 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00771 static char zonetag[80];
00772 static char locale[20];
00773 static int maxsilence;
00774 static int maxmsg;
00775 static int maxdeletedmsg;
00776 static int silencethreshold = 128;
00777 static char serveremail[80];
00778 static char mailcmd[160];
00779 static char externnotify[160];
00780 static struct ast_smdi_interface *smdi_iface = NULL;
00781 static char vmfmts[80];
00782 static double volgain;
00783 static int vmminsecs;
00784 static int vmmaxsecs;
00785 static int maxgreet;
00786 static int skipms;
00787 static int maxlogins;
00788 static int minpassword;
00789 static int passwordlocation;
00790
00791
00792
00793 static unsigned int poll_mailboxes;
00794
00795
00796 static unsigned int poll_freq;
00797
00798 #define DEFAULT_POLL_FREQ 30
00799
00800 AST_MUTEX_DEFINE_STATIC(poll_lock);
00801 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00802 static pthread_t poll_thread = AST_PTHREADT_NULL;
00803 static unsigned char poll_thread_run;
00804
00805
00806 static struct ast_event_sub *mwi_sub_sub;
00807
00808 static struct ast_event_sub *mwi_unsub_sub;
00809
00810
00811
00812
00813
00814
00815
00816
00817 struct mwi_sub {
00818 AST_RWLIST_ENTRY(mwi_sub) entry;
00819 int old_urgent;
00820 int old_new;
00821 int old_old;
00822 uint32_t uniqueid;
00823 char mailbox[1];
00824 };
00825
00826 struct mwi_sub_task {
00827 const char *mailbox;
00828 const char *context;
00829 uint32_t uniqueid;
00830 };
00831
00832 static struct ast_taskprocessor *mwi_subscription_tps;
00833
00834 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00835
00836
00837 static char listen_control_forward_key[12];
00838 static char listen_control_reverse_key[12];
00839 static char listen_control_pause_key[12];
00840 static char listen_control_restart_key[12];
00841 static char listen_control_stop_key[12];
00842
00843
00844 static char vm_password[80] = "vm-password";
00845 static char vm_newpassword[80] = "vm-newpassword";
00846 static char vm_passchanged[80] = "vm-passchanged";
00847 static char vm_reenterpassword[80] = "vm-reenterpassword";
00848 static char vm_mismatch[80] = "vm-mismatch";
00849 static char vm_invalid_password[80] = "vm-invalid-password";
00850 static char vm_pls_try_again[80] = "vm-pls-try-again";
00851
00852 static struct ast_flags globalflags = {0};
00853
00854 static int saydurationminfo;
00855
00856 static char dialcontext[AST_MAX_CONTEXT] = "";
00857 static char callcontext[AST_MAX_CONTEXT] = "";
00858 static char exitcontext[AST_MAX_CONTEXT] = "";
00859
00860 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00861
00862
00863 static char *emailbody = NULL;
00864 static char *emailsubject = NULL;
00865 static char *pagerbody = NULL;
00866 static char *pagersubject = NULL;
00867 static char fromstring[100];
00868 static char pagerfromstring[100];
00869 static char charset[32] = "ISO-8859-1";
00870
00871 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00872 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00873 static int adsiver = 1;
00874 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00875 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00876
00877
00878 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00879 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);
00880 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00881 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00882 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00883 signed char record_gain, struct vm_state *vms, char *flag);
00884 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00885 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00886 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);
00887 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);
00888 static void apply_options(struct ast_vm_user *vmu, const char *options);
00889 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);
00890 static int is_valid_dtmf(const char *key);
00891 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00892 static int write_password_to_file(const char *secretfn, const char *password);
00893
00894 struct ao2_container *inprocess_container;
00895
00896 struct inprocess {
00897 int count;
00898 char *context;
00899 char mailbox[0];
00900 };
00901
00902 static int inprocess_hash_fn(const void *obj, const int flags)
00903 {
00904 const struct inprocess *i = obj;
00905 return atoi(i->mailbox);
00906 }
00907
00908 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00909 {
00910 struct inprocess *i = obj, *j = arg;
00911 if (strcmp(i->mailbox, j->mailbox)) {
00912 return 0;
00913 }
00914 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00915 }
00916
00917 static int inprocess_count(const char *context, const char *mailbox, int delta)
00918 {
00919 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00920 arg->context = arg->mailbox + strlen(mailbox) + 1;
00921 strcpy(arg->mailbox, mailbox);
00922 strcpy(arg->context, context);
00923 ao2_lock(inprocess_container);
00924 if ((i = ao2_find(inprocess_container, arg, 0))) {
00925 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00926 ao2_unlock(inprocess_container);
00927 ao2_ref(i, -1);
00928 return ret;
00929 }
00930 if (delta < 0) {
00931 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00932 }
00933 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00934 ao2_unlock(inprocess_container);
00935 return 0;
00936 }
00937 i->context = i->mailbox + strlen(mailbox) + 1;
00938 strcpy(i->mailbox, mailbox);
00939 strcpy(i->context, context);
00940 i->count = delta;
00941 ao2_link(inprocess_container, i);
00942 ao2_unlock(inprocess_container);
00943 ao2_ref(i, -1);
00944 return 0;
00945 }
00946
00947 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00948 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00949 #endif
00950
00951
00952
00953
00954
00955
00956
00957 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00958 {
00959 char *bufptr = buf;
00960 for (; *input; input++) {
00961 if (*input < 32) {
00962 continue;
00963 }
00964 *bufptr++ = *input;
00965 if (bufptr == buf + buflen - 1) {
00966 break;
00967 }
00968 }
00969 *bufptr = '\0';
00970 return buf;
00971 }
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986 static void populate_defaults(struct ast_vm_user *vmu)
00987 {
00988 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00989 vmu->passwordlocation = passwordlocation;
00990 if (saydurationminfo) {
00991 vmu->saydurationm = saydurationminfo;
00992 }
00993 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00994 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00995 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00996 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00997 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
00998 if (vmminsecs) {
00999 vmu->minsecs = vmminsecs;
01000 }
01001 if (vmmaxsecs) {
01002 vmu->maxsecs = vmmaxsecs;
01003 }
01004 if (maxmsg) {
01005 vmu->maxmsg = maxmsg;
01006 }
01007 if (maxdeletedmsg) {
01008 vmu->maxdeletedmsg = maxdeletedmsg;
01009 }
01010 vmu->volgain = volgain;
01011 vmu->emailsubject = NULL;
01012 vmu->emailbody = NULL;
01013 #ifdef IMAP_STORAGE
01014 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01015 #endif
01016 }
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01027 {
01028 int x;
01029 if (!strcasecmp(var, "attach")) {
01030 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01031 } else if (!strcasecmp(var, "attachfmt")) {
01032 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01033 } else if (!strcasecmp(var, "serveremail")) {
01034 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01035 } else if (!strcasecmp(var, "language")) {
01036 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01037 } else if (!strcasecmp(var, "tz")) {
01038 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01039 } else if (!strcasecmp(var, "locale")) {
01040 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01041 #ifdef IMAP_STORAGE
01042 } else if (!strcasecmp(var, "imapuser")) {
01043 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01044 vmu->imapversion = imapversion;
01045 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01046 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01047 vmu->imapversion = imapversion;
01048 } else if (!strcasecmp(var, "imapfolder")) {
01049 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01050 } else if (!strcasecmp(var, "imapvmshareid")) {
01051 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01052 vmu->imapversion = imapversion;
01053 #endif
01054 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01055 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01056 } else if (!strcasecmp(var, "saycid")){
01057 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01058 } else if (!strcasecmp(var, "sendvoicemail")){
01059 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01060 } else if (!strcasecmp(var, "review")){
01061 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01062 } else if (!strcasecmp(var, "tempgreetwarn")){
01063 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01064 } else if (!strcasecmp(var, "messagewrap")){
01065 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01066 } else if (!strcasecmp(var, "operator")) {
01067 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01068 } else if (!strcasecmp(var, "envelope")){
01069 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01070 } else if (!strcasecmp(var, "moveheard")){
01071 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01072 } else if (!strcasecmp(var, "sayduration")){
01073 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01074 } else if (!strcasecmp(var, "saydurationm")){
01075 if (sscanf(value, "%30d", &x) == 1) {
01076 vmu->saydurationm = x;
01077 } else {
01078 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01079 }
01080 } else if (!strcasecmp(var, "forcename")){
01081 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01082 } else if (!strcasecmp(var, "forcegreetings")){
01083 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01084 } else if (!strcasecmp(var, "callback")) {
01085 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01086 } else if (!strcasecmp(var, "dialout")) {
01087 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01088 } else if (!strcasecmp(var, "exitcontext")) {
01089 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01090 } else if (!strcasecmp(var, "minsecs")) {
01091 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01092 vmu->minsecs = x;
01093 } else {
01094 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01095 vmu->minsecs = vmminsecs;
01096 }
01097 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01098 vmu->maxsecs = atoi(value);
01099 if (vmu->maxsecs <= 0) {
01100 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01101 vmu->maxsecs = vmmaxsecs;
01102 } else {
01103 vmu->maxsecs = atoi(value);
01104 }
01105 if (!strcasecmp(var, "maxmessage"))
01106 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01107 } else if (!strcasecmp(var, "maxmsg")) {
01108 vmu->maxmsg = atoi(value);
01109
01110 if (vmu->maxmsg < 0) {
01111 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01112 vmu->maxmsg = MAXMSG;
01113 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01114 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01115 vmu->maxmsg = MAXMSGLIMIT;
01116 }
01117 } else if (!strcasecmp(var, "nextaftercmd")) {
01118 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01119 } else if (!strcasecmp(var, "backupdeleted")) {
01120 if (sscanf(value, "%30d", &x) == 1)
01121 vmu->maxdeletedmsg = x;
01122 else if (ast_true(value))
01123 vmu->maxdeletedmsg = MAXMSG;
01124 else
01125 vmu->maxdeletedmsg = 0;
01126
01127 if (vmu->maxdeletedmsg < 0) {
01128 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01129 vmu->maxdeletedmsg = MAXMSG;
01130 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01131 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01132 vmu->maxdeletedmsg = MAXMSGLIMIT;
01133 }
01134 } else if (!strcasecmp(var, "volgain")) {
01135 sscanf(value, "%30lf", &vmu->volgain);
01136 } else if (!strcasecmp(var, "passwordlocation")) {
01137 if (!strcasecmp(value, "spooldir")) {
01138 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01139 } else {
01140 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01141 }
01142 } else if (!strcasecmp(var, "options")) {
01143 apply_options(vmu, value);
01144 }
01145 }
01146
01147 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01148 {
01149 int fds[2], pid = 0;
01150
01151 memset(buf, 0, len);
01152
01153 if (pipe(fds)) {
01154 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01155 } else {
01156
01157 pid = ast_safe_fork(0);
01158
01159 if (pid < 0) {
01160
01161 close(fds[0]);
01162 close(fds[1]);
01163 snprintf(buf, len, "FAILURE: Fork failed");
01164 } else if (pid) {
01165
01166 close(fds[1]);
01167 if (read(fds[0], buf, len) < 0) {
01168 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01169 }
01170 close(fds[0]);
01171 } else {
01172
01173 AST_DECLARE_APP_ARGS(arg,
01174 AST_APP_ARG(v)[20];
01175 );
01176 char *mycmd = ast_strdupa(command);
01177
01178 close(fds[0]);
01179 dup2(fds[1], STDOUT_FILENO);
01180 close(fds[1]);
01181 ast_close_fds_above_n(STDOUT_FILENO);
01182
01183 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01184
01185 execv(arg.v[0], arg.v);
01186 printf("FAILURE: %s", strerror(errno));
01187 _exit(0);
01188 }
01189 }
01190 return buf;
01191 }
01192
01193
01194
01195
01196
01197
01198
01199
01200 static int check_password(struct ast_vm_user *vmu, char *password)
01201 {
01202
01203 if (strlen(password) < minpassword)
01204 return 1;
01205 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01206 char cmd[255], buf[255];
01207
01208 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01209
01210 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01211 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01212 ast_debug(5, "Result: %s\n", buf);
01213 if (!strncasecmp(buf, "VALID", 5)) {
01214 ast_debug(3, "Passed password check: '%s'\n", buf);
01215 return 0;
01216 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01217 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01218 return 0;
01219 } else {
01220 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01221 return 1;
01222 }
01223 }
01224 }
01225 return 0;
01226 }
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01239 {
01240 int res = -1;
01241 if (!strcmp(vmu->password, password)) {
01242
01243 return 0;
01244 }
01245
01246 if (strlen(password) > 10) {
01247 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01248 }
01249 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01250 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01251 res = 0;
01252 }
01253 return res;
01254 }
01255
01256
01257
01258
01259 static void apply_options(struct ast_vm_user *vmu, const char *options)
01260 {
01261 char *stringp;
01262 char *s;
01263 char *var, *value;
01264 stringp = ast_strdupa(options);
01265 while ((s = strsep(&stringp, "|"))) {
01266 value = s;
01267 if ((var = strsep(&value, "=")) && value) {
01268 apply_option(vmu, var, value);
01269 }
01270 }
01271 }
01272
01273
01274
01275
01276
01277
01278 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01279 {
01280 for (; var; var = var->next) {
01281 if (!strcasecmp(var->name, "vmsecret")) {
01282 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01283 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01284 if (ast_strlen_zero(retval->password))
01285 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01286 } else if (!strcasecmp(var->name, "uniqueid")) {
01287 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01288 } else if (!strcasecmp(var->name, "pager")) {
01289 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01290 } else if (!strcasecmp(var->name, "email")) {
01291 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01292 } else if (!strcasecmp(var->name, "fullname")) {
01293 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01294 } else if (!strcasecmp(var->name, "context")) {
01295 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01296 } else if (!strcasecmp(var->name, "emailsubject")) {
01297 retval->emailsubject = ast_strdup(var->value);
01298 } else if (!strcasecmp(var->name, "emailbody")) {
01299 retval->emailbody = ast_strdup(var->value);
01300 #ifdef IMAP_STORAGE
01301 } else if (!strcasecmp(var->name, "imapuser")) {
01302 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01303 retval->imapversion = imapversion;
01304 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01305 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01306 retval->imapversion = imapversion;
01307 } else if (!strcasecmp(var->name, "imapfolder")) {
01308 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01309 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01310 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01311 retval->imapversion = imapversion;
01312 #endif
01313 } else
01314 apply_option(retval, var->name, var->value);
01315 }
01316 }
01317
01318
01319
01320
01321
01322
01323
01324
01325 static int is_valid_dtmf(const char *key)
01326 {
01327 int i;
01328 char *local_key = ast_strdupa(key);
01329
01330 for (i = 0; i < strlen(key); ++i) {
01331 if (!strchr(VALID_DTMF, *local_key)) {
01332 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01333 return 0;
01334 }
01335 local_key++;
01336 }
01337 return 1;
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01351 {
01352 struct ast_variable *var;
01353 struct ast_vm_user *retval;
01354
01355 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01356 if (!ivm)
01357 ast_set_flag(retval, VM_ALLOCED);
01358 else
01359 memset(retval, 0, sizeof(*retval));
01360 if (mailbox)
01361 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01362 populate_defaults(retval);
01363 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01364 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01365 else
01366 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01367 if (var) {
01368 apply_options_full(retval, var);
01369 ast_variables_destroy(var);
01370 } else {
01371 if (!ivm)
01372 ast_free(retval);
01373 retval = NULL;
01374 }
01375 }
01376 return retval;
01377 }
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01388 {
01389
01390 struct ast_vm_user *vmu = NULL, *cur;
01391 AST_LIST_LOCK(&users);
01392
01393 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01394 context = "default";
01395
01396 AST_LIST_TRAVERSE(&users, cur, list) {
01397 #ifdef IMAP_STORAGE
01398 if (cur->imapversion != imapversion) {
01399 continue;
01400 }
01401 #endif
01402 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01403 break;
01404 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01405 break;
01406 }
01407 if (cur) {
01408
01409 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01410 memcpy(vmu, cur, sizeof(*vmu));
01411 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01412 AST_LIST_NEXT(vmu, list) = NULL;
01413 }
01414 } else
01415 vmu = find_user_realtime(ivm, context, mailbox);
01416 AST_LIST_UNLOCK(&users);
01417 return vmu;
01418 }
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01431 {
01432
01433 struct ast_vm_user *cur;
01434 int res = -1;
01435 AST_LIST_LOCK(&users);
01436 AST_LIST_TRAVERSE(&users, cur, list) {
01437 if ((!context || !strcasecmp(context, cur->context)) &&
01438 (!strcasecmp(mailbox, cur->mailbox)))
01439 break;
01440 }
01441 if (cur) {
01442 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01443 res = 0;
01444 }
01445 AST_LIST_UNLOCK(&users);
01446 return res;
01447 }
01448
01449
01450
01451
01452
01453
01454
01455
01456 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01457 {
01458 struct ast_config *cfg = NULL;
01459 struct ast_variable *var = NULL;
01460 struct ast_category *cat = NULL;
01461 char *category = NULL, *value = NULL, *new = NULL;
01462 const char *tmp = NULL;
01463 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01464 char secretfn[PATH_MAX] = "";
01465 int found = 0;
01466
01467 if (!change_password_realtime(vmu, newpassword))
01468 return;
01469
01470
01471 switch (vmu->passwordlocation) {
01472 case OPT_PWLOC_SPOOLDIR:
01473 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01474 if (write_password_to_file(secretfn, newpassword) == 0) {
01475 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01476 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01477 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01478 break;
01479 } else {
01480 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01481 }
01482
01483 case OPT_PWLOC_VOICEMAILCONF:
01484 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01485 while ((category = ast_category_browse(cfg, category))) {
01486 if (!strcasecmp(category, vmu->context)) {
01487 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01488 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01489 break;
01490 }
01491 value = strstr(tmp, ",");
01492 if (!value) {
01493 new = alloca(strlen(newpassword)+1);
01494 sprintf(new, "%s", newpassword);
01495 } else {
01496 new = alloca((strlen(value) + strlen(newpassword) + 1));
01497 sprintf(new, "%s%s", newpassword, value);
01498 }
01499 if (!(cat = ast_category_get(cfg, category))) {
01500 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01501 break;
01502 }
01503 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01504 found = 1;
01505 }
01506 }
01507
01508 if (found) {
01509 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01510 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01511 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01512 break;
01513 }
01514 }
01515
01516 case OPT_PWLOC_USERSCONF:
01517
01518
01519 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01520 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01521 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01522 ast_debug(4, "users.conf: %s\n", category);
01523 if (!strcasecmp(category, vmu->mailbox)) {
01524 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01525 ast_debug(3, "looks like we need to make vmsecret!\n");
01526 var = ast_variable_new("vmsecret", newpassword, "");
01527 } else {
01528 var = NULL;
01529 }
01530 new = alloca(strlen(newpassword) + 1);
01531 sprintf(new, "%s", newpassword);
01532 if (!(cat = ast_category_get(cfg, category))) {
01533 ast_debug(4, "failed to get category!\n");
01534 ast_free(var);
01535 break;
01536 }
01537 if (!var) {
01538 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01539 } else {
01540 ast_variable_append(cat, var);
01541 }
01542 found = 1;
01543 break;
01544 }
01545 }
01546
01547 if (found) {
01548 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01549 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01550 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01551 }
01552 }
01553 }
01554 }
01555
01556 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01557 {
01558 char buf[255];
01559 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01560 if (!ast_safe_system(buf)) {
01561 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01562
01563 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01564 }
01565 }
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01581 {
01582 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01583 }
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597 static int make_file(char *dest, const int len, const char *dir, const int num)
01598 {
01599 return snprintf(dest, len, "%s/msg%04d", dir, num);
01600 }
01601
01602
01603 static FILE *vm_mkftemp(char *template)
01604 {
01605 FILE *p = NULL;
01606 int pfd = mkstemp(template);
01607 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01608 if (pfd > -1) {
01609 p = fdopen(pfd, "w+");
01610 if (!p) {
01611 close(pfd);
01612 pfd = -1;
01613 }
01614 }
01615 return p;
01616 }
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01627 {
01628 mode_t mode = VOICEMAIL_DIR_MODE;
01629 int res;
01630
01631 make_dir(dest, len, context, ext, folder);
01632 if ((res = ast_mkdir(dest, mode))) {
01633 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01634 return -1;
01635 }
01636 return 0;
01637 }
01638
01639 static const char * const mailbox_folders[] = {
01640 #ifdef IMAP_STORAGE
01641 imapfolder,
01642 #else
01643 "INBOX",
01644 #endif
01645 "Old",
01646 "Work",
01647 "Family",
01648 "Friends",
01649 "Cust1",
01650 "Cust2",
01651 "Cust3",
01652 "Cust4",
01653 "Cust5",
01654 "Deleted",
01655 "Urgent",
01656 };
01657
01658 static const char *mbox(struct ast_vm_user *vmu, int id)
01659 {
01660 #ifdef IMAP_STORAGE
01661 if (vmu && id == 0) {
01662 return vmu->imapfolder;
01663 }
01664 #endif
01665 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01666 }
01667
01668 static int get_folder_by_name(const char *name)
01669 {
01670 size_t i;
01671
01672 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01673 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01674 return i;
01675 }
01676 }
01677
01678 return -1;
01679 }
01680
01681 static void free_user(struct ast_vm_user *vmu)
01682 {
01683 if (ast_test_flag(vmu, VM_ALLOCED)) {
01684 if (vmu->emailbody != NULL) {
01685 ast_free(vmu->emailbody);
01686 vmu->emailbody = NULL;
01687 }
01688 if (vmu->emailsubject != NULL) {
01689 ast_free(vmu->emailsubject);
01690 vmu->emailsubject = NULL;
01691 }
01692 ast_free(vmu);
01693 }
01694 }
01695
01696 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01697
01698 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01699 if (!vms->dh_arraysize) {
01700
01701 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01702 return -1;
01703 }
01704 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01705 return -1;
01706 }
01707 vms->dh_arraysize = arraysize;
01708 } else if (vms->dh_arraysize < arraysize) {
01709 if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) {
01710 return -1;
01711 }
01712 if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) {
01713 return -1;
01714 }
01715 memset(vms->deleted, 0, arraysize * sizeof(int));
01716 memset(vms->heard, 0, arraysize * sizeof(int));
01717 vms->dh_arraysize = arraysize;
01718 }
01719
01720 return 0;
01721 }
01722
01723
01724
01725 #ifdef IMAP_STORAGE
01726 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01727 {
01728 char arg[10];
01729 struct vm_state *vms;
01730 unsigned long messageNum;
01731
01732
01733 if (msgnum < 0 && !imapgreetings) {
01734 ast_filedelete(file, NULL);
01735 return;
01736 }
01737
01738 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01739 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);
01740 return;
01741 }
01742
01743
01744
01745 messageNum = vms->msgArray[msgnum];
01746 if (messageNum == 0) {
01747 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01748 return;
01749 }
01750 if (option_debug > 2)
01751 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01752
01753 snprintf (arg, sizeof(arg), "%lu", messageNum);
01754 ast_mutex_lock(&vms->lock);
01755 mail_setflag (vms->mailstream, arg, "\\DELETED");
01756 mail_expunge(vms->mailstream);
01757 ast_mutex_unlock(&vms->lock);
01758 }
01759
01760 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01761 {
01762 struct vm_state *vms_p;
01763 char *file, *filename;
01764 char *attachment;
01765 int ret = 0, i;
01766 BODY *body;
01767
01768
01769
01770
01771 if (msgnum > -1 || !imapgreetings) {
01772 return 0;
01773 } else {
01774 file = strrchr(ast_strdupa(dir), '/');
01775 if (file)
01776 *file++ = '\0';
01777 else {
01778 ast_debug (1, "Failed to procure file name from directory passed.\n");
01779 return -1;
01780 }
01781 }
01782
01783
01784 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01785 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01786
01787
01788
01789
01790 if (!(vms_p = create_vm_state_from_user(vmu))) {
01791 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01792 return -1;
01793 }
01794 }
01795
01796
01797 *vms_p->introfn = '\0';
01798
01799 ast_mutex_lock(&vms_p->lock);
01800 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01801 if (!vms_p->mailstream) {
01802 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01803 ast_mutex_unlock(&vms_p->lock);
01804 return -1;
01805 }
01806
01807
01808 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01809 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01810
01811 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01812 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01813 } else {
01814 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01815 ast_mutex_unlock(&vms_p->lock);
01816 return -1;
01817 }
01818 filename = strsep(&attachment, ".");
01819 if (!strcmp(filename, file)) {
01820 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01821 vms_p->msgArray[vms_p->curmsg] = i + 1;
01822 save_body(body, vms_p, "2", attachment, 0);
01823 ast_mutex_unlock(&vms_p->lock);
01824 return 0;
01825 }
01826 }
01827 ast_mutex_unlock(&vms_p->lock);
01828
01829 return -1;
01830 }
01831
01832 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01833 {
01834 BODY *body;
01835 char *header_content;
01836 char *attachedfilefmt;
01837 char buf[80];
01838 struct vm_state *vms;
01839 char text_file[PATH_MAX];
01840 FILE *text_file_ptr;
01841 int res = 0;
01842 struct ast_vm_user *vmu;
01843
01844 if (!(vmu = find_user(NULL, context, mailbox))) {
01845 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01846 return -1;
01847 }
01848
01849 if (msgnum < 0) {
01850 if (imapgreetings) {
01851 res = imap_retrieve_greeting(dir, msgnum, vmu);
01852 goto exit;
01853 } else {
01854 res = 0;
01855 goto exit;
01856 }
01857 }
01858
01859
01860
01861
01862 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01863
01864
01865
01866
01867
01868
01869
01870 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01871 res = -1;
01872 goto exit;
01873 }
01874
01875 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01876 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01877
01878
01879 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01880 res = 0;
01881 goto exit;
01882 }
01883
01884 if (option_debug > 2)
01885 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01886 if (vms->msgArray[msgnum] == 0) {
01887 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01888 res = -1;
01889 goto exit;
01890 }
01891
01892
01893 ast_mutex_lock(&vms->lock);
01894 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01895 ast_mutex_unlock(&vms->lock);
01896
01897 if (ast_strlen_zero(header_content)) {
01898 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01899 res = -1;
01900 goto exit;
01901 }
01902
01903 ast_mutex_lock(&vms->lock);
01904 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01905 ast_mutex_unlock(&vms->lock);
01906
01907
01908 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01909 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01910 } else {
01911 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01912 res = -1;
01913 goto exit;
01914 }
01915
01916
01917
01918 strsep(&attachedfilefmt, ".");
01919 if (!attachedfilefmt) {
01920 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01921 res = -1;
01922 goto exit;
01923 }
01924
01925 save_body(body, vms, "2", attachedfilefmt, 0);
01926 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01927 *vms->introfn = '\0';
01928 }
01929
01930
01931 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01932
01933 if (!(text_file_ptr = fopen(text_file, "w"))) {
01934 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01935 }
01936
01937 fprintf(text_file_ptr, "%s\n", "[message]");
01938
01939 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01940 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01941 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01942 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01943 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01944 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01945 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01946 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01947 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01948 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01949 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01950 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01951 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01952 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01953 fclose(text_file_ptr);
01954
01955 exit:
01956 free_user(vmu);
01957 return res;
01958 }
01959
01960 static int folder_int(const char *folder)
01961 {
01962
01963 if (!folder) {
01964 return 0;
01965 }
01966 if (!strcasecmp(folder, imapfolder)) {
01967 return 0;
01968 } else if (!strcasecmp(folder, "Old")) {
01969 return 1;
01970 } else if (!strcasecmp(folder, "Work")) {
01971 return 2;
01972 } else if (!strcasecmp(folder, "Family")) {
01973 return 3;
01974 } else if (!strcasecmp(folder, "Friends")) {
01975 return 4;
01976 } else if (!strcasecmp(folder, "Cust1")) {
01977 return 5;
01978 } else if (!strcasecmp(folder, "Cust2")) {
01979 return 6;
01980 } else if (!strcasecmp(folder, "Cust3")) {
01981 return 7;
01982 } else if (!strcasecmp(folder, "Cust4")) {
01983 return 8;
01984 } else if (!strcasecmp(folder, "Cust5")) {
01985 return 9;
01986 } else if (!strcasecmp(folder, "Urgent")) {
01987 return 11;
01988 } else {
01989 return 0;
01990 }
01991 }
01992
01993 static int __messagecount(const char *context, const char *mailbox, const char *folder)
01994 {
01995 SEARCHPGM *pgm;
01996 SEARCHHEADER *hdr;
01997
01998 struct ast_vm_user *vmu, vmus;
01999 struct vm_state *vms_p;
02000 int ret = 0;
02001 int fold = folder_int(folder);
02002 int urgent = 0;
02003
02004
02005 if (fold == 11) {
02006 fold = NEW_FOLDER;
02007 urgent = 1;
02008 }
02009
02010 if (ast_strlen_zero(mailbox))
02011 return 0;
02012
02013
02014 vmu = find_user(&vmus, context, mailbox);
02015 if (!vmu) {
02016 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02017 return -1;
02018 } else {
02019
02020 if (vmu->imapuser[0] == '\0') {
02021 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02022 return -1;
02023 }
02024 }
02025
02026
02027 if (vmu->imapuser[0] == '\0') {
02028 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02029 free_user(vmu);
02030 return -1;
02031 }
02032
02033
02034 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02035 if (!vms_p) {
02036 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02037 }
02038 if (vms_p) {
02039 ast_debug(3, "Returning before search - user is logged in\n");
02040 if (fold == 0) {
02041 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02042 }
02043 if (fold == 1) {
02044 return vms_p->oldmessages;
02045 }
02046 }
02047
02048
02049 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02050 if (!vms_p) {
02051 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02052 }
02053
02054 if (!vms_p) {
02055 vms_p = create_vm_state_from_user(vmu);
02056 }
02057 ret = init_mailstream(vms_p, fold);
02058 if (!vms_p->mailstream) {
02059 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02060 return -1;
02061 }
02062 if (ret == 0) {
02063 ast_mutex_lock(&vms_p->lock);
02064 pgm = mail_newsearchpgm ();
02065 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02066 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02067 pgm->header = hdr;
02068 if (fold != OLD_FOLDER) {
02069 pgm->unseen = 1;
02070 pgm->seen = 0;
02071 }
02072
02073
02074
02075 else {
02076 pgm->unseen = 0;
02077 pgm->seen = 1;
02078 }
02079
02080 if (fold == NEW_FOLDER) {
02081 if (urgent) {
02082 pgm->flagged = 1;
02083 pgm->unflagged = 0;
02084 } else {
02085 pgm->flagged = 0;
02086 pgm->unflagged = 1;
02087 }
02088 }
02089 pgm->undeleted = 1;
02090 pgm->deleted = 0;
02091
02092 vms_p->vmArrayIndex = 0;
02093 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02094 if (fold == 0 && urgent == 0)
02095 vms_p->newmessages = vms_p->vmArrayIndex;
02096 if (fold == 1)
02097 vms_p->oldmessages = vms_p->vmArrayIndex;
02098 if (fold == 0 && urgent == 1)
02099 vms_p->urgentmessages = vms_p->vmArrayIndex;
02100
02101 mail_free_searchpgm(&pgm);
02102 ast_mutex_unlock(&vms_p->lock);
02103 vms_p->updated = 0;
02104 return vms_p->vmArrayIndex;
02105 } else {
02106 ast_mutex_lock(&vms_p->lock);
02107 mail_ping(vms_p->mailstream);
02108 ast_mutex_unlock(&vms_p->lock);
02109 }
02110 return 0;
02111 }
02112
02113 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02114 {
02115
02116 check_quota(vms, vmu->imapfolder);
02117 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02118 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02119 ast_play_and_wait(chan, "vm-mailboxfull");
02120 return -1;
02121 }
02122
02123
02124 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));
02125 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02126 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02127 ast_play_and_wait(chan, "vm-mailboxfull");
02128 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02129 return -1;
02130 }
02131
02132 return 0;
02133 }
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144 static int messagecount(const char *context, const char *mailbox, const char *folder)
02145 {
02146 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02147 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02148 } else {
02149 return __messagecount(context, mailbox, folder);
02150 }
02151 }
02152
02153 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)
02154 {
02155 char *myserveremail = serveremail;
02156 char fn[PATH_MAX];
02157 char introfn[PATH_MAX];
02158 char mailbox[256];
02159 char *stringp;
02160 FILE *p = NULL;
02161 char tmp[80] = "/tmp/astmail-XXXXXX";
02162 long len;
02163 void *buf;
02164 int tempcopy = 0;
02165 STRING str;
02166 int ret;
02167 char *imap_flags = NIL;
02168 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02169
02170
02171 if (msgnum < 0 && !imapgreetings) {
02172 return 0;
02173 }
02174
02175 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02176 return -1;
02177 }
02178
02179
02180 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02181 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02182 imap_flags = "\\FLAGGED";
02183 }
02184
02185
02186 fmt = ast_strdupa(fmt);
02187 stringp = fmt;
02188 strsep(&stringp, "|");
02189
02190 if (!ast_strlen_zero(vmu->serveremail))
02191 myserveremail = vmu->serveremail;
02192
02193 if (msgnum > -1)
02194 make_file(fn, sizeof(fn), dir, msgnum);
02195 else
02196 ast_copy_string (fn, dir, sizeof(fn));
02197
02198 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02199 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02200 *introfn = '\0';
02201 }
02202
02203 if (ast_strlen_zero(vmu->email)) {
02204
02205
02206
02207
02208
02209 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02210 tempcopy = 1;
02211 }
02212
02213 if (!strcmp(fmt, "wav49"))
02214 fmt = "WAV";
02215 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02216
02217
02218
02219 if (!(p = vm_mkftemp(tmp))) {
02220 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02221 if (tempcopy)
02222 *(vmu->email) = '\0';
02223 return -1;
02224 }
02225
02226 if (msgnum < 0 && imapgreetings) {
02227 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02228 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02229 return -1;
02230 }
02231 imap_delete_old_greeting(fn, vms);
02232 }
02233
02234 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02235 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02236 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02237 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02238
02239 len = ftell(p);
02240 rewind(p);
02241 if (!(buf = ast_malloc(len + 1))) {
02242 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02243 fclose(p);
02244 if (tempcopy)
02245 *(vmu->email) = '\0';
02246 return -1;
02247 }
02248 if (fread(buf, len, 1, p) < len) {
02249 if (ferror(p)) {
02250 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02251 return -1;
02252 }
02253 }
02254 ((char *) buf)[len] = '\0';
02255 INIT(&str, mail_string, buf, len);
02256 ret = init_mailstream(vms, NEW_FOLDER);
02257 if (ret == 0) {
02258 imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
02259 ast_mutex_lock(&vms->lock);
02260 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02261 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02262 ast_mutex_unlock(&vms->lock);
02263 fclose(p);
02264 unlink(tmp);
02265 ast_free(buf);
02266 } else {
02267 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02268 fclose(p);
02269 unlink(tmp);
02270 ast_free(buf);
02271 return -1;
02272 }
02273 ast_debug(3, "%s stored\n", fn);
02274
02275 if (tempcopy)
02276 *(vmu->email) = '\0';
02277 inprocess_count(vmu->mailbox, vmu->context, -1);
02278 return 0;
02279
02280 }
02281
02282
02283
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02296 {
02297 char tmp[PATH_MAX] = "";
02298 char *mailboxnc;
02299 char *context;
02300 char *mb;
02301 char *cur;
02302 if (newmsgs)
02303 *newmsgs = 0;
02304 if (oldmsgs)
02305 *oldmsgs = 0;
02306 if (urgentmsgs)
02307 *urgentmsgs = 0;
02308
02309 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02310
02311 if (ast_strlen_zero(mailbox_context))
02312 return 0;
02313
02314 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02315 context = strchr(tmp, '@');
02316 if (strchr(mailbox_context, ',')) {
02317 int tmpnew, tmpold, tmpurgent;
02318 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02319 mb = tmp;
02320 while ((cur = strsep(&mb, ", "))) {
02321 if (!ast_strlen_zero(cur)) {
02322 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02323 return -1;
02324 else {
02325 if (newmsgs)
02326 *newmsgs += tmpnew;
02327 if (oldmsgs)
02328 *oldmsgs += tmpold;
02329 if (urgentmsgs)
02330 *urgentmsgs += tmpurgent;
02331 }
02332 }
02333 }
02334 return 0;
02335 }
02336 if (context) {
02337 *context = '\0';
02338 mailboxnc = tmp;
02339 context++;
02340 } else {
02341 context = "default";
02342 mailboxnc = (char *) mailbox_context;
02343 }
02344
02345 if (newmsgs) {
02346 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02347 if (!vmu) {
02348 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02349 return -1;
02350 }
02351 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02352 return -1;
02353 }
02354 }
02355 if (oldmsgs) {
02356 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02357 return -1;
02358 }
02359 }
02360 if (urgentmsgs) {
02361 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02362 return -1;
02363 }
02364 }
02365 return 0;
02366 }
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378 static int has_voicemail(const char *mailbox, const char *folder)
02379 {
02380 char tmp[256], *tmp2, *box, *context;
02381 ast_copy_string(tmp, mailbox, sizeof(tmp));
02382 tmp2 = tmp;
02383 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02384 while ((box = strsep(&tmp2, ",&"))) {
02385 if (!ast_strlen_zero(box)) {
02386 if (has_voicemail(box, folder)) {
02387 return 1;
02388 }
02389 }
02390 }
02391 }
02392 if ((context = strchr(tmp, '@'))) {
02393 *context++ = '\0';
02394 } else {
02395 context = "default";
02396 }
02397 return __messagecount(context, tmp, folder) ? 1 : 0;
02398 }
02399
02400
02401
02402
02403
02404
02405
02406
02407
02408
02409
02410
02411
02412
02413
02414
02415 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)
02416 {
02417 struct vm_state *sendvms = NULL, *destvms = NULL;
02418 char messagestring[10];
02419 if (msgnum >= recip->maxmsg) {
02420 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02421 return -1;
02422 }
02423 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02424 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02425 return -1;
02426 }
02427 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02428 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02429 return -1;
02430 }
02431 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02432 ast_mutex_lock(&sendvms->lock);
02433 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02434 ast_mutex_unlock(&sendvms->lock);
02435 return 0;
02436 }
02437 ast_mutex_unlock(&sendvms->lock);
02438 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02439 return -1;
02440 }
02441
02442 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02443 {
02444 char tmp[256], *t = tmp;
02445 size_t left = sizeof(tmp);
02446
02447 if (box == OLD_FOLDER) {
02448 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02449 } else {
02450 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02451 }
02452
02453 if (box == NEW_FOLDER) {
02454 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02455 } else {
02456 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02457 }
02458
02459
02460 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02461
02462
02463 if (!ast_strlen_zero(authuser))
02464 ast_build_string(&t, &left, "/authuser=%s", authuser);
02465
02466
02467 if (!ast_strlen_zero(imapflags))
02468 ast_build_string(&t, &left, "/%s", imapflags);
02469
02470
02471 #if 1
02472 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02473 #else
02474 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02475 #endif
02476 if (box == NEW_FOLDER || box == OLD_FOLDER)
02477 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02478 else if (box == GREETINGS_FOLDER)
02479 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02480 else {
02481 if (!ast_strlen_zero(imapparentfolder)) {
02482
02483 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02484 } else {
02485 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02486 }
02487 }
02488 }
02489
02490 static int init_mailstream(struct vm_state *vms, int box)
02491 {
02492 MAILSTREAM *stream = NIL;
02493 long debug;
02494 char tmp[256];
02495
02496 if (!vms) {
02497 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02498 return -1;
02499 }
02500 if (option_debug > 2)
02501 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02502 if (vms->mailstream == NIL || !vms->mailstream) {
02503 if (option_debug)
02504 ast_log(LOG_DEBUG, "mailstream not set.\n");
02505 } else {
02506 stream = vms->mailstream;
02507 }
02508
02509 debug = NIL;
02510
02511 if (delimiter == '\0') {
02512 char *cp;
02513 #ifdef USE_SYSTEM_IMAP
02514 #include <imap/linkage.c>
02515 #elif defined(USE_SYSTEM_CCLIENT)
02516 #include <c-client/linkage.c>
02517 #else
02518 #include "linkage.c"
02519 #endif
02520
02521 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02522 ast_mutex_lock(&vms->lock);
02523 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02524 ast_mutex_unlock(&vms->lock);
02525 if (stream == NIL) {
02526 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02527 return -1;
02528 }
02529 get_mailbox_delimiter(stream);
02530
02531 for (cp = vms->imapfolder; *cp; cp++)
02532 if (*cp == '/')
02533 *cp = delimiter;
02534 }
02535
02536 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02537 if (option_debug > 2)
02538 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02539 ast_mutex_lock(&vms->lock);
02540 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02541 ast_mutex_unlock(&vms->lock);
02542 if (vms->mailstream == NIL) {
02543 return -1;
02544 } else {
02545 return 0;
02546 }
02547 }
02548
02549 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02550 {
02551 SEARCHPGM *pgm;
02552 SEARCHHEADER *hdr;
02553 int ret, urgent = 0;
02554
02555
02556 if (box == 11) {
02557 box = NEW_FOLDER;
02558 urgent = 1;
02559 }
02560
02561 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02562 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02563 vms->imapversion = vmu->imapversion;
02564 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02565
02566 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02567 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02568 return -1;
02569 }
02570
02571 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02572
02573
02574 if (box == 0) {
02575 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02576 check_quota(vms, (char *) mbox(vmu, box));
02577 }
02578
02579 ast_mutex_lock(&vms->lock);
02580 pgm = mail_newsearchpgm();
02581
02582
02583 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02584 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02585 pgm->header = hdr;
02586 pgm->deleted = 0;
02587 pgm->undeleted = 1;
02588
02589
02590 if (box == NEW_FOLDER && urgent == 1) {
02591 pgm->unseen = 1;
02592 pgm->seen = 0;
02593 pgm->flagged = 1;
02594 pgm->unflagged = 0;
02595 } else if (box == NEW_FOLDER && urgent == 0) {
02596 pgm->unseen = 1;
02597 pgm->seen = 0;
02598 pgm->flagged = 0;
02599 pgm->unflagged = 1;
02600 } else if (box == OLD_FOLDER) {
02601 pgm->seen = 1;
02602 pgm->unseen = 0;
02603 }
02604
02605 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02606
02607 vms->vmArrayIndex = 0;
02608 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02609 vms->lastmsg = vms->vmArrayIndex - 1;
02610 mail_free_searchpgm(&pgm);
02611
02612
02613
02614
02615 if (box == 0 && !vms->dh_arraysize) {
02616 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02617 }
02618 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02619 ast_mutex_unlock(&vms->lock);
02620 return -1;
02621 }
02622
02623 ast_mutex_unlock(&vms->lock);
02624 return 0;
02625 }
02626
02627 static void write_file(char *filename, char *buffer, unsigned long len)
02628 {
02629 FILE *output;
02630
02631 output = fopen (filename, "w");
02632 if (fwrite(buffer, len, 1, output) != 1) {
02633 if (ferror(output)) {
02634 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02635 }
02636 }
02637 fclose (output);
02638 }
02639
02640 static void update_messages_by_imapuser(const char *user, unsigned long number)
02641 {
02642 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02643
02644 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02645 return;
02646 }
02647
02648 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02649 vms->msgArray[vms->vmArrayIndex++] = number;
02650 }
02651
02652 void mm_searched(MAILSTREAM *stream, unsigned long number)
02653 {
02654 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02655
02656 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02657 return;
02658
02659 update_messages_by_imapuser(user, number);
02660 }
02661
02662 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02663 {
02664 struct ast_variable *var;
02665 struct ast_vm_user *vmu;
02666
02667 vmu = ast_calloc(1, sizeof *vmu);
02668 if (!vmu)
02669 return NULL;
02670 ast_set_flag(vmu, VM_ALLOCED);
02671 populate_defaults(vmu);
02672
02673 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02674 if (var) {
02675 apply_options_full(vmu, var);
02676 ast_variables_destroy(var);
02677 return vmu;
02678 } else {
02679 ast_free(vmu);
02680 return NULL;
02681 }
02682 }
02683
02684
02685
02686 void mm_exists(MAILSTREAM * stream, unsigned long number)
02687 {
02688
02689 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02690 if (number == 0) return;
02691 set_update(stream);
02692 }
02693
02694
02695 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02696 {
02697
02698 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02699 if (number == 0) return;
02700 set_update(stream);
02701 }
02702
02703
02704 void mm_flags(MAILSTREAM * stream, unsigned long number)
02705 {
02706
02707 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02708 if (number == 0) return;
02709 set_update(stream);
02710 }
02711
02712
02713 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02714 {
02715 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02716 mm_log (string, errflg);
02717 }
02718
02719
02720 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02721 {
02722 if (delimiter == '\0') {
02723 delimiter = delim;
02724 }
02725
02726 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02727 if (attributes & LATT_NOINFERIORS)
02728 ast_debug(5, "no inferiors\n");
02729 if (attributes & LATT_NOSELECT)
02730 ast_debug(5, "no select\n");
02731 if (attributes & LATT_MARKED)
02732 ast_debug(5, "marked\n");
02733 if (attributes & LATT_UNMARKED)
02734 ast_debug(5, "unmarked\n");
02735 }
02736
02737
02738 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02739 {
02740 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02741 if (attributes & LATT_NOINFERIORS)
02742 ast_debug(5, "no inferiors\n");
02743 if (attributes & LATT_NOSELECT)
02744 ast_debug(5, "no select\n");
02745 if (attributes & LATT_MARKED)
02746 ast_debug(5, "marked\n");
02747 if (attributes & LATT_UNMARKED)
02748 ast_debug(5, "unmarked\n");
02749 }
02750
02751
02752 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02753 {
02754 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02755 if (status->flags & SA_MESSAGES)
02756 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02757 if (status->flags & SA_RECENT)
02758 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02759 if (status->flags & SA_UNSEEN)
02760 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02761 if (status->flags & SA_UIDVALIDITY)
02762 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02763 if (status->flags & SA_UIDNEXT)
02764 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02765 ast_log(AST_LOG_NOTICE, "\n");
02766 }
02767
02768
02769 void mm_log(char *string, long errflg)
02770 {
02771 switch ((short) errflg) {
02772 case NIL:
02773 ast_debug(1, "IMAP Info: %s\n", string);
02774 break;
02775 case PARSE:
02776 case WARN:
02777 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02778 break;
02779 case ERROR:
02780 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02781 break;
02782 }
02783 }
02784
02785
02786 void mm_dlog(char *string)
02787 {
02788 ast_log(AST_LOG_NOTICE, "%s\n", string);
02789 }
02790
02791
02792 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02793 {
02794 struct ast_vm_user *vmu;
02795
02796 ast_debug(4, "Entering callback mm_login\n");
02797
02798 ast_copy_string(user, mb->user, MAILTMPLEN);
02799
02800
02801 if (!ast_strlen_zero(authpassword)) {
02802 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02803 } else {
02804 AST_LIST_TRAVERSE(&users, vmu, list) {
02805 if (!strcasecmp(mb->user, vmu->imapuser)) {
02806 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02807 break;
02808 }
02809 }
02810 if (!vmu) {
02811 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02812 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02813 free_user(vmu);
02814 }
02815 }
02816 }
02817 }
02818
02819
02820 void mm_critical(MAILSTREAM * stream)
02821 {
02822 }
02823
02824
02825 void mm_nocritical(MAILSTREAM * stream)
02826 {
02827 }
02828
02829
02830 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02831 {
02832 kill (getpid (), SIGSTOP);
02833 return NIL;
02834 }
02835
02836
02837 void mm_fatal(char *string)
02838 {
02839 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02840 }
02841
02842
02843 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02844 {
02845 struct vm_state *vms;
02846 char *mailbox = stream->mailbox, *user;
02847 char buf[1024] = "";
02848 unsigned long usage = 0, limit = 0;
02849
02850 while (pquota) {
02851 usage = pquota->usage;
02852 limit = pquota->limit;
02853 pquota = pquota->next;
02854 }
02855
02856 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)))) {
02857 ast_log(AST_LOG_ERROR, "No state found.\n");
02858 return;
02859 }
02860
02861 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02862
02863 vms->quota_usage = usage;
02864 vms->quota_limit = limit;
02865 }
02866
02867 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02868 {
02869 char *start, *eol_pnt;
02870 int taglen;
02871
02872 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02873 return NULL;
02874
02875 taglen = strlen(tag) + 1;
02876 if (taglen < 1)
02877 return NULL;
02878
02879 if (!(start = strstr(header, tag)))
02880 return NULL;
02881
02882
02883 memset(buf, 0, len);
02884
02885 ast_copy_string(buf, start+taglen, len);
02886 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02887 *eol_pnt = '\0';
02888 return buf;
02889 }
02890
02891 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02892 {
02893 char *start, *quote, *eol_pnt;
02894
02895 if (ast_strlen_zero(mailbox))
02896 return NULL;
02897
02898 if (!(start = strstr(mailbox, "/user=")))
02899 return NULL;
02900
02901 ast_copy_string(buf, start+6, len);
02902
02903 if (!(quote = strchr(buf, '\"'))) {
02904 if (!(eol_pnt = strchr(buf, '/')))
02905 eol_pnt = strchr(buf,'}');
02906 *eol_pnt = '\0';
02907 return buf;
02908 } else {
02909 eol_pnt = strchr(buf+1,'\"');
02910 *eol_pnt = '\0';
02911 return buf+1;
02912 }
02913 }
02914
02915 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02916 {
02917 struct vm_state *vms_p;
02918
02919 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02920 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02921 return vms_p;
02922 }
02923 if (option_debug > 4)
02924 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02925 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02926 return NULL;
02927 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02928 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02929 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02930 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02931 vms_p->mailstream = NIL;
02932 vms_p->imapversion = vmu->imapversion;
02933 if (option_debug > 4)
02934 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02935 vms_p->updated = 1;
02936
02937 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
02938 init_vm_state(vms_p);
02939 vmstate_insert(vms_p);
02940 return vms_p;
02941 }
02942
02943 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02944 {
02945 struct vmstate *vlist = NULL;
02946
02947 if (interactive) {
02948 struct vm_state *vms;
02949 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02950 vms = pthread_getspecific(ts_vmstate.key);
02951 return vms;
02952 }
02953
02954 AST_LIST_LOCK(&vmstates);
02955 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02956 if (!vlist->vms) {
02957 ast_debug(3, "error: vms is NULL for %s\n", user);
02958 continue;
02959 }
02960 if (vlist->vms->imapversion != imapversion) {
02961 continue;
02962 }
02963 if (!vlist->vms->imapuser) {
02964 ast_debug(3, "error: imapuser is NULL for %s\n", user);
02965 continue;
02966 }
02967
02968 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
02969 AST_LIST_UNLOCK(&vmstates);
02970 return vlist->vms;
02971 }
02972 }
02973 AST_LIST_UNLOCK(&vmstates);
02974
02975 ast_debug(3, "%s not found in vmstates\n", user);
02976
02977 return NULL;
02978 }
02979
02980 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02981 {
02982
02983 struct vmstate *vlist = NULL;
02984 const char *local_context = S_OR(context, "default");
02985
02986 if (interactive) {
02987 struct vm_state *vms;
02988 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02989 vms = pthread_getspecific(ts_vmstate.key);
02990 return vms;
02991 }
02992
02993 AST_LIST_LOCK(&vmstates);
02994 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02995 if (!vlist->vms) {
02996 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
02997 continue;
02998 }
02999 if (vlist->vms->imapversion != imapversion) {
03000 continue;
03001 }
03002 if (!vlist->vms->username || !vlist->vms->context) {
03003 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03004 continue;
03005 }
03006
03007 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);
03008
03009 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03010 ast_debug(3, "Found it!\n");
03011 AST_LIST_UNLOCK(&vmstates);
03012 return vlist->vms;
03013 }
03014 }
03015 AST_LIST_UNLOCK(&vmstates);
03016
03017 ast_debug(3, "%s not found in vmstates\n", mailbox);
03018
03019 return NULL;
03020 }
03021
03022 static void vmstate_insert(struct vm_state *vms)
03023 {
03024 struct vmstate *v;
03025 struct vm_state *altvms;
03026
03027
03028
03029
03030 if (vms->interactive == 1) {
03031 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03032 if (altvms) {
03033 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03034 vms->newmessages = altvms->newmessages;
03035 vms->oldmessages = altvms->oldmessages;
03036 vms->vmArrayIndex = altvms->vmArrayIndex;
03037 vms->lastmsg = altvms->lastmsg;
03038 vms->curmsg = altvms->curmsg;
03039
03040 vms->persist_vms = altvms;
03041
03042 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03043 vms->mailstream = altvms->mailstream;
03044 #else
03045 vms->mailstream = NIL;
03046 #endif
03047 }
03048 return;
03049 }
03050
03051 if (!(v = ast_calloc(1, sizeof(*v))))
03052 return;
03053
03054 v->vms = vms;
03055
03056 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03057
03058 AST_LIST_LOCK(&vmstates);
03059 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03060 AST_LIST_UNLOCK(&vmstates);
03061 }
03062
03063 static void vmstate_delete(struct vm_state *vms)
03064 {
03065 struct vmstate *vc = NULL;
03066 struct vm_state *altvms = NULL;
03067
03068
03069
03070 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03071 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03072 altvms->newmessages = vms->newmessages;
03073 altvms->oldmessages = vms->oldmessages;
03074 altvms->updated = 1;
03075 vms->mailstream = mail_close(vms->mailstream);
03076
03077
03078 return;
03079 }
03080
03081 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03082
03083 AST_LIST_LOCK(&vmstates);
03084 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03085 if (vc->vms == vms) {
03086 AST_LIST_REMOVE_CURRENT(list);
03087 break;
03088 }
03089 }
03090 AST_LIST_TRAVERSE_SAFE_END
03091 AST_LIST_UNLOCK(&vmstates);
03092
03093 if (vc) {
03094 ast_mutex_destroy(&vc->vms->lock);
03095 ast_free(vc);
03096 }
03097 else
03098 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03099 }
03100
03101 static void set_update(MAILSTREAM * stream)
03102 {
03103 struct vm_state *vms;
03104 char *mailbox = stream->mailbox, *user;
03105 char buf[1024] = "";
03106
03107 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03108 if (user && option_debug > 2)
03109 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03110 return;
03111 }
03112
03113 ast_debug(3, "User %s mailbox set for update.\n", user);
03114
03115 vms->updated = 1;
03116 }
03117
03118 static void init_vm_state(struct vm_state *vms)
03119 {
03120 int x;
03121 vms->vmArrayIndex = 0;
03122 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03123 vms->msgArray[x] = 0;
03124 }
03125 ast_mutex_init(&vms->lock);
03126 }
03127
03128 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03129 {
03130 char *body_content;
03131 char *body_decoded;
03132 char *fn = is_intro ? vms->introfn : vms->fn;
03133 unsigned long len;
03134 unsigned long newlen;
03135 char filename[256];
03136
03137 if (!body || body == NIL)
03138 return -1;
03139
03140 ast_mutex_lock(&vms->lock);
03141 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03142 ast_mutex_unlock(&vms->lock);
03143 if (body_content != NIL) {
03144 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03145
03146 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03147
03148 if (!newlen) {
03149 return -1;
03150 }
03151 write_file(filename, (char *) body_decoded, newlen);
03152 } else {
03153 ast_debug(5, "Body of message is NULL.\n");
03154 return -1;
03155 }
03156 return 0;
03157 }
03158
03159
03160
03161
03162
03163
03164
03165
03166 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03167 char tmp[50];
03168 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03169 mail_list(stream, tmp, "*");
03170 }
03171
03172
03173
03174
03175
03176
03177
03178
03179 static void check_quota(struct vm_state *vms, char *mailbox) {
03180 ast_mutex_lock(&vms->lock);
03181 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03182 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03183 if (vms && vms->mailstream != NULL) {
03184 imap_getquotaroot(vms->mailstream, mailbox);
03185 } else {
03186 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03187 }
03188 ast_mutex_unlock(&vms->lock);
03189 }
03190
03191 #endif
03192
03193
03194
03195
03196
03197 static int vm_lock_path(const char *path)
03198 {
03199 switch (ast_lock_path(path)) {
03200 case AST_LOCK_TIMEOUT:
03201 return -1;
03202 default:
03203 return 0;
03204 }
03205 }
03206
03207
03208 #ifdef ODBC_STORAGE
03209 struct generic_prepare_struct {
03210 char *sql;
03211 int argc;
03212 char **argv;
03213 };
03214
03215 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03216 {
03217 struct generic_prepare_struct *gps = data;
03218 int res, i;
03219 SQLHSTMT stmt;
03220
03221 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03222 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03223 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03224 return NULL;
03225 }
03226 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03227 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03228 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03229 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03230 return NULL;
03231 }
03232 for (i = 0; i < gps->argc; i++)
03233 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03234
03235 return stmt;
03236 }
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246
03247
03248
03249
03250
03251
03252 static int retrieve_file(char *dir, int msgnum)
03253 {
03254 int x = 0;
03255 int res;
03256 int fd = -1;
03257 size_t fdlen = 0;
03258 void *fdm = MAP_FAILED;
03259 SQLSMALLINT colcount = 0;
03260 SQLHSTMT stmt;
03261 char sql[PATH_MAX];
03262 char fmt[80]="";
03263 char *c;
03264 char coltitle[256];
03265 SQLSMALLINT collen;
03266 SQLSMALLINT datatype;
03267 SQLSMALLINT decimaldigits;
03268 SQLSMALLINT nullable;
03269 SQLULEN colsize;
03270 SQLLEN colsize2;
03271 FILE *f = NULL;
03272 char rowdata[80];
03273 char fn[PATH_MAX];
03274 char full_fn[PATH_MAX];
03275 char msgnums[80];
03276 char *argv[] = { dir, msgnums };
03277 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03278
03279 struct odbc_obj *obj;
03280 obj = ast_odbc_request_obj(odbc_database, 0);
03281 if (obj) {
03282 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03283 c = strchr(fmt, '|');
03284 if (c)
03285 *c = '\0';
03286 if (!strcasecmp(fmt, "wav49"))
03287 strcpy(fmt, "WAV");
03288 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03289 if (msgnum > -1)
03290 make_file(fn, sizeof(fn), dir, msgnum);
03291 else
03292 ast_copy_string(fn, dir, sizeof(fn));
03293
03294
03295 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03296
03297 if (!(f = fopen(full_fn, "w+"))) {
03298 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03299 goto yuck;
03300 }
03301
03302 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03303 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03304 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03305 if (!stmt) {
03306 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03307 ast_odbc_release_obj(obj);
03308 goto yuck;
03309 }
03310 res = SQLFetch(stmt);
03311 if (res == SQL_NO_DATA) {
03312 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03313 ast_odbc_release_obj(obj);
03314 goto yuck;
03315 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03316 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03317 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03318 ast_odbc_release_obj(obj);
03319 goto yuck;
03320 }
03321 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03322 if (fd < 0) {
03323 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03324 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03325 ast_odbc_release_obj(obj);
03326 goto yuck;
03327 }
03328 res = SQLNumResultCols(stmt, &colcount);
03329 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03330 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03331 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03332 ast_odbc_release_obj(obj);
03333 goto yuck;
03334 }
03335 if (f)
03336 fprintf(f, "[message]\n");
03337 for (x = 0; x < colcount; x++) {
03338 rowdata[0] = '\0';
03339 collen = sizeof(coltitle);
03340 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03341 &datatype, &colsize, &decimaldigits, &nullable);
03342 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03343 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03344 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03345 ast_odbc_release_obj(obj);
03346 goto yuck;
03347 }
03348 if (!strcasecmp(coltitle, "recording")) {
03349 off_t offset;
03350 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03351 fdlen = colsize2;
03352 if (fd > -1) {
03353 char tmp[1]="";
03354 lseek(fd, fdlen - 1, SEEK_SET);
03355 if (write(fd, tmp, 1) != 1) {
03356 close(fd);
03357 fd = -1;
03358 continue;
03359 }
03360
03361 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03362 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03363 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03364 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03365 ast_odbc_release_obj(obj);
03366 goto yuck;
03367 } else {
03368 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03369 munmap(fdm, CHUNKSIZE);
03370 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03371 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03372 unlink(full_fn);
03373 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03374 ast_odbc_release_obj(obj);
03375 goto yuck;
03376 }
03377 }
03378 }
03379 if (truncate(full_fn, fdlen) < 0) {
03380 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03381 }
03382 }
03383 } else {
03384 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03385 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03386 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03387 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03388 ast_odbc_release_obj(obj);
03389 goto yuck;
03390 }
03391 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03392 fprintf(f, "%s=%s\n", coltitle, rowdata);
03393 }
03394 }
03395 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03396 ast_odbc_release_obj(obj);
03397 } else
03398 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03399 yuck:
03400 if (f)
03401 fclose(f);
03402 if (fd > -1)
03403 close(fd);
03404 return x - 1;
03405 }
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415
03416
03417 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03418 {
03419 int x = 0;
03420 int res;
03421 SQLHSTMT stmt;
03422 char sql[PATH_MAX];
03423 char rowdata[20];
03424 char *argv[] = { dir };
03425 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03426
03427 struct odbc_obj *obj;
03428 obj = ast_odbc_request_obj(odbc_database, 0);
03429 if (obj) {
03430 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03431 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03432 if (!stmt) {
03433 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03434 ast_odbc_release_obj(obj);
03435 goto yuck;
03436 }
03437 res = SQLFetch(stmt);
03438 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03439 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03440 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03441 ast_odbc_release_obj(obj);
03442 goto yuck;
03443 }
03444 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03445 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03446 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03447 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03448 ast_odbc_release_obj(obj);
03449 goto yuck;
03450 }
03451 if (sscanf(rowdata, "%30d", &x) != 1)
03452 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03453 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03454 ast_odbc_release_obj(obj);
03455 } else
03456 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03457 yuck:
03458 return x - 1;
03459 }
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469
03470 static int message_exists(char *dir, int msgnum)
03471 {
03472 int x = 0;
03473 int res;
03474 SQLHSTMT stmt;
03475 char sql[PATH_MAX];
03476 char rowdata[20];
03477 char msgnums[20];
03478 char *argv[] = { dir, msgnums };
03479 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03480
03481 struct odbc_obj *obj;
03482 obj = ast_odbc_request_obj(odbc_database, 0);
03483 if (obj) {
03484 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03485 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03486 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03487 if (!stmt) {
03488 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03489 ast_odbc_release_obj(obj);
03490 goto yuck;
03491 }
03492 res = SQLFetch(stmt);
03493 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03494 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03495 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03496 ast_odbc_release_obj(obj);
03497 goto yuck;
03498 }
03499 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03500 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03501 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03502 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03503 ast_odbc_release_obj(obj);
03504 goto yuck;
03505 }
03506 if (sscanf(rowdata, "%30d", &x) != 1)
03507 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03508 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03509 ast_odbc_release_obj(obj);
03510 } else
03511 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03512 yuck:
03513 return x;
03514 }
03515
03516
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526
03527
03528 static int count_messages(struct ast_vm_user *vmu, char *dir)
03529 {
03530 return last_message_index(vmu, dir) + 1;
03531 }
03532
03533
03534
03535
03536
03537
03538
03539
03540
03541
03542
03543 static void delete_file(const char *sdir, int smsg)
03544 {
03545 SQLHSTMT stmt;
03546 char sql[PATH_MAX];
03547 char msgnums[20];
03548 char *argv[] = { NULL, msgnums };
03549 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03550 struct odbc_obj *obj;
03551
03552 argv[0] = ast_strdupa(sdir);
03553
03554 obj = ast_odbc_request_obj(odbc_database, 0);
03555 if (obj) {
03556 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03557 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03558 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03559 if (!stmt)
03560 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03561 else
03562 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03563 ast_odbc_release_obj(obj);
03564 } else
03565 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03566 return;
03567 }
03568
03569
03570
03571
03572
03573
03574
03575
03576
03577
03578
03579
03580 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03581 {
03582 SQLHSTMT stmt;
03583 char sql[512];
03584 char msgnums[20];
03585 char msgnumd[20];
03586 struct odbc_obj *obj;
03587 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03588 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03589
03590 delete_file(ddir, dmsg);
03591 obj = ast_odbc_request_obj(odbc_database, 0);
03592 if (obj) {
03593 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03594 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03595 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);
03596 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03597 if (!stmt)
03598 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03599 else
03600 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03601 ast_odbc_release_obj(obj);
03602 } else
03603 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03604 return;
03605 }
03606
03607 struct insert_data {
03608 char *sql;
03609 const char *dir;
03610 const char *msgnums;
03611 void *data;
03612 SQLLEN datalen;
03613 SQLLEN indlen;
03614 const char *context;
03615 const char *macrocontext;
03616 const char *callerid;
03617 const char *origtime;
03618 const char *duration;
03619 const char *mailboxuser;
03620 const char *mailboxcontext;
03621 const char *category;
03622 const char *flag;
03623 };
03624
03625 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03626 {
03627 struct insert_data *data = vdata;
03628 int res;
03629 SQLHSTMT stmt;
03630
03631 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03632 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03633 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03634 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03635 return NULL;
03636 }
03637
03638 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03639 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03640 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03641 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03642 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03643 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03644 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03645 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03646 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03647 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03648 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03649 if (!ast_strlen_zero(data->category)) {
03650 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03651 }
03652 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03653 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03654 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03655 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03656 return NULL;
03657 }
03658
03659 return stmt;
03660 }
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671
03672
03673
03674
03675 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03676 {
03677 int res = 0;
03678 int fd = -1;
03679 void *fdm = MAP_FAILED;
03680 size_t fdlen = -1;
03681 SQLHSTMT stmt;
03682 char sql[PATH_MAX];
03683 char msgnums[20];
03684 char fn[PATH_MAX];
03685 char full_fn[PATH_MAX];
03686 char fmt[80]="";
03687 char *c;
03688 struct ast_config *cfg = NULL;
03689 struct odbc_obj *obj;
03690 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03691 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03692 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03693
03694 delete_file(dir, msgnum);
03695 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03696 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03697 return -1;
03698 }
03699
03700 do {
03701 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03702 c = strchr(fmt, '|');
03703 if (c)
03704 *c = '\0';
03705 if (!strcasecmp(fmt, "wav49"))
03706 strcpy(fmt, "WAV");
03707 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03708 if (msgnum > -1)
03709 make_file(fn, sizeof(fn), dir, msgnum);
03710 else
03711 ast_copy_string(fn, dir, sizeof(fn));
03712 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03713 cfg = ast_config_load(full_fn, config_flags);
03714 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03715 fd = open(full_fn, O_RDWR);
03716 if (fd < 0) {
03717 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03718 res = -1;
03719 break;
03720 }
03721 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03722 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03723 idata.context = "";
03724 }
03725 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03726 idata.macrocontext = "";
03727 }
03728 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03729 idata.callerid = "";
03730 }
03731 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03732 idata.origtime = "";
03733 }
03734 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03735 idata.duration = "";
03736 }
03737 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03738 idata.category = "";
03739 }
03740 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03741 idata.flag = "";
03742 }
03743 }
03744 fdlen = lseek(fd, 0, SEEK_END);
03745 lseek(fd, 0, SEEK_SET);
03746 printf("Length is %zd\n", fdlen);
03747 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03748 if (fdm == MAP_FAILED) {
03749 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03750 res = -1;
03751 break;
03752 }
03753 idata.data = fdm;
03754 idata.datalen = idata.indlen = fdlen;
03755
03756 if (!ast_strlen_zero(idata.category))
03757 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03758 else
03759 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03760
03761 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03762 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03763 } else {
03764 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03765 res = -1;
03766 }
03767 } while (0);
03768 if (obj) {
03769 ast_odbc_release_obj(obj);
03770 }
03771 if (cfg)
03772 ast_config_destroy(cfg);
03773 if (fdm != MAP_FAILED)
03774 munmap(fdm, fdlen);
03775 if (fd > -1)
03776 close(fd);
03777 return res;
03778 }
03779
03780
03781
03782
03783
03784
03785
03786
03787
03788
03789
03790
03791
03792
03793 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03794 {
03795 SQLHSTMT stmt;
03796 char sql[PATH_MAX];
03797 char msgnums[20];
03798 char msgnumd[20];
03799 struct odbc_obj *obj;
03800 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03801 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03802
03803 delete_file(ddir, dmsg);
03804 obj = ast_odbc_request_obj(odbc_database, 0);
03805 if (obj) {
03806 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03807 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03808 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03809 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03810 if (!stmt)
03811 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03812 else
03813 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03814 ast_odbc_release_obj(obj);
03815 } else
03816 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03817 return;
03818 }
03819
03820
03821
03822
03823
03824
03825
03826
03827
03828
03829
03830
03831 static int remove_file(char *dir, int msgnum)
03832 {
03833 char fn[PATH_MAX];
03834 char full_fn[PATH_MAX];
03835 char msgnums[80];
03836
03837 if (msgnum > -1) {
03838 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03839 make_file(fn, sizeof(fn), dir, msgnum);
03840 } else
03841 ast_copy_string(fn, dir, sizeof(fn));
03842 ast_filedelete(fn, NULL);
03843 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03844 unlink(full_fn);
03845 return 0;
03846 }
03847 #else
03848 #ifndef IMAP_STORAGE
03849
03850
03851
03852
03853
03854
03855
03856
03857
03858 static int count_messages(struct ast_vm_user *vmu, char *dir)
03859 {
03860
03861 int vmcount = 0;
03862 DIR *vmdir = NULL;
03863 struct dirent *vment = NULL;
03864
03865 if (vm_lock_path(dir))
03866 return ERROR_LOCK_PATH;
03867
03868 if ((vmdir = opendir(dir))) {
03869 while ((vment = readdir(vmdir))) {
03870 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03871 vmcount++;
03872 }
03873 }
03874 closedir(vmdir);
03875 }
03876 ast_unlock_path(dir);
03877
03878 return vmcount;
03879 }
03880
03881
03882
03883
03884
03885
03886
03887
03888 static void rename_file(char *sfn, char *dfn)
03889 {
03890 char stxt[PATH_MAX];
03891 char dtxt[PATH_MAX];
03892 ast_filerename(sfn, dfn, NULL);
03893 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03894 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03895 if (ast_check_realtime("voicemail_data")) {
03896 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03897 }
03898 rename(stxt, dtxt);
03899 }
03900
03901
03902
03903
03904
03905
03906
03907
03908
03909
03910
03911
03912 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03913 {
03914 int x;
03915 unsigned char map[MAXMSGLIMIT] = "";
03916 DIR *msgdir;
03917 struct dirent *msgdirent;
03918 int msgdirint;
03919
03920
03921
03922
03923
03924 if (!(msgdir = opendir(dir))) {
03925 return -1;
03926 }
03927
03928 while ((msgdirent = readdir(msgdir))) {
03929 if (sscanf(msgdirent->d_name, "msg%30d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03930 map[msgdirint] = 1;
03931 }
03932 closedir(msgdir);
03933
03934 for (x = 0; x < vmu->maxmsg; x++) {
03935 if (map[x] == 0)
03936 break;
03937 }
03938
03939 return x - 1;
03940 }
03941
03942 #endif
03943 #endif
03944 #ifndef IMAP_STORAGE
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954
03955 static int copy(char *infile, char *outfile)
03956 {
03957 int ifd;
03958 int ofd;
03959 int res;
03960 int len;
03961 char buf[4096];
03962
03963 #ifdef HARDLINK_WHEN_POSSIBLE
03964
03965 if (link(infile, outfile)) {
03966 #endif
03967 if ((ifd = open(infile, O_RDONLY)) < 0) {
03968 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03969 return -1;
03970 }
03971 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03972 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03973 close(ifd);
03974 return -1;
03975 }
03976 do {
03977 len = read(ifd, buf, sizeof(buf));
03978 if (len < 0) {
03979 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03980 close(ifd);
03981 close(ofd);
03982 unlink(outfile);
03983 }
03984 if (len) {
03985 res = write(ofd, buf, len);
03986 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03987 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03988 close(ifd);
03989 close(ofd);
03990 unlink(outfile);
03991 }
03992 }
03993 } while (len);
03994 close(ifd);
03995 close(ofd);
03996 return 0;
03997 #ifdef HARDLINK_WHEN_POSSIBLE
03998 } else {
03999
04000 return 0;
04001 }
04002 #endif
04003 }
04004
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014 static void copy_plain_file(char *frompath, char *topath)
04015 {
04016 char frompath2[PATH_MAX], topath2[PATH_MAX];
04017 struct ast_variable *tmp,*var = NULL;
04018 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04019 ast_filecopy(frompath, topath, NULL);
04020 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04021 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04022 if (ast_check_realtime("voicemail_data")) {
04023 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04024
04025 for (tmp = var; tmp; tmp = tmp->next) {
04026 if (!strcasecmp(tmp->name, "origmailbox")) {
04027 origmailbox = tmp->value;
04028 } else if (!strcasecmp(tmp->name, "context")) {
04029 context = tmp->value;
04030 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04031 macrocontext = tmp->value;
04032 } else if (!strcasecmp(tmp->name, "exten")) {
04033 exten = tmp->value;
04034 } else if (!strcasecmp(tmp->name, "priority")) {
04035 priority = tmp->value;
04036 } else if (!strcasecmp(tmp->name, "callerchan")) {
04037 callerchan = tmp->value;
04038 } else if (!strcasecmp(tmp->name, "callerid")) {
04039 callerid = tmp->value;
04040 } else if (!strcasecmp(tmp->name, "origdate")) {
04041 origdate = tmp->value;
04042 } else if (!strcasecmp(tmp->name, "origtime")) {
04043 origtime = tmp->value;
04044 } else if (!strcasecmp(tmp->name, "category")) {
04045 category = tmp->value;
04046 } else if (!strcasecmp(tmp->name, "duration")) {
04047 duration = tmp->value;
04048 }
04049 }
04050 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);
04051 }
04052 copy(frompath2, topath2);
04053 ast_variables_destroy(var);
04054 }
04055 #endif
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065 static int vm_delete(char *file)
04066 {
04067 char *txt;
04068 int txtsize = 0;
04069
04070 txtsize = (strlen(file) + 5)*sizeof(char);
04071 txt = alloca(txtsize);
04072
04073
04074
04075 if (ast_check_realtime("voicemail_data")) {
04076 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04077 }
04078 snprintf(txt, txtsize, "%s.txt", file);
04079 unlink(txt);
04080 return ast_filedelete(file, NULL);
04081 }
04082
04083
04084
04085
04086 static int inbuf(struct baseio *bio, FILE *fi)
04087 {
04088 int l;
04089
04090 if (bio->ateof)
04091 return 0;
04092
04093 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04094 if (ferror(fi))
04095 return -1;
04096
04097 bio->ateof = 1;
04098 return 0;
04099 }
04100
04101 bio->iolen = l;
04102 bio->iocp = 0;
04103
04104 return 1;
04105 }
04106
04107
04108
04109
04110 static int inchar(struct baseio *bio, FILE *fi)
04111 {
04112 if (bio->iocp>=bio->iolen) {
04113 if (!inbuf(bio, fi))
04114 return EOF;
04115 }
04116
04117 return bio->iobuf[bio->iocp++];
04118 }
04119
04120
04121
04122
04123 static int ochar(struct baseio *bio, int c, FILE *so)
04124 {
04125 if (bio->linelength >= BASELINELEN) {
04126 if (fputs(ENDL, so) == EOF) {
04127 return -1;
04128 }
04129
04130 bio->linelength = 0;
04131 }
04132
04133 if (putc(((unsigned char) c), so) == EOF) {
04134 return -1;
04135 }
04136
04137 bio->linelength++;
04138
04139 return 1;
04140 }
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151 static int base_encode(char *filename, FILE *so)
04152 {
04153 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04154 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04155 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04156 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04157 int i, hiteof = 0;
04158 FILE *fi;
04159 struct baseio bio;
04160
04161 memset(&bio, 0, sizeof(bio));
04162 bio.iocp = BASEMAXINLINE;
04163
04164 if (!(fi = fopen(filename, "rb"))) {
04165 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04166 return -1;
04167 }
04168
04169 while (!hiteof){
04170 unsigned char igroup[3], ogroup[4];
04171 int c, n;
04172
04173 memset(igroup, 0, sizeof(igroup));
04174
04175 for (n = 0; n < 3; n++) {
04176 if ((c = inchar(&bio, fi)) == EOF) {
04177 hiteof = 1;
04178 break;
04179 }
04180
04181 igroup[n] = (unsigned char) c;
04182 }
04183
04184 if (n > 0) {
04185 ogroup[0]= dtable[igroup[0] >> 2];
04186 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04187 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04188 ogroup[3]= dtable[igroup[2] & 0x3F];
04189
04190 if (n < 3) {
04191 ogroup[3] = '=';
04192
04193 if (n < 2)
04194 ogroup[2] = '=';
04195 }
04196
04197 for (i = 0; i < 4; i++)
04198 ochar(&bio, ogroup[i], so);
04199 }
04200 }
04201
04202 fclose(fi);
04203
04204 if (fputs(ENDL, so) == EOF) {
04205 return 0;
04206 }
04207
04208 return 1;
04209 }
04210
04211 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)
04212 {
04213 char callerid[256];
04214 char num[12];
04215 char fromdir[256], fromfile[256];
04216 struct ast_config *msg_cfg;
04217 const char *origcallerid, *origtime;
04218 char origcidname[80], origcidnum[80], origdate[80];
04219 int inttime;
04220 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04221
04222
04223 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04224 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04225 snprintf(num, sizeof(num), "%d", msgnum);
04226 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04227 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04228 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04229 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04230 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04231 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04232 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04233 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04234 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04235 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04236
04237
04238 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04239 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04240 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04241 strcat(fromfile, ".txt");
04242 }
04243 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04244 if (option_debug > 0) {
04245 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04246 }
04247 return;
04248 }
04249
04250 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04251 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04252 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04253 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04254 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04255 }
04256
04257 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04258 struct timeval tv = { inttime, };
04259 struct ast_tm tm;
04260 ast_localtime(&tv, &tm, NULL);
04261 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04262 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04263 }
04264 ast_config_destroy(msg_cfg);
04265 }
04266
04267
04268
04269
04270
04271
04272
04273
04274
04275 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04276 {
04277 const char *ptr;
04278
04279
04280 ast_str_set(buf, maxlen, "\"");
04281 for (ptr = from; *ptr; ptr++) {
04282 if (*ptr == '"' || *ptr == '\\') {
04283 ast_str_append(buf, maxlen, "\\%c", *ptr);
04284 } else {
04285 ast_str_append(buf, maxlen, "%c", *ptr);
04286 }
04287 }
04288 ast_str_append(buf, maxlen, "\"");
04289
04290 return ast_str_buffer(*buf);
04291 }
04292
04293
04294
04295
04296
04297 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04298 {
04299 const struct vm_zone *z = NULL;
04300 struct timeval t = ast_tvnow();
04301
04302
04303 if (!ast_strlen_zero(vmu->zonetag)) {
04304
04305 AST_LIST_LOCK(&zones);
04306 AST_LIST_TRAVERSE(&zones, z, list) {
04307 if (!strcmp(z->name, vmu->zonetag))
04308 break;
04309 }
04310 AST_LIST_UNLOCK(&zones);
04311 }
04312 ast_localtime(&t, tm, z ? z->timezone : NULL);
04313 return tm;
04314 }
04315
04316
04317
04318
04319
04320 static int check_mime(const char *str)
04321 {
04322 for (; *str; str++) {
04323 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04324 return 1;
04325 }
04326 }
04327 return 0;
04328 }
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345
04346
04347 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04348 {
04349 struct ast_str *tmp = ast_str_alloca(80);
04350 int first_section = 1;
04351
04352 ast_str_reset(*end);
04353 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04354 for (; *start; start++) {
04355 int need_encoding = 0;
04356 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04357 need_encoding = 1;
04358 }
04359 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04360 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04361 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04362 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04363
04364 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04365 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04366 first_section = 0;
04367 }
04368 if (need_encoding && *start == ' ') {
04369 ast_str_append(&tmp, -1, "_");
04370 } else if (need_encoding) {
04371 ast_str_append(&tmp, -1, "=%hhX", *start);
04372 } else {
04373 ast_str_append(&tmp, -1, "%c", *start);
04374 }
04375 }
04376 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04377 return ast_str_buffer(*end);
04378 }
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395
04396
04397
04398
04399
04400
04401
04402
04403 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)
04404 {
04405 char date[256];
04406 char host[MAXHOSTNAMELEN] = "";
04407 char who[256];
04408 char bound[256];
04409 char dur[256];
04410 struct ast_tm tm;
04411 char enc_cidnum[256] = "", enc_cidname[256] = "";
04412 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04413 char *greeting_attachment;
04414 char filename[256];
04415
04416 if (!str1 || !str2) {
04417 ast_free(str1);
04418 ast_free(str2);
04419 return;
04420 }
04421
04422 if (cidnum) {
04423 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04424 }
04425 if (cidname) {
04426 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04427 }
04428 gethostname(host, sizeof(host) - 1);
04429
04430 if (strchr(srcemail, '@')) {
04431 ast_copy_string(who, srcemail, sizeof(who));
04432 } else {
04433 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04434 }
04435
04436 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04437 if (greeting_attachment) {
04438 *greeting_attachment++ = '\0';
04439 }
04440
04441 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04442 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04443 fprintf(p, "Date: %s" ENDL, date);
04444
04445
04446 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04447
04448 if (!ast_strlen_zero(fromstring)) {
04449 struct ast_channel *ast;
04450 if ((ast = ast_dummy_channel_alloc())) {
04451 char *ptr;
04452 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04453 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04454
04455 if (check_mime(ast_str_buffer(str1))) {
04456 int first_line = 1;
04457 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04458 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04459 *ptr = '\0';
04460 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04461 first_line = 0;
04462
04463 ast_str_set(&str2, 0, "%s", ptr + 1);
04464 }
04465 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04466 } else {
04467 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04468 }
04469 ast = ast_channel_release(ast);
04470 } else {
04471 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04472 }
04473 } else {
04474 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04475 }
04476
04477 if (check_mime(vmu->fullname)) {
04478 int first_line = 1;
04479 char *ptr;
04480 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04481 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04482 *ptr = '\0';
04483 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04484 first_line = 0;
04485
04486 ast_str_set(&str2, 0, "%s", ptr + 1);
04487 }
04488 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04489 } else {
04490 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04491 }
04492
04493 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04494 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04495 struct ast_channel *ast;
04496 if ((ast = ast_dummy_channel_alloc())) {
04497 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04498 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04499 if (check_mime(ast_str_buffer(str1))) {
04500 int first_line = 1;
04501 char *ptr;
04502 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04503 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04504 *ptr = '\0';
04505 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04506 first_line = 0;
04507
04508 ast_str_set(&str2, 0, "%s", ptr + 1);
04509 }
04510 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04511 } else {
04512 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04513 }
04514 ast = ast_channel_release(ast);
04515 } else {
04516 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04517 }
04518 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04519 if (ast_strlen_zero(flag)) {
04520 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04521 } else {
04522 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04523 }
04524 } else {
04525 if (ast_strlen_zero(flag)) {
04526 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04527 } else {
04528 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04529 }
04530 }
04531
04532 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04533 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04534 if (imap) {
04535
04536 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04537
04538 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04539 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04540 #ifdef IMAP_STORAGE
04541 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04542 #else
04543 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04544 #endif
04545
04546 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04547 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04548 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04549 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04550 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04551 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04552 if (!ast_strlen_zero(category)) {
04553 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04554 } else {
04555 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04556 }
04557 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04558 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04559 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04560 }
04561 if (!ast_strlen_zero(cidnum)) {
04562 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04563 }
04564 if (!ast_strlen_zero(cidname)) {
04565 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04566 }
04567 fprintf(p, "MIME-Version: 1.0" ENDL);
04568 if (attach_user_voicemail) {
04569
04570 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04571 (int) getpid(), (unsigned int) ast_random());
04572
04573 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04574 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04575 fprintf(p, "--%s" ENDL, bound);
04576 }
04577 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04578 if (emailbody || vmu->emailbody) {
04579 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04580 struct ast_channel *ast;
04581 if ((ast = ast_dummy_channel_alloc())) {
04582 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04583 ast_str_substitute_variables(&str1, 0, ast, e_body);
04584 #ifdef IMAP_STORAGE
04585 {
04586
04587 char *line = ast_str_buffer(str1), *next;
04588 do {
04589
04590 if ((next = strchr(line, '\n'))) {
04591 *next++ = '\0';
04592 }
04593 fprintf(p, "%s" ENDL, line);
04594 line = next;
04595 } while (!ast_strlen_zero(line));
04596 }
04597 #else
04598 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04599 #endif
04600 ast = ast_channel_release(ast);
04601 } else {
04602 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04603 }
04604 } else if (msgnum > -1) {
04605 if (strcmp(vmu->mailbox, mailbox)) {
04606
04607 struct ast_config *msg_cfg;
04608 const char *v;
04609 int inttime;
04610 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04611 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04612
04613 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04614 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04615 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04616 strcat(fromfile, ".txt");
04617 }
04618 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04619 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04620 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04621 }
04622
04623
04624
04625 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04626 struct timeval tv = { inttime, };
04627 struct ast_tm tm;
04628 ast_localtime(&tv, &tm, NULL);
04629 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04630 }
04631 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04632 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04633 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04634 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04635 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04636 date, origcallerid, origdate);
04637 ast_config_destroy(msg_cfg);
04638 } else {
04639 goto plain_message;
04640 }
04641 } else {
04642 plain_message:
04643 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04644 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04645 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04646 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04647 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04648 }
04649 } else {
04650 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04651 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04652 }
04653
04654 if (imap || attach_user_voicemail) {
04655 if (!ast_strlen_zero(attach2)) {
04656 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04657 ast_debug(5, "creating second attachment filename %s\n", filename);
04658 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04659 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04660 ast_debug(5, "creating attachment filename %s\n", filename);
04661 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04662 } else {
04663 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04664 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04665 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04666 }
04667 }
04668 ast_free(str1);
04669 ast_free(str2);
04670 }
04671
04672 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)
04673 {
04674 char tmpdir[256], newtmp[256];
04675 char fname[256];
04676 char tmpcmd[256];
04677 int tmpfd = -1;
04678
04679
04680 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04681
04682 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04683 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04684 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04685 tmpfd = mkstemp(newtmp);
04686 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04687 ast_debug(3, "newtmp: %s\n", newtmp);
04688 if (tmpfd > -1) {
04689 int soxstatus;
04690 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04691 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04692 attach = newtmp;
04693 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04694 } else {
04695 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04696 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04697 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04698 }
04699 }
04700 }
04701 fprintf(p, "--%s" ENDL, bound);
04702 if (msgnum > -1)
04703 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04704 else
04705 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04706 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04707 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04708 if (msgnum > -1)
04709 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04710 else
04711 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04712 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04713 base_encode(fname, p);
04714 if (last)
04715 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04716 if (tmpfd > -1) {
04717 unlink(fname);
04718 close(tmpfd);
04719 unlink(newtmp);
04720 }
04721 return 0;
04722 }
04723
04724 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)
04725 {
04726 FILE *p = NULL;
04727 char tmp[80] = "/tmp/astmail-XXXXXX";
04728 char tmp2[256];
04729 char *stringp;
04730
04731 if (vmu && ast_strlen_zero(vmu->email)) {
04732 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04733 return(0);
04734 }
04735
04736
04737 format = ast_strdupa(format);
04738 stringp = format;
04739 strsep(&stringp, "|");
04740
04741 if (!strcmp(format, "wav49"))
04742 format = "WAV";
04743 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));
04744
04745
04746 if ((p = vm_mkftemp(tmp)) == NULL) {
04747 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04748 return -1;
04749 } else {
04750 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04751 fclose(p);
04752 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04753 ast_safe_system(tmp2);
04754 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04755 }
04756 return 0;
04757 }
04758
04759 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)
04760 {
04761 char enc_cidnum[256], enc_cidname[256];
04762 char date[256];
04763 char host[MAXHOSTNAMELEN] = "";
04764 char who[256];
04765 char dur[PATH_MAX];
04766 char tmp[80] = "/tmp/astmail-XXXXXX";
04767 char tmp2[PATH_MAX];
04768 struct ast_tm tm;
04769 FILE *p;
04770 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04771
04772 if (!str1 || !str2) {
04773 ast_free(str1);
04774 ast_free(str2);
04775 return -1;
04776 }
04777
04778 if (cidnum) {
04779 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04780 }
04781 if (cidname) {
04782 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04783 }
04784
04785 if ((p = vm_mkftemp(tmp)) == NULL) {
04786 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04787 ast_free(str1);
04788 ast_free(str2);
04789 return -1;
04790 }
04791 gethostname(host, sizeof(host)-1);
04792 if (strchr(srcemail, '@')) {
04793 ast_copy_string(who, srcemail, sizeof(who));
04794 } else {
04795 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04796 }
04797 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04798 ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04799 fprintf(p, "Date: %s\n", date);
04800
04801
04802 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04803
04804 if (!ast_strlen_zero(pagerfromstring)) {
04805 struct ast_channel *ast;
04806 if ((ast = ast_dummy_channel_alloc())) {
04807 char *ptr;
04808 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04809 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04810
04811 if (check_mime(ast_str_buffer(str1))) {
04812 int first_line = 1;
04813 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04814 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04815 *ptr = '\0';
04816 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04817 first_line = 0;
04818
04819 ast_str_set(&str2, 0, "%s", ptr + 1);
04820 }
04821 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04822 } else {
04823 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04824 }
04825 ast = ast_channel_release(ast);
04826 } else {
04827 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04828 }
04829 } else {
04830 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04831 }
04832
04833 if (check_mime(vmu->fullname)) {
04834 int first_line = 1;
04835 char *ptr;
04836 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04837 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04838 *ptr = '\0';
04839 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04840 first_line = 0;
04841
04842 ast_str_set(&str2, 0, "%s", ptr + 1);
04843 }
04844 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04845 } else {
04846 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04847 }
04848
04849 if (!ast_strlen_zero(pagersubject)) {
04850 struct ast_channel *ast;
04851 if ((ast = ast_dummy_channel_alloc())) {
04852 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04853 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04854 if (check_mime(ast_str_buffer(str1))) {
04855 int first_line = 1;
04856 char *ptr;
04857 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04858 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04859 *ptr = '\0';
04860 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04861 first_line = 0;
04862
04863 ast_str_set(&str2, 0, "%s", ptr + 1);
04864 }
04865 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04866 } else {
04867 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04868 }
04869 ast = ast_channel_release(ast);
04870 } else {
04871 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04872 }
04873 } else {
04874 if (ast_strlen_zero(flag)) {
04875 fprintf(p, "Subject: New VM\n\n");
04876 } else {
04877 fprintf(p, "Subject: New %s VM\n\n", flag);
04878 }
04879 }
04880
04881 if (pagerbody) {
04882 struct ast_channel *ast;
04883 if ((ast = ast_dummy_channel_alloc())) {
04884 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04885 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
04886 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04887 ast = ast_channel_release(ast);
04888 } else {
04889 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04890 }
04891 } else {
04892 fprintf(p, "New %s long %s msg in box %s\n"
04893 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04894 }
04895
04896 fclose(p);
04897 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04898 ast_safe_system(tmp2);
04899 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04900 ast_free(str1);
04901 ast_free(str2);
04902 return 0;
04903 }
04904
04905
04906
04907
04908
04909
04910
04911
04912
04913
04914 static int get_date(char *s, int len)
04915 {
04916 struct ast_tm tm;
04917 struct timeval t = ast_tvnow();
04918
04919 ast_localtime(&t, &tm, "UTC");
04920
04921 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04922 }
04923
04924 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
04925 {
04926 int res;
04927 char fn[PATH_MAX];
04928 char dest[PATH_MAX];
04929
04930 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04931
04932 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04933 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04934 return -1;
04935 }
04936
04937 RETRIEVE(fn, -1, ext, context);
04938 if (ast_fileexists(fn, NULL, NULL) > 0) {
04939 res = ast_stream_and_wait(chan, fn, ecodes);
04940 if (res) {
04941 DISPOSE(fn, -1);
04942 return res;
04943 }
04944 } else {
04945
04946 DISPOSE(fn, -1);
04947 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04948 if (res)
04949 return res;
04950 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04951 if (res)
04952 return res;
04953 }
04954 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04955 return res;
04956 }
04957
04958 static void free_zone(struct vm_zone *z)
04959 {
04960 ast_free(z);
04961 }
04962
04963 #ifdef ODBC_STORAGE
04964 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04965 {
04966 int x = -1;
04967 int res;
04968 SQLHSTMT stmt = NULL;
04969 char sql[PATH_MAX];
04970 char rowdata[20];
04971 char tmp[PATH_MAX] = "";
04972 struct odbc_obj *obj = NULL;
04973 char *context;
04974 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04975
04976 if (newmsgs)
04977 *newmsgs = 0;
04978 if (oldmsgs)
04979 *oldmsgs = 0;
04980 if (urgentmsgs)
04981 *urgentmsgs = 0;
04982
04983
04984 if (ast_strlen_zero(mailbox))
04985 return 0;
04986
04987 ast_copy_string(tmp, mailbox, sizeof(tmp));
04988
04989 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
04990 int u, n, o;
04991 char *next, *remaining = tmp;
04992 while ((next = strsep(&remaining, " ,"))) {
04993 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
04994 return -1;
04995 }
04996 if (urgentmsgs) {
04997 *urgentmsgs += u;
04998 }
04999 if (newmsgs) {
05000 *newmsgs += n;
05001 }
05002 if (oldmsgs) {
05003 *oldmsgs += o;
05004 }
05005 }
05006 return 0;
05007 }
05008
05009 context = strchr(tmp, '@');
05010 if (context) {
05011 *context = '\0';
05012 context++;
05013 } else
05014 context = "default";
05015
05016 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05017 do {
05018 if (newmsgs) {
05019 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05020 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05021 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05022 break;
05023 }
05024 res = SQLFetch(stmt);
05025 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05026 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05027 break;
05028 }
05029 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05030 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05031 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05032 break;
05033 }
05034 *newmsgs = atoi(rowdata);
05035 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05036 }
05037
05038 if (oldmsgs) {
05039 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05040 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05041 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05042 break;
05043 }
05044 res = SQLFetch(stmt);
05045 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05046 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05047 break;
05048 }
05049 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05050 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05051 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05052 break;
05053 }
05054 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05055 *oldmsgs = atoi(rowdata);
05056 }
05057
05058 if (urgentmsgs) {
05059 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05060 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05061 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05062 break;
05063 }
05064 res = SQLFetch(stmt);
05065 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05066 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05067 break;
05068 }
05069 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05070 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05071 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05072 break;
05073 }
05074 *urgentmsgs = atoi(rowdata);
05075 }
05076
05077 x = 0;
05078 } while (0);
05079 } else {
05080 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05081 }
05082
05083 if (stmt) {
05084 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05085 }
05086 if (obj) {
05087 ast_odbc_release_obj(obj);
05088 }
05089
05090 return x;
05091 }
05092
05093
05094
05095
05096
05097
05098
05099
05100
05101
05102 static int messagecount(const char *context, const char *mailbox, const char *folder)
05103 {
05104 struct odbc_obj *obj = NULL;
05105 int nummsgs = 0;
05106 int res;
05107 SQLHSTMT stmt = NULL;
05108 char sql[PATH_MAX];
05109 char rowdata[20];
05110 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05111 if (!folder)
05112 folder = "INBOX";
05113
05114 if (ast_strlen_zero(mailbox))
05115 return 0;
05116
05117 obj = ast_odbc_request_obj(odbc_database, 0);
05118 if (obj) {
05119 if (!strcmp(folder, "INBOX")) {
05120 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);
05121 } else {
05122 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05123 }
05124 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05125 if (!stmt) {
05126 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05127 goto yuck;
05128 }
05129 res = SQLFetch(stmt);
05130 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05131 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05132 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05133 goto yuck;
05134 }
05135 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05136 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05137 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05138 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05139 goto yuck;
05140 }
05141 nummsgs = atoi(rowdata);
05142 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05143 } else
05144 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05145
05146 yuck:
05147 if (obj)
05148 ast_odbc_release_obj(obj);
05149 return nummsgs;
05150 }
05151
05152
05153
05154
05155
05156
05157
05158
05159
05160 static int has_voicemail(const char *mailbox, const char *folder)
05161 {
05162 char tmp[256], *tmp2 = tmp, *box, *context;
05163 ast_copy_string(tmp, mailbox, sizeof(tmp));
05164 while ((context = box = strsep(&tmp2, ",&"))) {
05165 strsep(&context, "@");
05166 if (ast_strlen_zero(context))
05167 context = "default";
05168 if (messagecount(context, box, folder))
05169 return 1;
05170 }
05171 return 0;
05172 }
05173 #endif
05174 #ifndef IMAP_STORAGE
05175
05176
05177
05178
05179
05180
05181
05182
05183
05184
05185
05186
05187
05188
05189
05190
05191 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)
05192 {
05193 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05194 const char *frombox = mbox(vmu, imbox);
05195 int recipmsgnum;
05196 int res = 0;
05197
05198 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05199
05200 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05201 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
05202 } else {
05203 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05204 }
05205
05206 if (!dir)
05207 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05208 else
05209 ast_copy_string(fromdir, dir, sizeof(fromdir));
05210
05211 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05212 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
05213
05214 if (vm_lock_path(todir))
05215 return ERROR_LOCK_PATH;
05216
05217 recipmsgnum = last_message_index(recip, todir) + 1;
05218 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05219 make_file(topath, sizeof(topath), todir, recipmsgnum);
05220 #ifndef ODBC_STORAGE
05221 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05222 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05223 } else {
05224 #endif
05225
05226
05227
05228 copy_plain_file(frompath, topath);
05229 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05230 vm_delete(topath);
05231 #ifndef ODBC_STORAGE
05232 }
05233 #endif
05234 } else {
05235 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05236 res = -1;
05237 }
05238 ast_unlock_path(todir);
05239 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05240 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05241 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05242 flag);
05243
05244 return res;
05245 }
05246 #endif
05247 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05248
05249 static int messagecount(const char *context, const char *mailbox, const char *folder)
05250 {
05251 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05252 }
05253
05254 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05255 {
05256 DIR *dir;
05257 struct dirent *de;
05258 char fn[256];
05259 int ret = 0;
05260
05261
05262 if (ast_strlen_zero(mailbox))
05263 return 0;
05264
05265 if (ast_strlen_zero(folder))
05266 folder = "INBOX";
05267 if (ast_strlen_zero(context))
05268 context = "default";
05269
05270 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05271
05272 if (!(dir = opendir(fn)))
05273 return 0;
05274
05275 while ((de = readdir(dir))) {
05276 if (!strncasecmp(de->d_name, "msg", 3)) {
05277 if (shortcircuit) {
05278 ret = 1;
05279 break;
05280 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05281 ret++;
05282 }
05283 }
05284 }
05285
05286 closedir(dir);
05287
05288 return ret;
05289 }
05290
05291
05292
05293
05294
05295
05296
05297
05298
05299
05300 static int has_voicemail(const char *mailbox, const char *folder)
05301 {
05302 char tmp[256], *tmp2 = tmp, *box, *context;
05303 ast_copy_string(tmp, mailbox, sizeof(tmp));
05304 if (ast_strlen_zero(folder)) {
05305 folder = "INBOX";
05306 }
05307 while ((box = strsep(&tmp2, ",&"))) {
05308 if ((context = strchr(box, '@')))
05309 *context++ = '\0';
05310 else
05311 context = "default";
05312 if (__has_voicemail(context, box, folder, 1))
05313 return 1;
05314
05315 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05316 return 1;
05317 }
05318 }
05319 return 0;
05320 }
05321
05322
05323 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05324 {
05325 char tmp[256];
05326 char *context;
05327
05328
05329 if (ast_strlen_zero(mailbox))
05330 return 0;
05331
05332 if (newmsgs)
05333 *newmsgs = 0;
05334 if (oldmsgs)
05335 *oldmsgs = 0;
05336 if (urgentmsgs)
05337 *urgentmsgs = 0;
05338
05339 if (strchr(mailbox, ',')) {
05340 int tmpnew, tmpold, tmpurgent;
05341 char *mb, *cur;
05342
05343 ast_copy_string(tmp, mailbox, sizeof(tmp));
05344 mb = tmp;
05345 while ((cur = strsep(&mb, ", "))) {
05346 if (!ast_strlen_zero(cur)) {
05347 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05348 return -1;
05349 else {
05350 if (newmsgs)
05351 *newmsgs += tmpnew;
05352 if (oldmsgs)
05353 *oldmsgs += tmpold;
05354 if (urgentmsgs)
05355 *urgentmsgs += tmpurgent;
05356 }
05357 }
05358 }
05359 return 0;
05360 }
05361
05362 ast_copy_string(tmp, mailbox, sizeof(tmp));
05363
05364 if ((context = strchr(tmp, '@')))
05365 *context++ = '\0';
05366 else
05367 context = "default";
05368
05369 if (newmsgs)
05370 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05371 if (oldmsgs)
05372 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05373 if (urgentmsgs)
05374 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05375
05376 return 0;
05377 }
05378
05379 #endif
05380
05381
05382 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05383 {
05384 int urgentmsgs = 0;
05385 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05386 if (newmsgs) {
05387 *newmsgs += urgentmsgs;
05388 }
05389 return res;
05390 }
05391
05392 static void run_externnotify(char *context, char *extension, const char *flag)
05393 {
05394 char arguments[255];
05395 char ext_context[256] = "";
05396 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05397 struct ast_smdi_mwi_message *mwi_msg;
05398
05399 if (!ast_strlen_zero(context))
05400 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05401 else
05402 ast_copy_string(ext_context, extension, sizeof(ext_context));
05403
05404 if (smdi_iface) {
05405 if (ast_app_has_voicemail(ext_context, NULL))
05406 ast_smdi_mwi_set(smdi_iface, extension);
05407 else
05408 ast_smdi_mwi_unset(smdi_iface, extension);
05409
05410 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05411 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05412 if (!strncmp(mwi_msg->cause, "INV", 3))
05413 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05414 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05415 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05416 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05417 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05418 } else {
05419 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05420 }
05421 }
05422
05423 if (!ast_strlen_zero(externnotify)) {
05424 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05425 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05426 } else {
05427 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05428 ast_debug(1, "Executing %s\n", arguments);
05429 ast_safe_system(arguments);
05430 }
05431 }
05432 }
05433
05434
05435
05436
05437
05438
05439 struct leave_vm_options {
05440 unsigned int flags;
05441 signed char record_gain;
05442 char *exitcontext;
05443 };
05444
05445
05446
05447
05448
05449
05450
05451
05452
05453
05454
05455 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05456 {
05457 #ifdef IMAP_STORAGE
05458 int newmsgs, oldmsgs;
05459 #else
05460 char urgdir[PATH_MAX];
05461 #endif
05462 char txtfile[PATH_MAX];
05463 char tmptxtfile[PATH_MAX];
05464 struct vm_state *vms = NULL;
05465 char callerid[256];
05466 FILE *txt;
05467 char date[256];
05468 int txtdes;
05469 int res = 0;
05470 int msgnum;
05471 int duration = 0;
05472 int ausemacro = 0;
05473 int ousemacro = 0;
05474 int ouseexten = 0;
05475 char tmpdur[16];
05476 char priority[16];
05477 char origtime[16];
05478 char dir[PATH_MAX];
05479 char tmpdir[PATH_MAX];
05480 char fn[PATH_MAX];
05481 char prefile[PATH_MAX] = "";
05482 char tempfile[PATH_MAX] = "";
05483 char ext_context[256] = "";
05484 char fmt[80];
05485 char *context;
05486 char ecodes[17] = "#";
05487 struct ast_str *tmp = ast_str_create(16);
05488 char *tmpptr;
05489 struct ast_vm_user *vmu;
05490 struct ast_vm_user svm;
05491 const char *category = NULL;
05492 const char *code;
05493 const char *alldtmf = "0123456789ABCD*#";
05494 char flag[80];
05495
05496 if (!tmp) {
05497 return -1;
05498 }
05499
05500 ast_str_set(&tmp, 0, "%s", ext);
05501 ext = ast_str_buffer(tmp);
05502 if ((context = strchr(ext, '@'))) {
05503 *context++ = '\0';
05504 tmpptr = strchr(context, '&');
05505 } else {
05506 tmpptr = strchr(ext, '&');
05507 }
05508
05509 if (tmpptr)
05510 *tmpptr++ = '\0';
05511
05512 ast_channel_lock(chan);
05513 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05514 category = ast_strdupa(category);
05515 }
05516 ast_channel_unlock(chan);
05517
05518 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05519 ast_copy_string(flag, "Urgent", sizeof(flag));
05520 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05521 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05522 } else {
05523 flag[0] = '\0';
05524 }
05525
05526 ast_debug(3, "Before find_user\n");
05527 if (!(vmu = find_user(&svm, context, ext))) {
05528 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05529 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05530 ast_free(tmp);
05531 return res;
05532 }
05533
05534 if (strcmp(vmu->context, "default"))
05535 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05536 else
05537 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05538
05539
05540
05541
05542
05543
05544 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05545 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05546 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05547 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05548 }
05549
05550
05551
05552
05553 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05554 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05555 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05556 ast_free(tmp);
05557 return -1;
05558 }
05559 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05560 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05561 ast_copy_string(prefile, tempfile, sizeof(prefile));
05562
05563 DISPOSE(tempfile, -1);
05564
05565 #ifndef IMAP_STORAGE
05566 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05567 #else
05568 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05569 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05570 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05571 }
05572 #endif
05573
05574
05575 if (ast_test_flag(vmu, VM_OPERATOR)) {
05576 if (!ast_strlen_zero(vmu->exit)) {
05577 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05578 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05579 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05580 ouseexten = 1;
05581 }
05582 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05583 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05584 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05585 ouseexten = 1;
05586 } else if (!ast_strlen_zero(chan->macrocontext)
05587 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05588 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05589 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05590 ousemacro = 1;
05591 }
05592 }
05593
05594 if (!ast_strlen_zero(vmu->exit)) {
05595 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05596 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05597 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05598 }
05599 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05600 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05601 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05602 } else if (!ast_strlen_zero(chan->macrocontext)
05603 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05604 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05605 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05606 ausemacro = 1;
05607 }
05608
05609 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05610 for (code = alldtmf; *code; code++) {
05611 char e[2] = "";
05612 e[0] = *code;
05613 if (strchr(ecodes, e[0]) == NULL
05614 && ast_canmatch_extension(chan, chan->context, e, 1,
05615 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05616 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05617 }
05618 }
05619 }
05620
05621
05622 if (!ast_strlen_zero(prefile)) {
05623 #ifdef ODBC_STORAGE
05624 int success =
05625 #endif
05626 RETRIEVE(prefile, -1, ext, context);
05627 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05628 if (ast_streamfile(chan, prefile, chan->language) > -1)
05629 res = ast_waitstream(chan, ecodes);
05630 #ifdef ODBC_STORAGE
05631 if (success == -1) {
05632
05633 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05634 store_file(prefile, vmu->mailbox, vmu->context, -1);
05635 }
05636 #endif
05637 } else {
05638 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05639 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05640 }
05641 DISPOSE(prefile, -1);
05642 if (res < 0) {
05643 ast_debug(1, "Hang up during prefile playback\n");
05644 free_user(vmu);
05645 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05646 ast_free(tmp);
05647 return -1;
05648 }
05649 }
05650 if (res == '#') {
05651
05652 ast_set_flag(options, OPT_SILENT);
05653 res = 0;
05654 }
05655
05656 if (vmu->maxmsg == 0) {
05657 if (option_debug > 2)
05658 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05659 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05660 goto leave_vm_out;
05661 }
05662 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05663 res = ast_stream_and_wait(chan, INTRO, ecodes);
05664 if (res == '#') {
05665 ast_set_flag(options, OPT_SILENT);
05666 res = 0;
05667 }
05668 }
05669 if (res > 0)
05670 ast_stopstream(chan);
05671
05672
05673 if (res == '*') {
05674 chan->exten[0] = 'a';
05675 chan->exten[1] = '\0';
05676 if (!ast_strlen_zero(vmu->exit)) {
05677 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05678 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05679 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05680 }
05681 chan->priority = 0;
05682 free_user(vmu);
05683 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05684 ast_free(tmp);
05685 return 0;
05686 }
05687
05688
05689 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05690 transfer:
05691 if (ouseexten || ousemacro) {
05692 chan->exten[0] = 'o';
05693 chan->exten[1] = '\0';
05694 if (!ast_strlen_zero(vmu->exit)) {
05695 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05696 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05697 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05698 }
05699 ast_play_and_wait(chan, "transfer");
05700 chan->priority = 0;
05701 free_user(vmu);
05702 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05703 }
05704 ast_free(tmp);
05705 return OPERATOR_EXIT;
05706 }
05707
05708
05709 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05710 if (!ast_strlen_zero(options->exitcontext))
05711 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05712 free_user(vmu);
05713 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05714 ast_free(tmp);
05715 return res;
05716 }
05717
05718 if (res < 0) {
05719 free_user(vmu);
05720 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05721 ast_free(tmp);
05722 return -1;
05723 }
05724
05725 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05726 if (!ast_strlen_zero(fmt)) {
05727 msgnum = 0;
05728
05729 #ifdef IMAP_STORAGE
05730
05731
05732 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05733 if (res < 0) {
05734 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05735 ast_free(tmp);
05736 return -1;
05737 }
05738 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05739
05740
05741
05742
05743 if (!(vms = create_vm_state_from_user(vmu))) {
05744 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05745 ast_free(tmp);
05746 return -1;
05747 }
05748 }
05749 vms->newmessages++;
05750
05751
05752 msgnum = newmsgs + oldmsgs;
05753 ast_debug(3, "Messagecount set to %d\n", msgnum);
05754 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05755
05756 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05757
05758 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05759 goto leave_vm_out;
05760 }
05761 #else
05762 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05763 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05764 if (!res)
05765 res = ast_waitstream(chan, "");
05766 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05767 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05768 inprocess_count(vmu->mailbox, vmu->context, -1);
05769 goto leave_vm_out;
05770 }
05771
05772 #endif
05773 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05774 txtdes = mkstemp(tmptxtfile);
05775 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05776 if (txtdes < 0) {
05777 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05778 if (!res)
05779 res = ast_waitstream(chan, "");
05780 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05781 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05782 inprocess_count(vmu->mailbox, vmu->context, -1);
05783 goto leave_vm_out;
05784 }
05785
05786
05787 if (res >= 0) {
05788
05789 res = ast_stream_and_wait(chan, "beep", "");
05790 }
05791
05792
05793 if (ast_check_realtime("voicemail_data")) {
05794 snprintf(priority, sizeof(priority), "%d", chan->priority);
05795 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05796 get_date(date, sizeof(date));
05797 ast_callerid_merge(callerid, sizeof(callerid),
05798 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05799 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05800 "Unknown");
05801 ast_store_realtime("voicemail_data",
05802 "origmailbox", ext,
05803 "context", chan->context,
05804 "macrocontext", chan->macrocontext,
05805 "exten", chan->exten,
05806 "priority", priority,
05807 "callerchan", chan->name,
05808 "callerid", callerid,
05809 "origdate", date,
05810 "origtime", origtime,
05811 "category", S_OR(category, ""),
05812 "filename", tmptxtfile,
05813 SENTINEL);
05814 }
05815
05816
05817 txt = fdopen(txtdes, "w+");
05818 if (txt) {
05819 get_date(date, sizeof(date));
05820 ast_callerid_merge(callerid, sizeof(callerid),
05821 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05822 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05823 "Unknown");
05824 fprintf(txt,
05825 ";\n"
05826 "; Message Information file\n"
05827 ";\n"
05828 "[message]\n"
05829 "origmailbox=%s\n"
05830 "context=%s\n"
05831 "macrocontext=%s\n"
05832 "exten=%s\n"
05833 "rdnis=%s\n"
05834 "priority=%d\n"
05835 "callerchan=%s\n"
05836 "callerid=%s\n"
05837 "origdate=%s\n"
05838 "origtime=%ld\n"
05839 "category=%s\n",
05840 ext,
05841 chan->context,
05842 chan->macrocontext,
05843 chan->exten,
05844 S_COR(chan->redirecting.from.number.valid,
05845 chan->redirecting.from.number.str, "unknown"),
05846 chan->priority,
05847 chan->name,
05848 callerid,
05849 date, (long) time(NULL),
05850 category ? category : "");
05851 } else {
05852 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05853 inprocess_count(vmu->mailbox, vmu->context, -1);
05854 if (ast_check_realtime("voicemail_data")) {
05855 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05856 }
05857 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05858 goto leave_vm_out;
05859 }
05860 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05861
05862 if (txt) {
05863 fprintf(txt, "flag=%s\n", flag);
05864 if (duration < vmu->minsecs) {
05865 fclose(txt);
05866 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmu->minsecs);
05867 ast_filedelete(tmptxtfile, NULL);
05868 unlink(tmptxtfile);
05869 if (ast_check_realtime("voicemail_data")) {
05870 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05871 }
05872 inprocess_count(vmu->mailbox, vmu->context, -1);
05873 } else {
05874 fprintf(txt, "duration=%d\n", duration);
05875 fclose(txt);
05876 if (vm_lock_path(dir)) {
05877 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05878
05879 ast_filedelete(tmptxtfile, NULL);
05880 unlink(tmptxtfile);
05881 inprocess_count(vmu->mailbox, vmu->context, -1);
05882 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05883 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05884 unlink(tmptxtfile);
05885 ast_unlock_path(dir);
05886 inprocess_count(vmu->mailbox, vmu->context, -1);
05887 if (ast_check_realtime("voicemail_data")) {
05888 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05889 }
05890 } else {
05891 #ifndef IMAP_STORAGE
05892 msgnum = last_message_index(vmu, dir) + 1;
05893 #endif
05894 make_file(fn, sizeof(fn), dir, msgnum);
05895
05896
05897 #ifndef IMAP_STORAGE
05898 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05899 #else
05900 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05901 #endif
05902
05903 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05904 ast_filerename(tmptxtfile, fn, NULL);
05905 rename(tmptxtfile, txtfile);
05906 inprocess_count(vmu->mailbox, vmu->context, -1);
05907
05908
05909
05910 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05911 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05912
05913 ast_unlock_path(dir);
05914 if (ast_check_realtime("voicemail_data")) {
05915 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05916 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
05917 }
05918
05919
05920
05921 if (ast_fileexists(fn, NULL, NULL) > 0) {
05922 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05923 }
05924
05925
05926 while (tmpptr) {
05927 struct ast_vm_user recipu, *recip;
05928 char *exten, *cntx;
05929
05930 exten = strsep(&tmpptr, "&");
05931 cntx = strchr(exten, '@');
05932 if (cntx) {
05933 *cntx = '\0';
05934 cntx++;
05935 }
05936 if ((recip = find_user(&recipu, cntx, exten))) {
05937 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05938 free_user(recip);
05939 }
05940 }
05941 #ifndef IMAP_STORAGE
05942 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05943
05944 char sfn[PATH_MAX];
05945 char dfn[PATH_MAX];
05946 int x;
05947
05948 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05949 x = last_message_index(vmu, urgdir) + 1;
05950 make_file(sfn, sizeof(sfn), dir, msgnum);
05951 make_file(dfn, sizeof(dfn), urgdir, x);
05952 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
05953 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05954
05955 ast_copy_string(fn, dfn, sizeof(fn));
05956 msgnum = x;
05957 }
05958 #endif
05959
05960 if (ast_fileexists(fn, NULL, NULL)) {
05961 #ifdef IMAP_STORAGE
05962 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
05963 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05964 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05965 flag);
05966 #else
05967 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
05968 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05969 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05970 flag);
05971 #endif
05972 }
05973
05974
05975 if (ast_fileexists(fn, NULL, NULL)) {
05976 DISPOSE(dir, msgnum);
05977 }
05978 }
05979 }
05980 } else {
05981 inprocess_count(vmu->mailbox, vmu->context, -1);
05982 }
05983 if (res == '0') {
05984 goto transfer;
05985 } else if (res > 0 && res != 't')
05986 res = 0;
05987
05988 if (duration < vmu->minsecs)
05989
05990 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05991 else
05992 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05993 } else
05994 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
05995 leave_vm_out:
05996 free_user(vmu);
05997
05998 #ifdef IMAP_STORAGE
05999
06000 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06001 if (expungeonhangup == 1) {
06002 ast_mutex_lock(&vms->lock);
06003 #ifdef HAVE_IMAP_TK2006
06004 if (LEVELUIDPLUS (vms->mailstream)) {
06005 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06006 } else
06007 #endif
06008 mail_expunge(vms->mailstream);
06009 ast_mutex_unlock(&vms->lock);
06010 }
06011 #endif
06012
06013 ast_free(tmp);
06014 return res;
06015 }
06016
06017 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06018 {
06019 int d;
06020 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06021 return d;
06022 }
06023
06024 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06025 {
06026 #ifdef IMAP_STORAGE
06027
06028
06029 char sequence[10];
06030 char mailbox[256];
06031 int res;
06032
06033
06034 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06035
06036 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06037 ast_mutex_lock(&vms->lock);
06038
06039 if (box == OLD_FOLDER) {
06040 mail_setflag(vms->mailstream, sequence, "\\Seen");
06041 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06042 } else if (box == NEW_FOLDER) {
06043 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06044 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06045 }
06046 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06047 ast_mutex_unlock(&vms->lock);
06048 return 0;
06049 }
06050
06051 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06052 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06053 if (mail_create(vms->mailstream, mailbox) == NIL)
06054 ast_debug(5, "Folder exists.\n");
06055 else
06056 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06057 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06058 ast_mutex_unlock(&vms->lock);
06059 return res;
06060 #else
06061 char *dir = vms->curdir;
06062 char *username = vms->username;
06063 char *context = vmu->context;
06064 char sfn[PATH_MAX];
06065 char dfn[PATH_MAX];
06066 char ddir[PATH_MAX];
06067 const char *dbox = mbox(vmu, box);
06068 int x, i;
06069 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06070
06071 if (vm_lock_path(ddir))
06072 return ERROR_LOCK_PATH;
06073
06074 x = last_message_index(vmu, ddir) + 1;
06075
06076 if (box == 10 && x >= vmu->maxdeletedmsg) {
06077 x--;
06078 for (i = 1; i <= x; i++) {
06079
06080 make_file(sfn, sizeof(sfn), ddir, i);
06081 make_file(dfn, sizeof(dfn), ddir, i - 1);
06082 if (EXISTS(ddir, i, sfn, NULL)) {
06083 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06084 } else
06085 break;
06086 }
06087 } else {
06088 if (x >= vmu->maxmsg) {
06089 ast_unlock_path(ddir);
06090 return -1;
06091 }
06092 }
06093 make_file(sfn, sizeof(sfn), dir, msg);
06094 make_file(dfn, sizeof(dfn), ddir, x);
06095 if (strcmp(sfn, dfn)) {
06096 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06097 }
06098 ast_unlock_path(ddir);
06099 #endif
06100 return 0;
06101 }
06102
06103 static int adsi_logo(unsigned char *buf)
06104 {
06105 int bytes = 0;
06106 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06107 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06108 return bytes;
06109 }
06110
06111 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06112 {
06113 unsigned char buf[256];
06114 int bytes = 0;
06115 int x;
06116 char num[5];
06117
06118 *useadsi = 0;
06119 bytes += ast_adsi_data_mode(buf + bytes);
06120 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06121
06122 bytes = 0;
06123 bytes += adsi_logo(buf);
06124 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06125 #ifdef DISPLAY
06126 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06127 #endif
06128 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06129 bytes += ast_adsi_data_mode(buf + bytes);
06130 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06131
06132 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06133 bytes = 0;
06134 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06135 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06136 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06137 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06138 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06139 return 0;
06140 }
06141
06142 #ifdef DISPLAY
06143
06144 bytes = 0;
06145 bytes += ast_adsi_logo(buf);
06146 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06147 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06148 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06149 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06150 #endif
06151 bytes = 0;
06152 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06153 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06154 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06155 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06156 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06157 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06158 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06159
06160 #ifdef DISPLAY
06161
06162 bytes = 0;
06163 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06164 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06165
06166 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06167 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06168 #endif
06169
06170 bytes = 0;
06171
06172 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06173 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06174 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06175 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06176 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06177 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06178 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06179
06180 #ifdef DISPLAY
06181
06182 bytes = 0;
06183 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06184 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06185 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06186 #endif
06187
06188 bytes = 0;
06189 for (x = 0; x < 5; x++) {
06190 snprintf(num, sizeof(num), "%d", x);
06191 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06192 }
06193 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06194 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06195
06196 #ifdef DISPLAY
06197
06198 bytes = 0;
06199 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06200 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06201 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06202 #endif
06203
06204 if (ast_adsi_end_download(chan)) {
06205 bytes = 0;
06206 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06207 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06208 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06209 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06210 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06211 return 0;
06212 }
06213 bytes = 0;
06214 bytes += ast_adsi_download_disconnect(buf + bytes);
06215 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06216 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06217
06218 ast_debug(1, "Done downloading scripts...\n");
06219
06220 #ifdef DISPLAY
06221
06222 bytes = 0;
06223 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06224 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06225 #endif
06226 ast_debug(1, "Restarting session...\n");
06227
06228 bytes = 0;
06229
06230 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06231 *useadsi = 1;
06232 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06233 } else
06234 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06235
06236 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06237 return 0;
06238 }
06239
06240 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06241 {
06242 int x;
06243 if (!ast_adsi_available(chan))
06244 return;
06245 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06246 if (x < 0)
06247 return;
06248 if (!x) {
06249 if (adsi_load_vmail(chan, useadsi)) {
06250 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06251 return;
06252 }
06253 } else
06254 *useadsi = 1;
06255 }
06256
06257 static void adsi_login(struct ast_channel *chan)
06258 {
06259 unsigned char buf[256];
06260 int bytes = 0;
06261 unsigned char keys[8];
06262 int x;
06263 if (!ast_adsi_available(chan))
06264 return;
06265
06266 for (x = 0; x < 8; x++)
06267 keys[x] = 0;
06268
06269 keys[3] = ADSI_KEY_APPS + 3;
06270
06271 bytes += adsi_logo(buf + bytes);
06272 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06273 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06274 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06275 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06276 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06277 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06278 bytes += ast_adsi_set_keys(buf + bytes, keys);
06279 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06280 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06281 }
06282
06283 static void adsi_password(struct ast_channel *chan)
06284 {
06285 unsigned char buf[256];
06286 int bytes = 0;
06287 unsigned char keys[8];
06288 int x;
06289 if (!ast_adsi_available(chan))
06290 return;
06291
06292 for (x = 0; x < 8; x++)
06293 keys[x] = 0;
06294
06295 keys[3] = ADSI_KEY_APPS + 3;
06296
06297 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06298 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06299 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06300 bytes += ast_adsi_set_keys(buf + bytes, keys);
06301 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06302 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06303 }
06304
06305 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06306 {
06307 unsigned char buf[256];
06308 int bytes = 0;
06309 unsigned char keys[8];
06310 int x, y;
06311
06312 if (!ast_adsi_available(chan))
06313 return;
06314
06315 for (x = 0; x < 5; x++) {
06316 y = ADSI_KEY_APPS + 12 + start + x;
06317 if (y > ADSI_KEY_APPS + 12 + 4)
06318 y = 0;
06319 keys[x] = ADSI_KEY_SKT | y;
06320 }
06321 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06322 keys[6] = 0;
06323 keys[7] = 0;
06324
06325 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06326 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06327 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06328 bytes += ast_adsi_set_keys(buf + bytes, keys);
06329 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06330
06331 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06332 }
06333
06334 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06335 {
06336 int bytes = 0;
06337 unsigned char buf[256];
06338 char buf1[256], buf2[256];
06339 char fn2[PATH_MAX];
06340
06341 char cid[256] = "";
06342 char *val;
06343 char *name, *num;
06344 char datetime[21] = "";
06345 FILE *f;
06346
06347 unsigned char keys[8];
06348
06349 int x;
06350
06351 if (!ast_adsi_available(chan))
06352 return;
06353
06354
06355 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06356 f = fopen(fn2, "r");
06357 if (f) {
06358 while (!feof(f)) {
06359 if (!fgets((char *) buf, sizeof(buf), f)) {
06360 continue;
06361 }
06362 if (!feof(f)) {
06363 char *stringp = NULL;
06364 stringp = (char *) buf;
06365 strsep(&stringp, "=");
06366 val = strsep(&stringp, "=");
06367 if (!ast_strlen_zero(val)) {
06368 if (!strcmp((char *) buf, "callerid"))
06369 ast_copy_string(cid, val, sizeof(cid));
06370 if (!strcmp((char *) buf, "origdate"))
06371 ast_copy_string(datetime, val, sizeof(datetime));
06372 }
06373 }
06374 }
06375 fclose(f);
06376 }
06377
06378 for (x = 0; x < 5; x++)
06379 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06380 keys[6] = 0x0;
06381 keys[7] = 0x0;
06382
06383 if (!vms->curmsg) {
06384
06385 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06386 }
06387 if (vms->curmsg >= vms->lastmsg) {
06388
06389 if (vms->curmsg) {
06390
06391 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06392 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06393
06394 } else {
06395
06396 keys[3] = 1;
06397 }
06398 }
06399
06400 if (!ast_strlen_zero(cid)) {
06401 ast_callerid_parse(cid, &name, &num);
06402 if (!name)
06403 name = num;
06404 } else
06405 name = "Unknown Caller";
06406
06407
06408
06409 if (vms->deleted[vms->curmsg])
06410 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06411
06412
06413 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06414 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06415 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06416 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06417
06418 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06419 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06420 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06421 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06422 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06423 bytes += ast_adsi_set_keys(buf + bytes, keys);
06424 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06425
06426 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06427 }
06428
06429 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06430 {
06431 int bytes = 0;
06432 unsigned char buf[256];
06433 unsigned char keys[8];
06434
06435 int x;
06436
06437 if (!ast_adsi_available(chan))
06438 return;
06439
06440
06441 for (x = 0; x < 5; x++)
06442 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06443
06444 keys[6] = 0x0;
06445 keys[7] = 0x0;
06446
06447 if (!vms->curmsg) {
06448
06449 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06450 }
06451 if (vms->curmsg >= vms->lastmsg) {
06452
06453 if (vms->curmsg) {
06454
06455 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06456 } else {
06457
06458 keys[3] = 1;
06459 }
06460 }
06461
06462
06463 if (vms->deleted[vms->curmsg])
06464 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06465
06466
06467 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06468 bytes += ast_adsi_set_keys(buf + bytes, keys);
06469 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06470
06471 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06472 }
06473
06474 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06475 {
06476 unsigned char buf[256] = "";
06477 char buf1[256] = "", buf2[256] = "";
06478 int bytes = 0;
06479 unsigned char keys[8];
06480 int x;
06481
06482 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06483 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06484 if (!ast_adsi_available(chan))
06485 return;
06486 if (vms->newmessages) {
06487 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06488 if (vms->oldmessages) {
06489 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06490 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06491 } else {
06492 snprintf(buf2, sizeof(buf2), "%s.", newm);
06493 }
06494 } else if (vms->oldmessages) {
06495 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06496 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06497 } else {
06498 strcpy(buf1, "You have no messages.");
06499 buf2[0] = ' ';
06500 buf2[1] = '\0';
06501 }
06502 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06503 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06504 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06505
06506 for (x = 0; x < 6; x++)
06507 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06508 keys[6] = 0;
06509 keys[7] = 0;
06510
06511
06512 if (vms->lastmsg < 0)
06513 keys[0] = 1;
06514 bytes += ast_adsi_set_keys(buf + bytes, keys);
06515
06516 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06517
06518 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06519 }
06520
06521 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06522 {
06523 unsigned char buf[256] = "";
06524 char buf1[256] = "", buf2[256] = "";
06525 int bytes = 0;
06526 unsigned char keys[8];
06527 int x;
06528
06529 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06530
06531 if (!ast_adsi_available(chan))
06532 return;
06533
06534
06535 for (x = 0; x < 6; x++)
06536 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06537
06538 keys[6] = 0;
06539 keys[7] = 0;
06540
06541 if ((vms->lastmsg + 1) < 1)
06542 keys[0] = 0;
06543
06544 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06545 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06546
06547 if (vms->lastmsg + 1)
06548 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06549 else
06550 strcpy(buf2, "no messages.");
06551 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06552 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06553 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06554 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06555 bytes += ast_adsi_set_keys(buf + bytes, keys);
06556
06557 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06558
06559 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06560
06561 }
06562
06563
06564
06565
06566
06567
06568
06569
06570
06571
06572
06573
06574
06575
06576
06577 static void adsi_goodbye(struct ast_channel *chan)
06578 {
06579 unsigned char buf[256];
06580 int bytes = 0;
06581
06582 if (!ast_adsi_available(chan))
06583 return;
06584 bytes += adsi_logo(buf + bytes);
06585 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06586 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06587 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06588 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06589
06590 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06591 }
06592
06593
06594
06595
06596
06597 static int get_folder(struct ast_channel *chan, int start)
06598 {
06599 int x;
06600 int d;
06601 char fn[PATH_MAX];
06602 d = ast_play_and_wait(chan, "vm-press");
06603 if (d)
06604 return d;
06605 for (x = start; x < 5; x++) {
06606 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06607 return d;
06608 d = ast_play_and_wait(chan, "vm-for");
06609 if (d)
06610 return d;
06611 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06612 d = vm_play_folder_name(chan, fn);
06613 if (d)
06614 return d;
06615 d = ast_waitfordigit(chan, 500);
06616 if (d)
06617 return d;
06618 }
06619 d = ast_play_and_wait(chan, "vm-tocancel");
06620 if (d)
06621 return d;
06622 d = ast_waitfordigit(chan, 4000);
06623 return d;
06624 }
06625
06626
06627
06628
06629
06630
06631
06632
06633
06634
06635
06636
06637
06638 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06639 {
06640 int res = 0;
06641 int loops = 0;
06642 res = ast_play_and_wait(chan, fn);
06643 while (((res < '0') || (res > '9')) &&
06644 (res != '#') && (res >= 0) &&
06645 loops < 4) {
06646 res = get_folder(chan, 0);
06647 loops++;
06648 }
06649 if (loops == 4) {
06650 return '#';
06651 }
06652 return res;
06653 }
06654
06655
06656
06657
06658
06659
06660
06661
06662
06663
06664
06665
06666
06667
06668
06669
06670
06671
06672
06673 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06674 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06675 {
06676 #ifdef IMAP_STORAGE
06677 int res;
06678 #endif
06679 int cmd = 0;
06680 int retries = 0, prepend_duration = 0, already_recorded = 0;
06681 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06682 char textfile[PATH_MAX];
06683 struct ast_config *msg_cfg;
06684 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06685 #ifndef IMAP_STORAGE
06686 signed char zero_gain = 0;
06687 #endif
06688 const char *duration_str;
06689
06690
06691 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06692 strcpy(textfile, msgfile);
06693 strcpy(backup, msgfile);
06694 strcpy(backup_textfile, msgfile);
06695 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06696 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06697 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06698
06699 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06700 *duration = atoi(duration_str);
06701 } else {
06702 *duration = 0;
06703 }
06704
06705 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06706 if (cmd)
06707 retries = 0;
06708 switch (cmd) {
06709 case '1':
06710
06711 #ifdef IMAP_STORAGE
06712
06713 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06714 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06715 res = ast_play_and_wait(chan, INTRO);
06716 res = ast_play_and_wait(chan, "beep");
06717 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, record_gain, vms, flag);
06718 cmd = 't';
06719 #else
06720
06721
06722
06723 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06724 strcpy(textfile, msgfile);
06725 strncat(textfile, ".txt", sizeof(textfile) - 1);
06726 *duration = 0;
06727
06728
06729 if (!msg_cfg) {
06730 cmd = 0;
06731 break;
06732 }
06733
06734
06735 if (already_recorded) {
06736 ast_filecopy(backup, msgfile, NULL);
06737 copy(backup_textfile, textfile);
06738 }
06739 else {
06740 ast_filecopy(msgfile, backup, NULL);
06741 copy(textfile,backup_textfile);
06742 }
06743 already_recorded = 1;
06744
06745 if (record_gain)
06746 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06747
06748 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06749 if (cmd == 'S') {
06750 ast_filerename(backup, msgfile, NULL);
06751 }
06752
06753 if (record_gain)
06754 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06755
06756
06757 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06758 *duration = atoi(duration_str);
06759
06760 if (prepend_duration) {
06761 struct ast_category *msg_cat;
06762
06763 char duration_buf[12];
06764
06765 *duration += prepend_duration;
06766 msg_cat = ast_category_get(msg_cfg, "message");
06767 snprintf(duration_buf, 11, "%ld", *duration);
06768 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06769 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06770 }
06771 }
06772
06773 #endif
06774 break;
06775 case '2':
06776
06777 #ifdef IMAP_STORAGE
06778 *vms->introfn = '\0';
06779 #endif
06780 cmd = 't';
06781 break;
06782 case '*':
06783 cmd = '*';
06784 break;
06785 default:
06786 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06787
06788 if (!cmd)
06789 cmd = ast_play_and_wait(chan, "vm-starmain");
06790
06791 if (!cmd)
06792 cmd = ast_waitfordigit(chan, 6000);
06793 if (!cmd)
06794 retries++;
06795 if (retries > 3)
06796 cmd = 't';
06797 }
06798 }
06799
06800 if (msg_cfg)
06801 ast_config_destroy(msg_cfg);
06802 if (prepend_duration)
06803 *duration = prepend_duration;
06804
06805 if (already_recorded && cmd == -1) {
06806
06807 ast_filerename(backup, msgfile, NULL);
06808 rename(backup_textfile, textfile);
06809 }
06810
06811 if (cmd == 't' || cmd == 'S')
06812 cmd = 0;
06813 return cmd;
06814 }
06815
06816 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06817 {
06818 struct ast_event *event;
06819 char *mailbox, *context;
06820
06821
06822 context = mailbox = ast_strdupa(box);
06823 strsep(&context, "@");
06824 if (ast_strlen_zero(context))
06825 context = "default";
06826
06827 if (!(event = ast_event_new(AST_EVENT_MWI,
06828 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06829 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06830 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06831 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06832 AST_EVENT_IE_END))) {
06833 return;
06834 }
06835
06836 ast_event_queue_and_cache(event);
06837 }
06838
06839
06840
06841
06842
06843
06844
06845
06846
06847
06848
06849
06850
06851
06852
06853 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)
06854 {
06855 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06856 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06857 const char *category;
06858 char *myserveremail = serveremail;
06859
06860 ast_channel_lock(chan);
06861 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06862 category = ast_strdupa(category);
06863 }
06864 ast_channel_unlock(chan);
06865
06866 #ifndef IMAP_STORAGE
06867 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
06868 #else
06869 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
06870 #endif
06871 make_file(fn, sizeof(fn), todir, msgnum);
06872 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06873
06874 if (!ast_strlen_zero(vmu->attachfmt)) {
06875 if (strstr(fmt, vmu->attachfmt))
06876 fmt = vmu->attachfmt;
06877 else
06878 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);
06879 }
06880
06881
06882 fmt = ast_strdupa(fmt);
06883 stringp = fmt;
06884 strsep(&stringp, "|");
06885
06886 if (!ast_strlen_zero(vmu->serveremail))
06887 myserveremail = vmu->serveremail;
06888
06889 if (!ast_strlen_zero(vmu->email)) {
06890 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
06891
06892 if (attach_user_voicemail)
06893 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
06894
06895
06896 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
06897
06898 if (attach_user_voicemail)
06899 DISPOSE(todir, msgnum);
06900 }
06901
06902 if (!ast_strlen_zero(vmu->pager)) {
06903 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
06904 }
06905
06906 if (ast_test_flag(vmu, VM_DELETE))
06907 DELETE(todir, msgnum, fn, vmu);
06908
06909
06910 if (ast_app_has_voicemail(ext_context, NULL))
06911 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
06912
06913 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
06914
06915 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);
06916 run_externnotify(vmu->context, vmu->mailbox, flag);
06917
06918 #ifdef IMAP_STORAGE
06919 vm_delete(fn);
06920 if (ast_test_flag(vmu, VM_DELETE)) {
06921 vm_imap_delete(NULL, vms->curmsg, vmu);
06922 vms->newmessages--;
06923 }
06924 #endif
06925
06926 return 0;
06927 }
06928
06929
06930
06931
06932
06933
06934
06935
06936
06937
06938
06939
06940
06941
06942
06943
06944
06945
06946
06947
06948
06949
06950
06951
06952
06953
06954
06955
06956 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)
06957 {
06958 #ifdef IMAP_STORAGE
06959 int todircount = 0;
06960 struct vm_state *dstvms;
06961 #endif
06962 char username[70]="";
06963 char fn[PATH_MAX];
06964 char ecodes[16] = "#";
06965 int res = 0, cmd = 0;
06966 struct ast_vm_user *receiver = NULL, *vmtmp;
06967 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06968 char *stringp;
06969 const char *s;
06970 int saved_messages = 0;
06971 int valid_extensions = 0;
06972 char *dir;
06973 int curmsg;
06974 char urgent_str[7] = "";
06975 char tmptxtfile[PATH_MAX];
06976 int prompt_played = 0;
06977 #ifndef IMAP_STORAGE
06978 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06979 #endif
06980 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
06981 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
06982 }
06983
06984 if (vms == NULL) return -1;
06985 dir = vms->curdir;
06986 curmsg = vms->curmsg;
06987
06988 tmptxtfile[0] = '\0';
06989 while (!res && !valid_extensions) {
06990 int use_directory = 0;
06991 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
06992 int done = 0;
06993 int retries = 0;
06994 cmd = 0;
06995 while ((cmd >= 0) && !done ){
06996 if (cmd)
06997 retries = 0;
06998 switch (cmd) {
06999 case '1':
07000 use_directory = 0;
07001 done = 1;
07002 break;
07003 case '2':
07004 use_directory = 1;
07005 done = 1;
07006 break;
07007 case '*':
07008 cmd = 't';
07009 done = 1;
07010 break;
07011 default:
07012
07013 cmd = ast_play_and_wait(chan, "vm-forward");
07014 if (!cmd)
07015 cmd = ast_waitfordigit(chan, 3000);
07016 if (!cmd)
07017 retries++;
07018 if (retries > 3) {
07019 cmd = 't';
07020 done = 1;
07021 }
07022
07023 }
07024 }
07025 if (cmd < 0 || cmd == 't')
07026 break;
07027 }
07028
07029 if (use_directory) {
07030
07031
07032 char old_context[sizeof(chan->context)];
07033 char old_exten[sizeof(chan->exten)];
07034 int old_priority;
07035 struct ast_app* directory_app;
07036
07037 directory_app = pbx_findapp("Directory");
07038 if (directory_app) {
07039 char vmcontext[256];
07040
07041 memcpy(old_context, chan->context, sizeof(chan->context));
07042 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07043 old_priority = chan->priority;
07044
07045
07046 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07047 res = pbx_exec(chan, directory_app, vmcontext);
07048
07049 ast_copy_string(username, chan->exten, sizeof(username));
07050
07051
07052 memcpy(chan->context, old_context, sizeof(chan->context));
07053 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07054 chan->priority = old_priority;
07055 } else {
07056 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07057 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07058 }
07059 } else {
07060
07061 res = ast_streamfile(chan, "vm-extension", chan->language);
07062 prompt_played++;
07063 if (res || prompt_played > 4)
07064 break;
07065 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07066 break;
07067 }
07068
07069
07070 if (ast_strlen_zero(username))
07071 continue;
07072 stringp = username;
07073 s = strsep(&stringp, "*");
07074
07075 valid_extensions = 1;
07076 while (s) {
07077 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07078 int oldmsgs;
07079 int newmsgs;
07080 int capacity;
07081 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07082 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07083
07084 res = ast_play_and_wait(chan, "pbx-invalid");
07085 valid_extensions = 0;
07086 break;
07087 }
07088 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07089 if ((newmsgs + oldmsgs) >= capacity) {
07090 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07091 res = ast_play_and_wait(chan, "vm-mailboxfull");
07092 valid_extensions = 0;
07093 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07094 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07095 free_user(vmtmp);
07096 }
07097 inprocess_count(receiver->mailbox, receiver->context, -1);
07098 break;
07099 }
07100 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07101 } else {
07102
07103
07104
07105
07106
07107 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07108 free_user(receiver);
07109 }
07110 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07111
07112 res = ast_play_and_wait(chan, "pbx-invalid");
07113 valid_extensions = 0;
07114 break;
07115 }
07116
07117
07118 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07119 RETRIEVE(fn, -1, s, receiver->context);
07120 if (ast_fileexists(fn, NULL, NULL) > 0) {
07121 res = ast_stream_and_wait(chan, fn, ecodes);
07122 if (res) {
07123 DISPOSE(fn, -1);
07124 return res;
07125 }
07126 } else {
07127 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07128 }
07129 DISPOSE(fn, -1);
07130
07131 s = strsep(&stringp, "*");
07132 }
07133
07134 if (valid_extensions)
07135 break;
07136 }
07137
07138 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07139 return res;
07140 if (is_new_message == 1) {
07141 struct leave_vm_options leave_options;
07142 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07143 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07144
07145
07146 memset(&leave_options, 0, sizeof(leave_options));
07147 leave_options.record_gain = record_gain;
07148 cmd = leave_voicemail(chan, mailbox, &leave_options);
07149 } else {
07150
07151 long duration = 0;
07152 struct vm_state vmstmp;
07153 int copy_msg_result = 0;
07154 memcpy(&vmstmp, vms, sizeof(vmstmp));
07155
07156 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07157
07158 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07159 if (!cmd) {
07160 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07161 #ifdef IMAP_STORAGE
07162 int attach_user_voicemail;
07163 char *myserveremail = serveremail;
07164
07165
07166 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07167 if (!dstvms) {
07168 dstvms = create_vm_state_from_user(vmtmp);
07169 }
07170 if (dstvms) {
07171 init_mailstream(dstvms, 0);
07172 if (!dstvms->mailstream) {
07173 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07174 } else {
07175 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07176 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07177 }
07178 } else {
07179 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07180 }
07181 if (!ast_strlen_zero(vmtmp->serveremail))
07182 myserveremail = vmtmp->serveremail;
07183 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07184
07185 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07186 dstvms->curbox,
07187 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07188 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07189 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07190 NULL, urgent_str);
07191 #else
07192 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07193 #endif
07194 saved_messages++;
07195 AST_LIST_REMOVE_CURRENT(list);
07196 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07197 free_user(vmtmp);
07198 if (res)
07199 break;
07200 }
07201 AST_LIST_TRAVERSE_SAFE_END;
07202 if (saved_messages > 0 && !copy_msg_result) {
07203
07204
07205
07206
07207
07208
07209
07210
07211 #ifdef IMAP_STORAGE
07212
07213 if (ast_strlen_zero(vmstmp.introfn))
07214 #endif
07215 res = ast_play_and_wait(chan, "vm-msgsaved");
07216 }
07217 #ifndef IMAP_STORAGE
07218 else {
07219
07220 res = ast_play_and_wait(chan, "vm-mailboxfull");
07221 }
07222
07223 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07224 strcpy(textfile, msgfile);
07225 strcpy(backup, msgfile);
07226 strcpy(backup_textfile, msgfile);
07227 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07228 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07229 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07230 if (ast_fileexists(backup, NULL, NULL) > 0) {
07231 ast_filerename(backup, msgfile, NULL);
07232 rename(backup_textfile, textfile);
07233 }
07234 #endif
07235 }
07236 DISPOSE(dir, curmsg);
07237 #ifndef IMAP_STORAGE
07238 if (cmd) {
07239 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07240 strcpy(textfile, msgfile);
07241 strcpy(backup_textfile, msgfile);
07242 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07243 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07244 rename(backup_textfile, textfile);
07245 }
07246 #endif
07247 }
07248
07249
07250 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07251 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07252 free_user(vmtmp);
07253 }
07254 return res ? res : cmd;
07255 }
07256
07257 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07258 {
07259 int res;
07260 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07261 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07262 return res;
07263 }
07264
07265 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07266 {
07267 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);
07268 }
07269
07270 static int play_message_category(struct ast_channel *chan, const char *category)
07271 {
07272 int res = 0;
07273
07274 if (!ast_strlen_zero(category))
07275 res = ast_play_and_wait(chan, category);
07276
07277 if (res) {
07278 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07279 res = 0;
07280 }
07281
07282 return res;
07283 }
07284
07285 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07286 {
07287 int res = 0;
07288 struct vm_zone *the_zone = NULL;
07289 time_t t;
07290
07291 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07292 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07293 return 0;
07294 }
07295
07296
07297 if (!ast_strlen_zero(vmu->zonetag)) {
07298
07299 struct vm_zone *z;
07300 AST_LIST_LOCK(&zones);
07301 AST_LIST_TRAVERSE(&zones, z, list) {
07302 if (!strcmp(z->name, vmu->zonetag)) {
07303 the_zone = z;
07304 break;
07305 }
07306 }
07307 AST_LIST_UNLOCK(&zones);
07308 }
07309
07310
07311 #if 0
07312
07313 ast_localtime(&t, &time_now, NULL);
07314 tv_now = ast_tvnow();
07315 ast_localtime(&tv_now, &time_then, NULL);
07316
07317
07318 if (time_now.tm_year == time_then.tm_year)
07319 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07320 else
07321 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07322 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07323
07324
07325 #endif
07326 if (the_zone) {
07327 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07328 } else if (!strncasecmp(chan->language, "de", 2)) {
07329 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07330 } else if (!strncasecmp(chan->language, "gr", 2)) {
07331 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07332 } else if (!strncasecmp(chan->language, "it", 2)) {
07333 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);
07334 } else if (!strncasecmp(chan->language, "nl", 2)) {
07335 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07336 } else if (!strncasecmp(chan->language, "no", 2)) {
07337 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07338 } else if (!strncasecmp(chan->language, "pl", 2)) {
07339 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07340 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07341 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);
07342 } else if (!strncasecmp(chan->language, "se", 2)) {
07343 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07344 } else if (!strncasecmp(chan->language, "zh", 2)) {
07345 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07346 } else if (!strncasecmp(chan->language, "vi", 2)) {
07347 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);
07348 } else {
07349 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07350 }
07351 #if 0
07352 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07353 #endif
07354 return res;
07355 }
07356
07357
07358
07359 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07360 {
07361 int res = 0;
07362 int i;
07363 char *callerid, *name;
07364 char prefile[PATH_MAX] = "";
07365
07366
07367
07368
07369
07370
07371
07372
07373
07374 if ((cid == NULL)||(context == NULL))
07375 return res;
07376
07377
07378 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07379 ast_callerid_parse(cid, &name, &callerid);
07380 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07381
07382
07383 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07384 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07385 if ((strcmp(cidinternalcontexts[i], context) == 0))
07386 break;
07387 }
07388 if (i != MAX_NUM_CID_CONTEXTS){
07389 if (!res) {
07390 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07391 if (!ast_strlen_zero(prefile)) {
07392
07393 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07394 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07395 if (!callback)
07396 res = wait_file2(chan, vms, "vm-from");
07397 res = ast_stream_and_wait(chan, prefile, "");
07398 } else {
07399 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07400
07401 if (!callback)
07402 res = wait_file2(chan, vms, "vm-from-extension");
07403 res = ast_say_digit_str(chan, callerid, "", chan->language);
07404 }
07405 }
07406 }
07407 } else if (!res) {
07408 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07409
07410 if (!callback)
07411 res = wait_file2(chan, vms, "vm-from-phonenumber");
07412 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07413 }
07414 } else {
07415
07416 ast_debug(1, "VM-CID: From an unknown number\n");
07417
07418 res = wait_file2(chan, vms, "vm-unknown-caller");
07419 }
07420 return res;
07421 }
07422
07423 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07424 {
07425 int res = 0;
07426 int durationm;
07427 int durations;
07428
07429 if (duration == NULL)
07430 return res;
07431
07432
07433 durations = atoi(duration);
07434 durationm = (durations / 60);
07435
07436 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07437
07438 if ((!res) && (durationm >= minduration)) {
07439 res = wait_file2(chan, vms, "vm-duration");
07440
07441
07442 if (!strncasecmp(chan->language, "pl", 2)) {
07443 div_t num = div(durationm, 10);
07444
07445 if (durationm == 1) {
07446 res = ast_play_and_wait(chan, "digits/1z");
07447 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07448 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07449 if (num.rem == 2) {
07450 if (!num.quot) {
07451 res = ast_play_and_wait(chan, "digits/2-ie");
07452 } else {
07453 res = say_and_wait(chan, durationm - 2 , chan->language);
07454 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07455 }
07456 } else {
07457 res = say_and_wait(chan, durationm, chan->language);
07458 }
07459 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07460 } else {
07461 res = say_and_wait(chan, durationm, chan->language);
07462 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07463 }
07464
07465 } else {
07466 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07467 res = wait_file2(chan, vms, "vm-minutes");
07468 }
07469 }
07470 return res;
07471 }
07472
07473 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07474 {
07475 int res = 0;
07476 char filename[256], *cid;
07477 const char *origtime, *context, *category, *duration, *flag;
07478 struct ast_config *msg_cfg;
07479 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07480
07481 vms->starting = 0;
07482 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07483 adsi_message(chan, vms);
07484 if (!vms->curmsg)
07485 res = wait_file2(chan, vms, "vm-first");
07486 else if (vms->curmsg == vms->lastmsg)
07487 res = wait_file2(chan, vms, "vm-last");
07488
07489 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07490 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07491 msg_cfg = ast_config_load(filename, config_flags);
07492 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07493 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07494 return 0;
07495 }
07496 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07497
07498
07499 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07500 res = wait_file2(chan, vms, "vm-Urgent");
07501 }
07502
07503 if (!res) {
07504
07505
07506 if (!strncasecmp(chan->language, "pl", 2)) {
07507 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07508 int ten, one;
07509 char nextmsg[256];
07510 ten = (vms->curmsg + 1) / 10;
07511 one = (vms->curmsg + 1) % 10;
07512
07513 if (vms->curmsg < 20) {
07514 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07515 res = wait_file2(chan, vms, nextmsg);
07516 } else {
07517 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07518 res = wait_file2(chan, vms, nextmsg);
07519 if (one > 0) {
07520 if (!res) {
07521 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07522 res = wait_file2(chan, vms, nextmsg);
07523 }
07524 }
07525 }
07526 }
07527 if (!res)
07528 res = wait_file2(chan, vms, "vm-message");
07529
07530 } else if (!strncasecmp(chan->language, "he", 2)) {
07531 if (!vms->curmsg) {
07532 res = wait_file2(chan, vms, "vm-message");
07533 res = wait_file2(chan, vms, "vm-first");
07534 } else if (vms->curmsg == vms->lastmsg) {
07535 res = wait_file2(chan, vms, "vm-message");
07536 res = wait_file2(chan, vms, "vm-last");
07537 } else {
07538 res = wait_file2(chan, vms, "vm-message");
07539 res = wait_file2(chan, vms, "vm-number");
07540 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07541 }
07542
07543 } else if (!strncasecmp(chan->language, "vi", 2)) {
07544 if (!vms->curmsg) {
07545 res = wait_file2(chan, vms, "vm-message");
07546 res = wait_file2(chan, vms, "vm-first");
07547 } else if (vms->curmsg == vms->lastmsg) {
07548 res = wait_file2(chan, vms, "vm-message");
07549 res = wait_file2(chan, vms, "vm-last");
07550 } else {
07551 res = wait_file2(chan, vms, "vm-message");
07552 res = wait_file2(chan, vms, "vm-number");
07553 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07554 }
07555 } else {
07556 if (!strncasecmp(chan->language, "se", 2)) {
07557 res = wait_file2(chan, vms, "vm-meddelandet");
07558 } else {
07559 res = wait_file2(chan, vms, "vm-message");
07560 }
07561 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07562 if (!res) {
07563 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07564 }
07565 }
07566 }
07567 }
07568
07569 if (!msg_cfg) {
07570 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07571 return 0;
07572 }
07573
07574 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07575 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07576 DISPOSE(vms->curdir, vms->curmsg);
07577 ast_config_destroy(msg_cfg);
07578 return 0;
07579 }
07580
07581 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07582 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07583 category = ast_variable_retrieve(msg_cfg, "message", "category");
07584
07585 context = ast_variable_retrieve(msg_cfg, "message", "context");
07586 if (!strncasecmp("macro", context, 5))
07587 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07588 if (!res) {
07589 res = play_message_category(chan, category);
07590 }
07591 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
07592 res = play_message_datetime(chan, vmu, origtime, filename);
07593 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
07594 res = play_message_callerid(chan, vms, cid, context, 0);
07595 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
07596 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07597
07598 if (res == '1')
07599 res = 0;
07600 ast_config_destroy(msg_cfg);
07601
07602 if (!res) {
07603 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07604 vms->heard[vms->curmsg] = 1;
07605 #ifdef IMAP_STORAGE
07606
07607
07608
07609 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07610 wait_file(chan, vms, vms->introfn);
07611 }
07612 #endif
07613 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07614 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07615 res = 0;
07616 }
07617 }
07618 DISPOSE(vms->curdir, vms->curmsg);
07619 return res;
07620 }
07621
07622 #ifdef IMAP_STORAGE
07623 static int imap_remove_file(char *dir, int msgnum)
07624 {
07625 char fn[PATH_MAX];
07626 char full_fn[PATH_MAX];
07627 char intro[PATH_MAX] = {0,};
07628
07629 if (msgnum > -1) {
07630 make_file(fn, sizeof(fn), dir, msgnum);
07631 snprintf(intro, sizeof(intro), "%sintro", fn);
07632 } else
07633 ast_copy_string(fn, dir, sizeof(fn));
07634
07635 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07636 ast_filedelete(fn, NULL);
07637 if (!ast_strlen_zero(intro)) {
07638 ast_filedelete(intro, NULL);
07639 }
07640 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07641 unlink(full_fn);
07642 }
07643 return 0;
07644 }
07645
07646
07647
07648 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07649 {
07650 char *file, *filename;
07651 char *attachment;
07652 char arg[10];
07653 int i;
07654 BODY* body;
07655
07656 file = strrchr(ast_strdupa(dir), '/');
07657 if (file) {
07658 *file++ = '\0';
07659 } else {
07660 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07661 return -1;
07662 }
07663
07664 ast_mutex_lock(&vms->lock);
07665 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07666 mail_fetchstructure(vms->mailstream, i + 1, &body);
07667
07668 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07669 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07670 } else {
07671 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07672 ast_mutex_unlock(&vms->lock);
07673 return -1;
07674 }
07675 filename = strsep(&attachment, ".");
07676 if (!strcmp(filename, file)) {
07677 sprintf(arg, "%d", i + 1);
07678 mail_setflag(vms->mailstream, arg, "\\DELETED");
07679 }
07680 }
07681 mail_expunge(vms->mailstream);
07682 ast_mutex_unlock(&vms->lock);
07683 return 0;
07684 }
07685
07686 #elif !defined(IMAP_STORAGE)
07687 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07688 {
07689 int count_msg, last_msg;
07690
07691 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07692
07693
07694
07695
07696 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07697
07698
07699 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07700
07701
07702 count_msg = count_messages(vmu, vms->curdir);
07703 if (count_msg < 0) {
07704 return count_msg;
07705 } else {
07706 vms->lastmsg = count_msg - 1;
07707 }
07708
07709 if (vm_allocate_dh(vms, vmu, count_msg)) {
07710 return -1;
07711 }
07712
07713
07714
07715
07716
07717
07718
07719
07720 if (vm_lock_path(vms->curdir)) {
07721 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07722 return ERROR_LOCK_PATH;
07723 }
07724
07725
07726 last_msg = last_message_index(vmu, vms->curdir);
07727 ast_unlock_path(vms->curdir);
07728
07729 if (last_msg < -1) {
07730 return last_msg;
07731 } else if (vms->lastmsg != last_msg) {
07732 ast_log(LOG_NOTICE, "Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
07733 }
07734
07735 return 0;
07736 }
07737 #endif
07738
07739 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07740 {
07741 int x = 0;
07742 #ifndef IMAP_STORAGE
07743 int res = 0, nummsg;
07744 char fn2[PATH_MAX];
07745 #endif
07746
07747 if (vms->lastmsg <= -1) {
07748 goto done;
07749 }
07750
07751 vms->curmsg = -1;
07752 #ifndef IMAP_STORAGE
07753
07754 if (vm_lock_path(vms->curdir)) {
07755 return ERROR_LOCK_PATH;
07756 }
07757
07758
07759 for (x = 0; x < vms->lastmsg + 1; x++) {
07760 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07761
07762 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07763 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07764 break;
07765 }
07766 vms->curmsg++;
07767 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07768 if (strcmp(vms->fn, fn2)) {
07769 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07770 }
07771 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07772
07773 res = save_to_folder(vmu, vms, x, 1);
07774 if (res == ERROR_LOCK_PATH) {
07775
07776 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07777 vms->deleted[x] = 0;
07778 vms->heard[x] = 0;
07779 --x;
07780 }
07781 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07782
07783 res = save_to_folder(vmu, vms, x, 10);
07784 if (res == ERROR_LOCK_PATH) {
07785
07786 vms->deleted[x] = 0;
07787 vms->heard[x] = 0;
07788 --x;
07789 }
07790 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07791
07792
07793 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07794 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07795 DELETE(vms->curdir, x, vms->fn, vmu);
07796 }
07797 }
07798 }
07799
07800
07801 nummsg = x - 1;
07802 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07803 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07804 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
07805 DELETE(vms->curdir, x, vms->fn, vmu);
07806 }
07807 }
07808 ast_unlock_path(vms->curdir);
07809 #else
07810 if (vms->deleted) {
07811
07812
07813 for (x = vms->dh_arraysize - 1; x >= 0; x--) {
07814 if (vms->deleted[x]) {
07815 ast_debug(3, "IMAP delete of %d\n", x);
07816 DELETE(vms->curdir, x, vms->fn, vmu);
07817 }
07818 }
07819 }
07820 #endif
07821
07822 done:
07823 if (vms->deleted && vmu->maxmsg) {
07824 memset(vms->deleted, 0, vms->dh_arraysize * sizeof(int));
07825 }
07826 if (vms->heard && vmu->maxmsg) {
07827 memset(vms->heard, 0, vms->dh_arraysize * sizeof(int));
07828 }
07829
07830 return 0;
07831 }
07832
07833
07834
07835
07836
07837
07838
07839 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
07840 {
07841 int cmd;
07842 char *buf;
07843
07844 buf = alloca(strlen(box) + 2);
07845 strcpy(buf, box);
07846 strcat(buf, "s");
07847
07848 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
07849 cmd = ast_play_and_wait(chan, buf);
07850 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07851 } else {
07852 cmd = ast_play_and_wait(chan, "vm-messages");
07853 return cmd ? cmd : ast_play_and_wait(chan, box);
07854 }
07855 }
07856
07857 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
07858 {
07859 int cmd;
07860
07861 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
07862 if (!strcasecmp(box, "vm-INBOX"))
07863 cmd = ast_play_and_wait(chan, "vm-new-e");
07864 else
07865 cmd = ast_play_and_wait(chan, "vm-old-e");
07866 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07867 } else {
07868 cmd = ast_play_and_wait(chan, "vm-messages");
07869 return cmd ? cmd : ast_play_and_wait(chan, box);
07870 }
07871 }
07872
07873 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
07874 {
07875 int cmd;
07876
07877 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
07878 cmd = ast_play_and_wait(chan, "vm-messages");
07879 return cmd ? cmd : ast_play_and_wait(chan, box);
07880 } else {
07881 cmd = ast_play_and_wait(chan, box);
07882 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07883 }
07884 }
07885
07886 static int vm_play_folder_name(struct ast_channel *chan, char *box)
07887 {
07888 int cmd;
07889
07890 if ( !strncasecmp(chan->language, "it", 2) ||
07891 !strncasecmp(chan->language, "es", 2) ||
07892 !strncasecmp(chan->language, "pt", 2)) {
07893 cmd = ast_play_and_wait(chan, "vm-messages");
07894 return cmd ? cmd : ast_play_and_wait(chan, box);
07895 } else if (!strncasecmp(chan->language, "gr", 2)) {
07896 return vm_play_folder_name_gr(chan, box);
07897 } else if (!strncasecmp(chan->language, "he", 2)) {
07898 return ast_play_and_wait(chan, box);
07899 } else if (!strncasecmp(chan->language, "pl", 2)) {
07900 return vm_play_folder_name_pl(chan, box);
07901 } else if (!strncasecmp(chan->language, "ua", 2)) {
07902 return vm_play_folder_name_ua(chan, box);
07903 } else if (!strncasecmp(chan->language, "vi", 2)) {
07904 return ast_play_and_wait(chan, box);
07905 } else {
07906 cmd = ast_play_and_wait(chan, box);
07907 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07908 }
07909 }
07910
07911
07912
07913
07914
07915
07916
07917
07918
07919
07920
07921
07922
07923 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
07924 {
07925 int res = 0;
07926
07927 if (vms->newmessages) {
07928 res = ast_play_and_wait(chan, "vm-youhave");
07929 if (!res)
07930 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
07931 if (!res) {
07932 if ((vms->newmessages == 1)) {
07933 res = ast_play_and_wait(chan, "vm-INBOX");
07934 if (!res)
07935 res = ast_play_and_wait(chan, "vm-message");
07936 } else {
07937 res = ast_play_and_wait(chan, "vm-INBOXs");
07938 if (!res)
07939 res = ast_play_and_wait(chan, "vm-messages");
07940 }
07941 }
07942 } else if (vms->oldmessages){
07943 res = ast_play_and_wait(chan, "vm-youhave");
07944 if (!res)
07945 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
07946 if ((vms->oldmessages == 1)){
07947 res = ast_play_and_wait(chan, "vm-Old");
07948 if (!res)
07949 res = ast_play_and_wait(chan, "vm-message");
07950 } else {
07951 res = ast_play_and_wait(chan, "vm-Olds");
07952 if (!res)
07953 res = ast_play_and_wait(chan, "vm-messages");
07954 }
07955 } else if (!vms->oldmessages && !vms->newmessages)
07956 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
07957 return res;
07958 }
07959
07960
07961
07962
07963
07964
07965
07966
07967
07968
07969
07970
07971
07972
07973
07974
07975
07976
07977
07978
07979
07980
07981
07982
07983
07984
07985
07986
07987
07988
07989
07990
07991
07992
07993
07994
07995
07996
07997
07998
07999
08000
08001
08002
08003
08004
08005
08006
08007
08008
08009
08010
08011
08012
08013
08014
08015
08016
08017 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08018 {
08019 int res;
08020 int lastnum = 0;
08021
08022 res = ast_play_and_wait(chan, "vm-youhave");
08023
08024 if (!res && vms->newmessages) {
08025 lastnum = vms->newmessages;
08026
08027 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08028 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08029 }
08030
08031 if (!res && vms->oldmessages) {
08032 res = ast_play_and_wait(chan, "vm-and");
08033 }
08034 }
08035
08036 if (!res && vms->oldmessages) {
08037 lastnum = vms->oldmessages;
08038
08039 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08040 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08041 }
08042 }
08043
08044 if (!res) {
08045 if (lastnum == 0) {
08046 res = ast_play_and_wait(chan, "vm-no");
08047 }
08048 if (!res) {
08049 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08050 }
08051 }
08052
08053 return res;
08054 }
08055
08056
08057 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08058 {
08059 int res = 0;
08060
08061
08062 if (!res) {
08063 if ((vms->newmessages) || (vms->oldmessages)) {
08064 res = ast_play_and_wait(chan, "vm-youhave");
08065 }
08066
08067
08068
08069
08070
08071 if (vms->newmessages) {
08072 if (!res) {
08073 if (vms->newmessages == 1) {
08074 res = ast_play_and_wait(chan, "vm-INBOX1");
08075 } else {
08076 if (vms->newmessages == 2) {
08077 res = ast_play_and_wait(chan, "vm-shtei");
08078 } else {
08079 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08080 }
08081 res = ast_play_and_wait(chan, "vm-INBOX");
08082 }
08083 }
08084 if (vms->oldmessages && !res) {
08085 res = ast_play_and_wait(chan, "vm-and");
08086 if (vms->oldmessages == 1) {
08087 res = ast_play_and_wait(chan, "vm-Old1");
08088 } else {
08089 if (vms->oldmessages == 2) {
08090 res = ast_play_and_wait(chan, "vm-shtei");
08091 } else {
08092 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08093 }
08094 res = ast_play_and_wait(chan, "vm-Old");
08095 }
08096 }
08097 }
08098 if (!res && vms->oldmessages && !vms->newmessages) {
08099 if (!res) {
08100 if (vms->oldmessages == 1) {
08101 res = ast_play_and_wait(chan, "vm-Old1");
08102 } else {
08103 if (vms->oldmessages == 2) {
08104 res = ast_play_and_wait(chan, "vm-shtei");
08105 } else {
08106 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08107 }
08108 res = ast_play_and_wait(chan, "vm-Old");
08109 }
08110 }
08111 }
08112 if (!res) {
08113 if (!vms->oldmessages && !vms->newmessages) {
08114 if (!res) {
08115 res = ast_play_and_wait(chan, "vm-nomessages");
08116 }
08117 }
08118 }
08119 }
08120 return res;
08121 }
08122
08123
08124 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08125 {
08126 int res;
08127
08128
08129 res = ast_play_and_wait(chan, "vm-youhave");
08130 if (!res) {
08131 if (vms->urgentmessages) {
08132 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08133 if (!res)
08134 res = ast_play_and_wait(chan, "vm-Urgent");
08135 if ((vms->oldmessages || vms->newmessages) && !res) {
08136 res = ast_play_and_wait(chan, "vm-and");
08137 } else if (!res) {
08138 if ((vms->urgentmessages == 1))
08139 res = ast_play_and_wait(chan, "vm-message");
08140 else
08141 res = ast_play_and_wait(chan, "vm-messages");
08142 }
08143 }
08144 if (vms->newmessages) {
08145 res = say_and_wait(chan, vms->newmessages, chan->language);
08146 if (!res)
08147 res = ast_play_and_wait(chan, "vm-INBOX");
08148 if (vms->oldmessages && !res)
08149 res = ast_play_and_wait(chan, "vm-and");
08150 else if (!res) {
08151 if ((vms->newmessages == 1))
08152 res = ast_play_and_wait(chan, "vm-message");
08153 else
08154 res = ast_play_and_wait(chan, "vm-messages");
08155 }
08156
08157 }
08158 if (!res && vms->oldmessages) {
08159 res = say_and_wait(chan, vms->oldmessages, chan->language);
08160 if (!res)
08161 res = ast_play_and_wait(chan, "vm-Old");
08162 if (!res) {
08163 if (vms->oldmessages == 1)
08164 res = ast_play_and_wait(chan, "vm-message");
08165 else
08166 res = ast_play_and_wait(chan, "vm-messages");
08167 }
08168 }
08169 if (!res) {
08170 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08171 res = ast_play_and_wait(chan, "vm-no");
08172 if (!res)
08173 res = ast_play_and_wait(chan, "vm-messages");
08174 }
08175 }
08176 }
08177 return res;
08178 }
08179
08180
08181 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08182 {
08183
08184 int res;
08185 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08186 res = ast_play_and_wait(chan, "vm-no") ||
08187 ast_play_and_wait(chan, "vm-message");
08188 else
08189 res = ast_play_and_wait(chan, "vm-youhave");
08190 if (!res && vms->newmessages) {
08191 res = (vms->newmessages == 1) ?
08192 ast_play_and_wait(chan, "digits/un") ||
08193 ast_play_and_wait(chan, "vm-nuovo") ||
08194 ast_play_and_wait(chan, "vm-message") :
08195
08196 say_and_wait(chan, vms->newmessages, chan->language) ||
08197 ast_play_and_wait(chan, "vm-nuovi") ||
08198 ast_play_and_wait(chan, "vm-messages");
08199 if (!res && vms->oldmessages)
08200 res = ast_play_and_wait(chan, "vm-and");
08201 }
08202 if (!res && vms->oldmessages) {
08203 res = (vms->oldmessages == 1) ?
08204 ast_play_and_wait(chan, "digits/un") ||
08205 ast_play_and_wait(chan, "vm-vecchio") ||
08206 ast_play_and_wait(chan, "vm-message") :
08207
08208 say_and_wait(chan, vms->oldmessages, chan->language) ||
08209 ast_play_and_wait(chan, "vm-vecchi") ||
08210 ast_play_and_wait(chan, "vm-messages");
08211 }
08212 return res;
08213 }
08214
08215
08216 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08217 {
08218
08219 int res;
08220 div_t num;
08221
08222 if (!vms->oldmessages && !vms->newmessages) {
08223 res = ast_play_and_wait(chan, "vm-no");
08224 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08225 return res;
08226 } else {
08227 res = ast_play_and_wait(chan, "vm-youhave");
08228 }
08229
08230 if (vms->newmessages) {
08231 num = div(vms->newmessages, 10);
08232 if (vms->newmessages == 1) {
08233 res = ast_play_and_wait(chan, "digits/1-a");
08234 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08235 res = res ? res : ast_play_and_wait(chan, "vm-message");
08236 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08237 if (num.rem == 2) {
08238 if (!num.quot) {
08239 res = ast_play_and_wait(chan, "digits/2-ie");
08240 } else {
08241 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08242 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08243 }
08244 } else {
08245 res = say_and_wait(chan, vms->newmessages, chan->language);
08246 }
08247 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08248 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08249 } else {
08250 res = say_and_wait(chan, vms->newmessages, chan->language);
08251 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08252 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08253 }
08254 if (!res && vms->oldmessages)
08255 res = ast_play_and_wait(chan, "vm-and");
08256 }
08257 if (!res && vms->oldmessages) {
08258 num = div(vms->oldmessages, 10);
08259 if (vms->oldmessages == 1) {
08260 res = ast_play_and_wait(chan, "digits/1-a");
08261 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08262 res = res ? res : ast_play_and_wait(chan, "vm-message");
08263 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08264 if (num.rem == 2) {
08265 if (!num.quot) {
08266 res = ast_play_and_wait(chan, "digits/2-ie");
08267 } else {
08268 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08269 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08270 }
08271 } else {
08272 res = say_and_wait(chan, vms->oldmessages, chan->language);
08273 }
08274 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08275 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08276 } else {
08277 res = say_and_wait(chan, vms->oldmessages, chan->language);
08278 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08279 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08280 }
08281 }
08282
08283 return res;
08284 }
08285
08286
08287 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08288 {
08289
08290 int res;
08291
08292 res = ast_play_and_wait(chan, "vm-youhave");
08293 if (res)
08294 return res;
08295
08296 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08297 res = ast_play_and_wait(chan, "vm-no");
08298 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08299 return res;
08300 }
08301
08302 if (vms->newmessages) {
08303 if ((vms->newmessages == 1)) {
08304 res = ast_play_and_wait(chan, "digits/ett");
08305 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08306 res = res ? res : ast_play_and_wait(chan, "vm-message");
08307 } else {
08308 res = say_and_wait(chan, vms->newmessages, chan->language);
08309 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08310 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08311 }
08312 if (!res && vms->oldmessages)
08313 res = ast_play_and_wait(chan, "vm-and");
08314 }
08315 if (!res && vms->oldmessages) {
08316 if (vms->oldmessages == 1) {
08317 res = ast_play_and_wait(chan, "digits/ett");
08318 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08319 res = res ? res : ast_play_and_wait(chan, "vm-message");
08320 } else {
08321 res = say_and_wait(chan, vms->oldmessages, chan->language);
08322 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08323 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08324 }
08325 }
08326
08327 return res;
08328 }
08329
08330
08331 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08332 {
08333
08334 int res;
08335
08336 res = ast_play_and_wait(chan, "vm-youhave");
08337 if (res)
08338 return res;
08339
08340 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08341 res = ast_play_and_wait(chan, "vm-no");
08342 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08343 return res;
08344 }
08345
08346 if (vms->newmessages) {
08347 if ((vms->newmessages == 1)) {
08348 res = ast_play_and_wait(chan, "digits/1");
08349 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08350 res = res ? res : ast_play_and_wait(chan, "vm-message");
08351 } else {
08352 res = say_and_wait(chan, vms->newmessages, chan->language);
08353 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08354 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08355 }
08356 if (!res && vms->oldmessages)
08357 res = ast_play_and_wait(chan, "vm-and");
08358 }
08359 if (!res && vms->oldmessages) {
08360 if (vms->oldmessages == 1) {
08361 res = ast_play_and_wait(chan, "digits/1");
08362 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08363 res = res ? res : ast_play_and_wait(chan, "vm-message");
08364 } else {
08365 res = say_and_wait(chan, vms->oldmessages, chan->language);
08366 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08367 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08368 }
08369 }
08370
08371 return res;
08372 }
08373
08374
08375 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08376 {
08377
08378 int res;
08379 res = ast_play_and_wait(chan, "vm-youhave");
08380 if (!res) {
08381 if (vms->newmessages) {
08382 if ((vms->newmessages == 1))
08383 res = ast_play_and_wait(chan, "digits/1F");
08384 else
08385 res = say_and_wait(chan, vms->newmessages, chan->language);
08386 if (!res)
08387 res = ast_play_and_wait(chan, "vm-INBOX");
08388 if (vms->oldmessages && !res)
08389 res = ast_play_and_wait(chan, "vm-and");
08390 else if (!res) {
08391 if ((vms->newmessages == 1))
08392 res = ast_play_and_wait(chan, "vm-message");
08393 else
08394 res = ast_play_and_wait(chan, "vm-messages");
08395 }
08396
08397 }
08398 if (!res && vms->oldmessages) {
08399 if (vms->oldmessages == 1)
08400 res = ast_play_and_wait(chan, "digits/1F");
08401 else
08402 res = say_and_wait(chan, vms->oldmessages, chan->language);
08403 if (!res)
08404 res = ast_play_and_wait(chan, "vm-Old");
08405 if (!res) {
08406 if (vms->oldmessages == 1)
08407 res = ast_play_and_wait(chan, "vm-message");
08408 else
08409 res = ast_play_and_wait(chan, "vm-messages");
08410 }
08411 }
08412 if (!res) {
08413 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08414 res = ast_play_and_wait(chan, "vm-no");
08415 if (!res)
08416 res = ast_play_and_wait(chan, "vm-messages");
08417 }
08418 }
08419 }
08420 return res;
08421 }
08422
08423
08424 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08425 {
08426
08427 int res;
08428 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08429 res = ast_play_and_wait(chan, "vm-youhaveno");
08430 if (!res)
08431 res = ast_play_and_wait(chan, "vm-messages");
08432 } else {
08433 res = ast_play_and_wait(chan, "vm-youhave");
08434 }
08435 if (!res) {
08436 if (vms->newmessages) {
08437 if (!res) {
08438 if ((vms->newmessages == 1)) {
08439 res = ast_play_and_wait(chan, "digits/1M");
08440 if (!res)
08441 res = ast_play_and_wait(chan, "vm-message");
08442 if (!res)
08443 res = ast_play_and_wait(chan, "vm-INBOXs");
08444 } else {
08445 res = say_and_wait(chan, vms->newmessages, chan->language);
08446 if (!res)
08447 res = ast_play_and_wait(chan, "vm-messages");
08448 if (!res)
08449 res = ast_play_and_wait(chan, "vm-INBOX");
08450 }
08451 }
08452 if (vms->oldmessages && !res)
08453 res = ast_play_and_wait(chan, "vm-and");
08454 }
08455 if (vms->oldmessages) {
08456 if (!res) {
08457 if (vms->oldmessages == 1) {
08458 res = ast_play_and_wait(chan, "digits/1M");
08459 if (!res)
08460 res = ast_play_and_wait(chan, "vm-message");
08461 if (!res)
08462 res = ast_play_and_wait(chan, "vm-Olds");
08463 } else {
08464 res = say_and_wait(chan, vms->oldmessages, chan->language);
08465 if (!res)
08466 res = ast_play_and_wait(chan, "vm-messages");
08467 if (!res)
08468 res = ast_play_and_wait(chan, "vm-Old");
08469 }
08470 }
08471 }
08472 }
08473 return res;
08474 }
08475
08476
08477 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08478
08479 int res;
08480 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08481 res = ast_play_and_wait(chan, "vm-nomessages");
08482 return res;
08483 } else {
08484 res = ast_play_and_wait(chan, "vm-youhave");
08485 }
08486 if (vms->newmessages) {
08487 if (!res)
08488 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08489 if ((vms->newmessages == 1)) {
08490 if (!res)
08491 res = ast_play_and_wait(chan, "vm-message");
08492 if (!res)
08493 res = ast_play_and_wait(chan, "vm-INBOXs");
08494 } else {
08495 if (!res)
08496 res = ast_play_and_wait(chan, "vm-messages");
08497 if (!res)
08498 res = ast_play_and_wait(chan, "vm-INBOX");
08499 }
08500 if (vms->oldmessages && !res)
08501 res = ast_play_and_wait(chan, "vm-and");
08502 }
08503 if (vms->oldmessages) {
08504 if (!res)
08505 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08506 if (vms->oldmessages == 1) {
08507 if (!res)
08508 res = ast_play_and_wait(chan, "vm-message");
08509 if (!res)
08510 res = ast_play_and_wait(chan, "vm-Olds");
08511 } else {
08512 if (!res)
08513 res = ast_play_and_wait(chan, "vm-messages");
08514 if (!res)
08515 res = ast_play_and_wait(chan, "vm-Old");
08516 }
08517 }
08518 return res;
08519 }
08520
08521
08522 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08523 {
08524
08525 int res;
08526 res = ast_play_and_wait(chan, "vm-youhave");
08527 if (!res) {
08528 if (vms->newmessages) {
08529 res = say_and_wait(chan, vms->newmessages, chan->language);
08530 if (!res)
08531 res = ast_play_and_wait(chan, "vm-INBOX");
08532 if (vms->oldmessages && !res)
08533 res = ast_play_and_wait(chan, "vm-and");
08534 else if (!res) {
08535 if ((vms->newmessages == 1))
08536 res = ast_play_and_wait(chan, "vm-message");
08537 else
08538 res = ast_play_and_wait(chan, "vm-messages");
08539 }
08540
08541 }
08542 if (!res && vms->oldmessages) {
08543 res = say_and_wait(chan, vms->oldmessages, chan->language);
08544 if (!res)
08545 res = ast_play_and_wait(chan, "vm-Old");
08546 if (!res) {
08547 if (vms->oldmessages == 1)
08548 res = ast_play_and_wait(chan, "vm-message");
08549 else
08550 res = ast_play_and_wait(chan, "vm-messages");
08551 }
08552 }
08553 if (!res) {
08554 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08555 res = ast_play_and_wait(chan, "vm-no");
08556 if (!res)
08557 res = ast_play_and_wait(chan, "vm-messages");
08558 }
08559 }
08560 }
08561 return res;
08562 }
08563
08564
08565 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08566 {
08567
08568 int res;
08569 res = ast_play_and_wait(chan, "vm-youhave");
08570 if (!res) {
08571 if (vms->newmessages) {
08572 res = say_and_wait(chan, vms->newmessages, chan->language);
08573 if (!res) {
08574 if (vms->newmessages == 1)
08575 res = ast_play_and_wait(chan, "vm-INBOXs");
08576 else
08577 res = ast_play_and_wait(chan, "vm-INBOX");
08578 }
08579 if (vms->oldmessages && !res)
08580 res = ast_play_and_wait(chan, "vm-and");
08581 else if (!res) {
08582 if ((vms->newmessages == 1))
08583 res = ast_play_and_wait(chan, "vm-message");
08584 else
08585 res = ast_play_and_wait(chan, "vm-messages");
08586 }
08587
08588 }
08589 if (!res && vms->oldmessages) {
08590 res = say_and_wait(chan, vms->oldmessages, chan->language);
08591 if (!res) {
08592 if (vms->oldmessages == 1)
08593 res = ast_play_and_wait(chan, "vm-Olds");
08594 else
08595 res = ast_play_and_wait(chan, "vm-Old");
08596 }
08597 if (!res) {
08598 if (vms->oldmessages == 1)
08599 res = ast_play_and_wait(chan, "vm-message");
08600 else
08601 res = ast_play_and_wait(chan, "vm-messages");
08602 }
08603 }
08604 if (!res) {
08605 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08606 res = ast_play_and_wait(chan, "vm-no");
08607 if (!res)
08608 res = ast_play_and_wait(chan, "vm-messages");
08609 }
08610 }
08611 }
08612 return res;
08613 }
08614
08615
08616 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08617 {
08618
08619 int res;
08620 res = ast_play_and_wait(chan, "vm-youhave");
08621 if (!res) {
08622 if (vms->newmessages) {
08623 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08624 if (!res) {
08625 if ((vms->newmessages == 1)) {
08626 res = ast_play_and_wait(chan, "vm-message");
08627 if (!res)
08628 res = ast_play_and_wait(chan, "vm-INBOXs");
08629 } else {
08630 res = ast_play_and_wait(chan, "vm-messages");
08631 if (!res)
08632 res = ast_play_and_wait(chan, "vm-INBOX");
08633 }
08634 }
08635 if (vms->oldmessages && !res)
08636 res = ast_play_and_wait(chan, "vm-and");
08637 }
08638 if (!res && vms->oldmessages) {
08639 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08640 if (!res) {
08641 if (vms->oldmessages == 1) {
08642 res = ast_play_and_wait(chan, "vm-message");
08643 if (!res)
08644 res = ast_play_and_wait(chan, "vm-Olds");
08645 } else {
08646 res = ast_play_and_wait(chan, "vm-messages");
08647 if (!res)
08648 res = ast_play_and_wait(chan, "vm-Old");
08649 }
08650 }
08651 }
08652 if (!res) {
08653 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08654 res = ast_play_and_wait(chan, "vm-no");
08655 if (!res)
08656 res = ast_play_and_wait(chan, "vm-messages");
08657 }
08658 }
08659 }
08660 return res;
08661 }
08662
08663
08664
08665
08666
08667
08668
08669
08670
08671
08672
08673
08674
08675
08676
08677
08678
08679 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08680 {
08681 int res;
08682 res = ast_play_and_wait(chan, "vm-youhave");
08683 if (!res) {
08684 if (vms->newmessages) {
08685 if (vms->newmessages == 1) {
08686 res = ast_play_and_wait(chan, "digits/jednu");
08687 } else {
08688 res = say_and_wait(chan, vms->newmessages, chan->language);
08689 }
08690 if (!res) {
08691 if ((vms->newmessages == 1))
08692 res = ast_play_and_wait(chan, "vm-novou");
08693 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08694 res = ast_play_and_wait(chan, "vm-nove");
08695 if (vms->newmessages > 4)
08696 res = ast_play_and_wait(chan, "vm-novych");
08697 }
08698 if (vms->oldmessages && !res)
08699 res = ast_play_and_wait(chan, "vm-and");
08700 else if (!res) {
08701 if ((vms->newmessages == 1))
08702 res = ast_play_and_wait(chan, "vm-zpravu");
08703 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08704 res = ast_play_and_wait(chan, "vm-zpravy");
08705 if (vms->newmessages > 4)
08706 res = ast_play_and_wait(chan, "vm-zprav");
08707 }
08708 }
08709 if (!res && vms->oldmessages) {
08710 res = say_and_wait(chan, vms->oldmessages, chan->language);
08711 if (!res) {
08712 if ((vms->oldmessages == 1))
08713 res = ast_play_and_wait(chan, "vm-starou");
08714 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08715 res = ast_play_and_wait(chan, "vm-stare");
08716 if (vms->oldmessages > 4)
08717 res = ast_play_and_wait(chan, "vm-starych");
08718 }
08719 if (!res) {
08720 if ((vms->oldmessages == 1))
08721 res = ast_play_and_wait(chan, "vm-zpravu");
08722 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08723 res = ast_play_and_wait(chan, "vm-zpravy");
08724 if (vms->oldmessages > 4)
08725 res = ast_play_and_wait(chan, "vm-zprav");
08726 }
08727 }
08728 if (!res) {
08729 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08730 res = ast_play_and_wait(chan, "vm-no");
08731 if (!res)
08732 res = ast_play_and_wait(chan, "vm-zpravy");
08733 }
08734 }
08735 }
08736 return res;
08737 }
08738
08739
08740 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08741 {
08742 int res;
08743
08744 res = ast_play_and_wait(chan, "vm-you");
08745
08746 if (!res && vms->newmessages) {
08747 res = ast_play_and_wait(chan, "vm-have");
08748 if (!res)
08749 res = say_and_wait(chan, vms->newmessages, chan->language);
08750 if (!res)
08751 res = ast_play_and_wait(chan, "vm-tong");
08752 if (!res)
08753 res = ast_play_and_wait(chan, "vm-INBOX");
08754 if (vms->oldmessages && !res)
08755 res = ast_play_and_wait(chan, "vm-and");
08756 else if (!res)
08757 res = ast_play_and_wait(chan, "vm-messages");
08758 }
08759 if (!res && vms->oldmessages) {
08760 res = ast_play_and_wait(chan, "vm-have");
08761 if (!res)
08762 res = say_and_wait(chan, vms->oldmessages, chan->language);
08763 if (!res)
08764 res = ast_play_and_wait(chan, "vm-tong");
08765 if (!res)
08766 res = ast_play_and_wait(chan, "vm-Old");
08767 if (!res)
08768 res = ast_play_and_wait(chan, "vm-messages");
08769 }
08770 if (!res && !vms->oldmessages && !vms->newmessages) {
08771 res = ast_play_and_wait(chan, "vm-haveno");
08772 if (!res)
08773 res = ast_play_and_wait(chan, "vm-messages");
08774 }
08775 return res;
08776 }
08777
08778
08779 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
08780 {
08781 int res;
08782
08783
08784 res = ast_play_and_wait(chan, "vm-youhave");
08785 if (!res) {
08786 if (vms->newmessages) {
08787 res = say_and_wait(chan, vms->newmessages, chan->language);
08788 if (!res)
08789 res = ast_play_and_wait(chan, "vm-INBOX");
08790 if (vms->oldmessages && !res)
08791 res = ast_play_and_wait(chan, "vm-and");
08792 }
08793 if (!res && vms->oldmessages) {
08794 res = say_and_wait(chan, vms->oldmessages, chan->language);
08795 if (!res)
08796 res = ast_play_and_wait(chan, "vm-Old");
08797 }
08798 if (!res) {
08799 if (!vms->oldmessages && !vms->newmessages) {
08800 res = ast_play_and_wait(chan, "vm-no");
08801 if (!res)
08802 res = ast_play_and_wait(chan, "vm-message");
08803 }
08804 }
08805 }
08806 return res;
08807 }
08808
08809 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08810 {
08811 char prefile[256];
08812
08813
08814 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08815 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08816 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08817 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08818 ast_play_and_wait(chan, "vm-tempgreetactive");
08819 }
08820 DISPOSE(prefile, -1);
08821 }
08822
08823
08824 if (0) {
08825 return 0;
08826 } else if (!strncasecmp(chan->language, "cs", 2)) {
08827 return vm_intro_cs(chan, vms);
08828 } else if (!strncasecmp(chan->language, "cz", 2)) {
08829 static int deprecation_warning = 0;
08830 if (deprecation_warning++ % 10 == 0) {
08831 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
08832 }
08833 return vm_intro_cs(chan, vms);
08834 } else if (!strncasecmp(chan->language, "de", 2)) {
08835 return vm_intro_de(chan, vms);
08836 } else if (!strncasecmp(chan->language, "es", 2)) {
08837 return vm_intro_es(chan, vms);
08838 } else if (!strncasecmp(chan->language, "fr", 2)) {
08839 return vm_intro_fr(chan, vms);
08840 } else if (!strncasecmp(chan->language, "gr", 2)) {
08841 return vm_intro_gr(chan, vms);
08842 } else if (!strncasecmp(chan->language, "he", 2)) {
08843 return vm_intro_he(chan, vms);
08844 } else if (!strncasecmp(chan->language, "it", 2)) {
08845 return vm_intro_it(chan, vms);
08846 } else if (!strncasecmp(chan->language, "nl", 2)) {
08847 return vm_intro_nl(chan, vms);
08848 } else if (!strncasecmp(chan->language, "no", 2)) {
08849 return vm_intro_no(chan, vms);
08850 } else if (!strncasecmp(chan->language, "pl", 2)) {
08851 return vm_intro_pl(chan, vms);
08852 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
08853 return vm_intro_pt_BR(chan, vms);
08854 } else if (!strncasecmp(chan->language, "pt", 2)) {
08855 return vm_intro_pt(chan, vms);
08856 } else if (!strncasecmp(chan->language, "ru", 2)) {
08857 return vm_intro_multilang(chan, vms, "n");
08858 } else if (!strncasecmp(chan->language, "se", 2)) {
08859 return vm_intro_se(chan, vms);
08860 } else if (!strncasecmp(chan->language, "ua", 2)) {
08861 return vm_intro_multilang(chan, vms, "n");
08862 } else if (!strncasecmp(chan->language, "vi", 2)) {
08863 return vm_intro_vi(chan, vms);
08864 } else if (!strncasecmp(chan->language, "zh", 2)) {
08865 return vm_intro_zh(chan, vms);
08866 } else {
08867 return vm_intro_en(chan, vms);
08868 }
08869 }
08870
08871 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08872 {
08873 int res = 0;
08874
08875 while (!res) {
08876 if (vms->starting) {
08877 if (vms->lastmsg > -1) {
08878 if (skipadvanced)
08879 res = ast_play_and_wait(chan, "vm-onefor-full");
08880 else
08881 res = ast_play_and_wait(chan, "vm-onefor");
08882 if (!res)
08883 res = vm_play_folder_name(chan, vms->vmbox);
08884 }
08885 if (!res) {
08886 if (skipadvanced)
08887 res = ast_play_and_wait(chan, "vm-opts-full");
08888 else
08889 res = ast_play_and_wait(chan, "vm-opts");
08890 }
08891 } else {
08892
08893 if (skipadvanced) {
08894 res = ast_play_and_wait(chan, "vm-onefor-full");
08895 if (!res)
08896 res = vm_play_folder_name(chan, vms->vmbox);
08897 res = ast_play_and_wait(chan, "vm-opts-full");
08898 }
08899
08900
08901
08902
08903
08904
08905 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
08906 res = ast_play_and_wait(chan, "vm-prev");
08907 }
08908 if (!res && !skipadvanced)
08909 res = ast_play_and_wait(chan, "vm-advopts");
08910 if (!res)
08911 res = ast_play_and_wait(chan, "vm-repeat");
08912
08913
08914
08915
08916
08917
08918 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
08919 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
08920 res = ast_play_and_wait(chan, "vm-next");
08921 }
08922 if (!res) {
08923 if (!vms->deleted[vms->curmsg])
08924 res = ast_play_and_wait(chan, "vm-delete");
08925 else
08926 res = ast_play_and_wait(chan, "vm-undelete");
08927 if (!res)
08928 res = ast_play_and_wait(chan, "vm-toforward");
08929 if (!res)
08930 res = ast_play_and_wait(chan, "vm-savemessage");
08931 }
08932 }
08933 if (!res) {
08934 res = ast_play_and_wait(chan, "vm-helpexit");
08935 }
08936 if (!res)
08937 res = ast_waitfordigit(chan, 6000);
08938 if (!res) {
08939 vms->repeats++;
08940 if (vms->repeats > 2) {
08941 res = 't';
08942 }
08943 }
08944 }
08945 return res;
08946 }
08947
08948 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08949 {
08950 int res = 0;
08951
08952 while (!res) {
08953 if (vms->lastmsg > -1) {
08954 res = ast_play_and_wait(chan, "vm-listen");
08955 if (!res)
08956 res = vm_play_folder_name(chan, vms->vmbox);
08957 if (!res)
08958 res = ast_play_and_wait(chan, "press");
08959 if (!res)
08960 res = ast_play_and_wait(chan, "digits/1");
08961 }
08962 if (!res)
08963 res = ast_play_and_wait(chan, "vm-opts");
08964 if (!res) {
08965 vms->starting = 0;
08966 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08967 }
08968 }
08969 return res;
08970 }
08971
08972 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08973 {
08974 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
08975 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
08976 } else {
08977 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08978 }
08979 }
08980
08981
08982 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08983 {
08984 int cmd = 0;
08985 int duration = 0;
08986 int tries = 0;
08987 char newpassword[80] = "";
08988 char newpassword2[80] = "";
08989 char prefile[PATH_MAX] = "";
08990 unsigned char buf[256];
08991 int bytes = 0;
08992
08993 if (ast_adsi_available(chan)) {
08994 bytes += adsi_logo(buf + bytes);
08995 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
08996 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08997 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08998 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08999 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09000 }
09001
09002
09003
09004 for (;;) {
09005 newpassword[1] = '\0';
09006 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09007 if (cmd == '#')
09008 newpassword[0] = '\0';
09009 if (cmd < 0 || cmd == 't' || cmd == '#')
09010 return cmd;
09011 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09012 if (cmd < 0 || cmd == 't' || cmd == '#')
09013 return cmd;
09014 cmd = check_password(vmu, newpassword);
09015 if (cmd != 0) {
09016 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09017 cmd = ast_play_and_wait(chan, vm_invalid_password);
09018 } else {
09019 newpassword2[1] = '\0';
09020 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09021 if (cmd == '#')
09022 newpassword2[0] = '\0';
09023 if (cmd < 0 || cmd == 't' || cmd == '#')
09024 return cmd;
09025 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09026 if (cmd < 0 || cmd == 't' || cmd == '#')
09027 return cmd;
09028 if (!strcmp(newpassword, newpassword2))
09029 break;
09030 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09031 cmd = ast_play_and_wait(chan, vm_mismatch);
09032 }
09033 if (++tries == 3)
09034 return -1;
09035 if (cmd != 0) {
09036 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09037 }
09038 }
09039 if (pwdchange & PWDCHANGE_INTERNAL)
09040 vm_change_password(vmu, newpassword);
09041 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09042 vm_change_password_shell(vmu, newpassword);
09043
09044 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09045 cmd = ast_play_and_wait(chan, vm_passchanged);
09046
09047
09048 if (ast_test_flag(vmu, VM_FORCENAME)) {
09049 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09050 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09051 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09052 if (cmd < 0 || cmd == 't' || cmd == '#')
09053 return cmd;
09054 }
09055 }
09056
09057
09058 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09059 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09060 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09061 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09062 if (cmd < 0 || cmd == 't' || cmd == '#')
09063 return cmd;
09064 }
09065
09066 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09067 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09068 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09069 if (cmd < 0 || cmd == 't' || cmd == '#')
09070 return cmd;
09071 }
09072 }
09073
09074 return cmd;
09075 }
09076
09077 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09078 {
09079 int cmd = 0;
09080 int retries = 0;
09081 int duration = 0;
09082 char newpassword[80] = "";
09083 char newpassword2[80] = "";
09084 char prefile[PATH_MAX] = "";
09085 unsigned char buf[256];
09086 int bytes = 0;
09087
09088 if (ast_adsi_available(chan)) {
09089 bytes += adsi_logo(buf + bytes);
09090 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09091 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09092 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09093 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09094 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09095 }
09096 while ((cmd >= 0) && (cmd != 't')) {
09097 if (cmd)
09098 retries = 0;
09099 switch (cmd) {
09100 case '1':
09101 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09102 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09103 break;
09104 case '2':
09105 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09106 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09107 break;
09108 case '3':
09109 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09110 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09111 break;
09112 case '4':
09113 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09114 break;
09115 case '5':
09116 if (vmu->password[0] == '-') {
09117 cmd = ast_play_and_wait(chan, "vm-no");
09118 break;
09119 }
09120 newpassword[1] = '\0';
09121 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09122 if (cmd == '#')
09123 newpassword[0] = '\0';
09124 else {
09125 if (cmd < 0)
09126 break;
09127 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09128 break;
09129 }
09130 }
09131 cmd = check_password(vmu, newpassword);
09132 if (cmd != 0) {
09133 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09134 cmd = ast_play_and_wait(chan, vm_invalid_password);
09135 if (!cmd) {
09136 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09137 }
09138 break;
09139 }
09140 newpassword2[1] = '\0';
09141 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09142 if (cmd == '#')
09143 newpassword2[0] = '\0';
09144 else {
09145 if (cmd < 0)
09146 break;
09147
09148 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09149 break;
09150 }
09151 }
09152 if (strcmp(newpassword, newpassword2)) {
09153 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09154 cmd = ast_play_and_wait(chan, vm_mismatch);
09155 if (!cmd) {
09156 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09157 }
09158 break;
09159 }
09160 if (pwdchange & PWDCHANGE_INTERNAL)
09161 vm_change_password(vmu, newpassword);
09162 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09163 vm_change_password_shell(vmu, newpassword);
09164
09165 ast_debug(1, "User %s set password to %s of length %d\n",
09166 vms->username, newpassword, (int) strlen(newpassword));
09167 cmd = ast_play_and_wait(chan, vm_passchanged);
09168 break;
09169 case '*':
09170 cmd = 't';
09171 break;
09172 default:
09173 cmd = 0;
09174 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09175 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09176 if (ast_fileexists(prefile, NULL, NULL)) {
09177 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09178 }
09179 DISPOSE(prefile, -1);
09180 if (!cmd) {
09181 cmd = ast_play_and_wait(chan, "vm-options");
09182 }
09183 if (!cmd) {
09184 cmd = ast_waitfordigit(chan, 6000);
09185 }
09186 if (!cmd) {
09187 retries++;
09188 }
09189 if (retries > 3) {
09190 cmd = 't';
09191 }
09192 }
09193 }
09194 if (cmd == 't')
09195 cmd = 0;
09196 return cmd;
09197 }
09198
09199
09200
09201
09202
09203
09204
09205
09206
09207
09208
09209
09210
09211
09212
09213
09214
09215 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09216 {
09217 int cmd = 0;
09218 int retries = 0;
09219 int duration = 0;
09220 char prefile[PATH_MAX] = "";
09221 unsigned char buf[256];
09222 int bytes = 0;
09223
09224 if (ast_adsi_available(chan)) {
09225 bytes += adsi_logo(buf + bytes);
09226 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09227 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09228 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09229 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09230 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09231 }
09232
09233 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09234 while ((cmd >= 0) && (cmd != 't')) {
09235 if (cmd)
09236 retries = 0;
09237 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09238 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09239 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09240 cmd = 't';
09241 } else {
09242 switch (cmd) {
09243 case '1':
09244 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
09245 break;
09246 case '2':
09247 DELETE(prefile, -1, prefile, vmu);
09248 ast_play_and_wait(chan, "vm-tempremoved");
09249 cmd = 't';
09250 break;
09251 case '*':
09252 cmd = 't';
09253 break;
09254 default:
09255 cmd = ast_play_and_wait(chan,
09256 ast_fileexists(prefile, NULL, NULL) > 0 ?
09257 "vm-tempgreeting2" : "vm-tempgreeting");
09258 if (!cmd)
09259 cmd = ast_waitfordigit(chan, 6000);
09260 if (!cmd)
09261 retries++;
09262 if (retries > 3)
09263 cmd = 't';
09264 }
09265 }
09266 DISPOSE(prefile, -1);
09267 }
09268 if (cmd == 't')
09269 cmd = 0;
09270 return cmd;
09271 }
09272
09273
09274
09275
09276
09277
09278
09279
09280
09281 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09282 {
09283 int cmd = 0;
09284
09285 if (vms->lastmsg > -1) {
09286 cmd = play_message(chan, vmu, vms);
09287 } else {
09288 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09289 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09290 if (!cmd) {
09291 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09292 cmd = ast_play_and_wait(chan, vms->fn);
09293 }
09294 if (!cmd)
09295 cmd = ast_play_and_wait(chan, "vm-messages");
09296 } else {
09297 if (!cmd)
09298 cmd = ast_play_and_wait(chan, "vm-messages");
09299 if (!cmd) {
09300 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09301 cmd = ast_play_and_wait(chan, vms->fn);
09302 }
09303 }
09304 }
09305 return cmd;
09306 }
09307
09308
09309 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09310 {
09311 int cmd = 0;
09312
09313 if (vms->lastmsg > -1) {
09314 cmd = play_message(chan, vmu, vms);
09315 } else {
09316 if (!strcasecmp(vms->fn, "INBOX")) {
09317 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09318 } else {
09319 cmd = ast_play_and_wait(chan, "vm-nomessages");
09320 }
09321 }
09322 return cmd;
09323 }
09324
09325
09326
09327
09328
09329
09330
09331
09332
09333 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09334 {
09335 int cmd = 0;
09336
09337 if (vms->lastmsg > -1) {
09338 cmd = play_message(chan, vmu, vms);
09339 } else {
09340 cmd = ast_play_and_wait(chan, "vm-youhave");
09341 if (!cmd)
09342 cmd = ast_play_and_wait(chan, "vm-no");
09343 if (!cmd) {
09344 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09345 cmd = ast_play_and_wait(chan, vms->fn);
09346 }
09347 if (!cmd)
09348 cmd = ast_play_and_wait(chan, "vm-messages");
09349 }
09350 return cmd;
09351 }
09352
09353
09354
09355
09356
09357
09358
09359
09360
09361 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09362 {
09363 int cmd;
09364
09365 if (vms->lastmsg > -1) {
09366 cmd = play_message(chan, vmu, vms);
09367 } else {
09368 cmd = ast_play_and_wait(chan, "vm-no");
09369 if (!cmd)
09370 cmd = ast_play_and_wait(chan, "vm-message");
09371 if (!cmd) {
09372 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09373 cmd = ast_play_and_wait(chan, vms->fn);
09374 }
09375 }
09376 return cmd;
09377 }
09378
09379
09380
09381
09382
09383
09384
09385
09386
09387 static int vm_browse_messages_es(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-youhaveno");
09395 if (!cmd)
09396 cmd = ast_play_and_wait(chan, "vm-messages");
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_pt(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-no");
09421 if (!cmd) {
09422 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09423 cmd = ast_play_and_wait(chan, vms->fn);
09424 }
09425 if (!cmd)
09426 cmd = ast_play_and_wait(chan, "vm-messages");
09427 }
09428 return cmd;
09429 }
09430
09431
09432
09433
09434
09435
09436
09437
09438
09439 static int vm_browse_messages_zh(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-you");
09447 if (!cmd)
09448 cmd = ast_play_and_wait(chan, "vm-haveno");
09449 if (!cmd)
09450 cmd = ast_play_and_wait(chan, "vm-messages");
09451 if (!cmd) {
09452 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09453 cmd = ast_play_and_wait(chan, vms->fn);
09454 }
09455 }
09456 return cmd;
09457 }
09458
09459
09460
09461
09462
09463
09464
09465
09466
09467 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09468 {
09469 int cmd = 0;
09470
09471 if (vms->lastmsg > -1) {
09472 cmd = play_message(chan, vmu, vms);
09473 } else {
09474 cmd = ast_play_and_wait(chan, "vm-no");
09475 if (!cmd) {
09476 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09477 cmd = ast_play_and_wait(chan, vms->fn);
09478 }
09479 }
09480 return cmd;
09481 }
09482
09483
09484
09485
09486
09487
09488
09489
09490
09491
09492
09493
09494 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09495 {
09496 if (!strncasecmp(chan->language, "es", 2)) {
09497 return vm_browse_messages_es(chan, vms, vmu);
09498 } else if (!strncasecmp(chan->language, "gr", 2)) {
09499 return vm_browse_messages_gr(chan, vms, vmu);
09500 } else if (!strncasecmp(chan->language, "he", 2)) {
09501 return vm_browse_messages_he(chan, vms, vmu);
09502 } else if (!strncasecmp(chan->language, "it", 2)) {
09503 return vm_browse_messages_it(chan, vms, vmu);
09504 } else if (!strncasecmp(chan->language, "pt", 2)) {
09505 return vm_browse_messages_pt(chan, vms, vmu);
09506 } else if (!strncasecmp(chan->language, "vi", 2)) {
09507 return vm_browse_messages_vi(chan, vms, vmu);
09508 } else if (!strncasecmp(chan->language, "zh", 2)) {
09509 return vm_browse_messages_zh(chan, vms, vmu);
09510 } else {
09511 return vm_browse_messages_en(chan, vms, vmu);
09512 }
09513 }
09514
09515 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09516 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09517 int skipuser, int max_logins, int silent)
09518 {
09519 int useadsi = 0, valid = 0, logretries = 0;
09520 char password[AST_MAX_EXTENSION]="", *passptr;
09521 struct ast_vm_user vmus, *vmu = NULL;
09522
09523
09524 adsi_begin(chan, &useadsi);
09525 if (!skipuser && useadsi)
09526 adsi_login(chan);
09527 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09528 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09529 return -1;
09530 }
09531
09532
09533
09534 while (!valid && (logretries < max_logins)) {
09535
09536 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09537 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09538 return -1;
09539 }
09540 if (ast_strlen_zero(mailbox)) {
09541 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09542 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09543 } else {
09544 ast_verb(3, "Username not entered\n");
09545 return -1;
09546 }
09547 } else if (mailbox[0] == '*') {
09548
09549 if (ast_exists_extension(chan, chan->context, "a", 1,
09550 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09551 return -1;
09552 }
09553 mailbox[0] = '\0';
09554 }
09555
09556 if (useadsi)
09557 adsi_password(chan);
09558
09559 if (!ast_strlen_zero(prefix)) {
09560 char fullusername[80] = "";
09561 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09562 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09563 ast_copy_string(mailbox, fullusername, mailbox_size);
09564 }
09565
09566 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09567 vmu = find_user(&vmus, context, mailbox);
09568 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09569
09570 password[0] = '\0';
09571 } else {
09572 if (ast_streamfile(chan, vm_password, chan->language)) {
09573 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09574 return -1;
09575 }
09576 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09577 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09578 return -1;
09579 } else if (password[0] == '*') {
09580
09581 if (ast_exists_extension(chan, chan->context, "a", 1,
09582 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09583 mailbox[0] = '*';
09584 return -1;
09585 }
09586 mailbox[0] = '\0';
09587 }
09588 }
09589
09590 if (vmu) {
09591 passptr = vmu->password;
09592 if (passptr[0] == '-') passptr++;
09593 }
09594 if (vmu && !strcmp(passptr, password))
09595 valid++;
09596 else {
09597 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09598 if (!ast_strlen_zero(prefix))
09599 mailbox[0] = '\0';
09600 }
09601 logretries++;
09602 if (!valid) {
09603 if (skipuser || logretries >= max_logins) {
09604 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09605 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09606 return -1;
09607 }
09608 } else {
09609 if (useadsi)
09610 adsi_login(chan);
09611 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09612 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09613 return -1;
09614 }
09615 }
09616 if (ast_waitstream(chan, ""))
09617 return -1;
09618 }
09619 }
09620 if (!valid && (logretries >= max_logins)) {
09621 ast_stopstream(chan);
09622 ast_play_and_wait(chan, "vm-goodbye");
09623 return -1;
09624 }
09625 if (vmu && !skipuser) {
09626 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09627 }
09628 return 0;
09629 }
09630
09631 static int vm_execmain(struct ast_channel *chan, const char *data)
09632 {
09633
09634
09635
09636 int res = -1;
09637 int cmd = 0;
09638 int valid = 0;
09639 char prefixstr[80] ="";
09640 char ext_context[256]="";
09641 int box;
09642 int useadsi = 0;
09643 int skipuser = 0;
09644 struct vm_state vms;
09645 struct ast_vm_user *vmu = NULL, vmus;
09646 char *context = NULL;
09647 int silentexit = 0;
09648 struct ast_flags flags = { 0 };
09649 signed char record_gain = 0;
09650 int play_auto = 0;
09651 int play_folder = 0;
09652 int in_urgent = 0;
09653 #ifdef IMAP_STORAGE
09654 int deleted = 0;
09655 #endif
09656
09657
09658 memset(&vms, 0, sizeof(vms));
09659
09660 vms.lastmsg = -1;
09661
09662 memset(&vmus, 0, sizeof(vmus));
09663
09664 if (chan->_state != AST_STATE_UP) {
09665 ast_debug(1, "Before ast_answer\n");
09666 ast_answer(chan);
09667 }
09668
09669 if (!ast_strlen_zero(data)) {
09670 char *opts[OPT_ARG_ARRAY_SIZE];
09671 char *parse;
09672 AST_DECLARE_APP_ARGS(args,
09673 AST_APP_ARG(argv0);
09674 AST_APP_ARG(argv1);
09675 );
09676
09677 parse = ast_strdupa(data);
09678
09679 AST_STANDARD_APP_ARGS(args, parse);
09680
09681 if (args.argc == 2) {
09682 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09683 return -1;
09684 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09685 int gain;
09686 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09687 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09688 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09689 return -1;
09690 } else {
09691 record_gain = (signed char) gain;
09692 }
09693 } else {
09694 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09695 }
09696 }
09697 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09698 play_auto = 1;
09699 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09700
09701 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09702 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09703 play_folder = -1;
09704 }
09705 } else {
09706 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09707 }
09708 } else {
09709 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09710 }
09711 if (play_folder > 9 || play_folder < 0) {
09712 ast_log(AST_LOG_WARNING,
09713 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09714 opts[OPT_ARG_PLAYFOLDER]);
09715 play_folder = 0;
09716 }
09717 }
09718 } else {
09719
09720 while (*(args.argv0)) {
09721 if (*(args.argv0) == 's')
09722 ast_set_flag(&flags, OPT_SILENT);
09723 else if (*(args.argv0) == 'p')
09724 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09725 else
09726 break;
09727 (args.argv0)++;
09728 }
09729
09730 }
09731
09732 valid = ast_test_flag(&flags, OPT_SILENT);
09733
09734 if ((context = strchr(args.argv0, '@')))
09735 *context++ = '\0';
09736
09737 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09738 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09739 else
09740 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09741
09742 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09743 skipuser++;
09744 else
09745 valid = 0;
09746 }
09747
09748 if (!valid)
09749 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09750
09751 ast_debug(1, "After vm_authenticate\n");
09752
09753 if (vms.username[0] == '*') {
09754 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
09755
09756
09757 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
09758 res = 0;
09759 goto out;
09760 }
09761 }
09762
09763 if (!res) {
09764 valid = 1;
09765 if (!skipuser)
09766 vmu = &vmus;
09767 } else {
09768 res = 0;
09769 }
09770
09771
09772 adsi_begin(chan, &useadsi);
09773
09774 if (!valid) {
09775 goto out;
09776 }
09777
09778 #ifdef IMAP_STORAGE
09779 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
09780 pthread_setspecific(ts_vmstate.key, &vms);
09781
09782 vms.interactive = 1;
09783 vms.updated = 1;
09784 if (vmu)
09785 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
09786 vmstate_insert(&vms);
09787 init_vm_state(&vms);
09788 #endif
09789
09790 if (!(vms.deleted = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09791 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
09792 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09793 return -1;
09794 }
09795 if (!(vms.heard = ast_calloc(vmu->maxmsg ? vmu->maxmsg : 1, sizeof(int)))) {
09796 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
09797 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09798 return -1;
09799 }
09800
09801
09802 if (!ast_strlen_zero(vmu->language))
09803 ast_string_field_set(chan, language, vmu->language);
09804
09805
09806 ast_debug(1, "Before open_mailbox\n");
09807 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09808 if (res < 0)
09809 goto out;
09810 vms.oldmessages = vms.lastmsg + 1;
09811 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
09812
09813 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09814 if (res < 0)
09815 goto out;
09816 vms.newmessages = vms.lastmsg + 1;
09817 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
09818
09819 in_urgent = 1;
09820 res = open_mailbox(&vms, vmu, 11);
09821 if (res < 0)
09822 goto out;
09823 vms.urgentmessages = vms.lastmsg + 1;
09824 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
09825
09826
09827 if (play_auto) {
09828 if (vms.urgentmessages) {
09829 in_urgent = 1;
09830 res = open_mailbox(&vms, vmu, 11);
09831 } else {
09832 in_urgent = 0;
09833 res = open_mailbox(&vms, vmu, play_folder);
09834 }
09835 if (res < 0)
09836 goto out;
09837
09838
09839 if (vms.lastmsg == -1) {
09840 in_urgent = 0;
09841 cmd = vm_browse_messages(chan, &vms, vmu);
09842 res = 0;
09843 goto out;
09844 }
09845 } else {
09846 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
09847
09848 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09849 in_urgent = 0;
09850 play_folder = 1;
09851 if (res < 0)
09852 goto out;
09853 } else if (!vms.urgentmessages && vms.newmessages) {
09854
09855 in_urgent = 0;
09856 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09857 if (res < 0)
09858 goto out;
09859 }
09860 }
09861
09862 if (useadsi)
09863 adsi_status(chan, &vms);
09864 res = 0;
09865
09866
09867 if (!strcasecmp(vmu->mailbox, vmu->password) &&
09868 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
09869 if (ast_play_and_wait(chan, "vm-newuser") == -1)
09870 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
09871 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
09872 if ((cmd == 't') || (cmd == '#')) {
09873
09874 res = 0;
09875 goto out;
09876 } else if (cmd < 0) {
09877
09878 res = -1;
09879 goto out;
09880 }
09881 }
09882 #ifdef IMAP_STORAGE
09883 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
09884 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
09885 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
09886 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09887 }
09888 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09889 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
09890 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09891 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09892 }
09893 #endif
09894 if (play_auto) {
09895 cmd = '1';
09896 } else {
09897 cmd = vm_intro(chan, vmu, &vms);
09898 }
09899
09900 vms.repeats = 0;
09901 vms.starting = 1;
09902 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09903
09904 switch (cmd) {
09905 case '1':
09906 vms.curmsg = 0;
09907
09908 case '5':
09909 cmd = vm_browse_messages(chan, &vms, vmu);
09910 break;
09911 case '2':
09912 if (useadsi)
09913 adsi_folders(chan, 0, "Change to folder...");
09914 cmd = get_folder2(chan, "vm-changeto", 0);
09915 if (cmd == '#') {
09916 cmd = 0;
09917 } else if (cmd > 0) {
09918 cmd = cmd - '0';
09919 res = close_mailbox(&vms, vmu);
09920 if (res == ERROR_LOCK_PATH)
09921 goto out;
09922
09923 if (cmd != 11) in_urgent = 0;
09924 res = open_mailbox(&vms, vmu, cmd);
09925 if (res < 0)
09926 goto out;
09927 play_folder = cmd;
09928 cmd = 0;
09929 }
09930 if (useadsi)
09931 adsi_status2(chan, &vms);
09932
09933 if (!cmd)
09934 cmd = vm_play_folder_name(chan, vms.vmbox);
09935
09936 vms.starting = 1;
09937 break;
09938 case '3':
09939 cmd = 0;
09940 vms.repeats = 0;
09941 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09942 switch (cmd) {
09943 case '1':
09944 if (vms.lastmsg > -1 && !vms.starting) {
09945 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
09946 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09947 res = cmd;
09948 goto out;
09949 }
09950 } else
09951 cmd = ast_play_and_wait(chan, "vm-sorry");
09952 cmd = 't';
09953 break;
09954 case '2':
09955 if (!vms.starting)
09956 ast_verb(3, "Callback Requested\n");
09957 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
09958 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
09959 if (cmd == 9) {
09960 silentexit = 1;
09961 goto out;
09962 } else if (cmd == ERROR_LOCK_PATH) {
09963 res = cmd;
09964 goto out;
09965 }
09966 } else
09967 cmd = ast_play_and_wait(chan, "vm-sorry");
09968 cmd = 't';
09969 break;
09970 case '3':
09971 if (vms.lastmsg > -1 && !vms.starting) {
09972 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
09973 if (cmd == ERROR_LOCK_PATH) {
09974 res = cmd;
09975 goto out;
09976 }
09977 } else
09978 cmd = ast_play_and_wait(chan, "vm-sorry");
09979 cmd = 't';
09980 break;
09981 case '4':
09982 if (!ast_strlen_zero(vmu->dialout)) {
09983 cmd = dialout(chan, vmu, NULL, vmu->dialout);
09984 if (cmd == 9) {
09985 silentexit = 1;
09986 goto out;
09987 }
09988 } else
09989 cmd = ast_play_and_wait(chan, "vm-sorry");
09990 cmd = 't';
09991 break;
09992
09993 case '5':
09994 if (ast_test_flag(vmu, VM_SVMAIL)) {
09995 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
09996 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09997 res = cmd;
09998 goto out;
09999 }
10000 } else
10001 cmd = ast_play_and_wait(chan, "vm-sorry");
10002 cmd = 't';
10003 break;
10004
10005 case '*':
10006 cmd = 't';
10007 break;
10008
10009 default:
10010 cmd = 0;
10011 if (!vms.starting) {
10012 cmd = ast_play_and_wait(chan, "vm-toreply");
10013 }
10014 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10015 cmd = ast_play_and_wait(chan, "vm-tocallback");
10016 }
10017 if (!cmd && !vms.starting) {
10018 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10019 }
10020 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10021 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10022 }
10023 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
10024 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10025 if (!cmd)
10026 cmd = ast_play_and_wait(chan, "vm-starmain");
10027 if (!cmd)
10028 cmd = ast_waitfordigit(chan, 6000);
10029 if (!cmd)
10030 vms.repeats++;
10031 if (vms.repeats > 3)
10032 cmd = 't';
10033 }
10034 }
10035 if (cmd == 't') {
10036 cmd = 0;
10037 vms.repeats = 0;
10038 }
10039 break;
10040 case '4':
10041 if (vms.curmsg > 0) {
10042 vms.curmsg--;
10043 cmd = play_message(chan, vmu, &vms);
10044 } else {
10045
10046
10047
10048
10049 if (in_urgent == 0 && vms.urgentmessages > 0) {
10050
10051 in_urgent = 1;
10052 res = close_mailbox(&vms, vmu);
10053 if (res == ERROR_LOCK_PATH)
10054 goto out;
10055 res = open_mailbox(&vms, vmu, 11);
10056 if (res < 0)
10057 goto out;
10058 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10059 vms.curmsg = vms.lastmsg;
10060 if (vms.lastmsg < 0)
10061 cmd = ast_play_and_wait(chan, "vm-nomore");
10062 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10063 vms.curmsg = vms.lastmsg;
10064 cmd = play_message(chan, vmu, &vms);
10065 } else {
10066 cmd = ast_play_and_wait(chan, "vm-nomore");
10067 }
10068 }
10069 break;
10070 case '6':
10071 if (vms.curmsg < vms.lastmsg) {
10072 vms.curmsg++;
10073 cmd = play_message(chan, vmu, &vms);
10074 } else {
10075 if (in_urgent && vms.newmessages > 0) {
10076
10077
10078
10079
10080 in_urgent = 0;
10081 res = close_mailbox(&vms, vmu);
10082 if (res == ERROR_LOCK_PATH)
10083 goto out;
10084 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10085 if (res < 0)
10086 goto out;
10087 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10088 vms.curmsg = -1;
10089 if (vms.lastmsg < 0) {
10090 cmd = ast_play_and_wait(chan, "vm-nomore");
10091 }
10092 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10093 vms.curmsg = 0;
10094 cmd = play_message(chan, vmu, &vms);
10095 } else {
10096 cmd = ast_play_and_wait(chan, "vm-nomore");
10097 }
10098 }
10099 break;
10100 case '7':
10101 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10102 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10103 if (useadsi)
10104 adsi_delete(chan, &vms);
10105 if (vms.deleted[vms.curmsg]) {
10106 if (play_folder == 0) {
10107 if (in_urgent) {
10108 vms.urgentmessages--;
10109 } else {
10110 vms.newmessages--;
10111 }
10112 }
10113 else if (play_folder == 1)
10114 vms.oldmessages--;
10115 cmd = ast_play_and_wait(chan, "vm-deleted");
10116 } else {
10117 if (play_folder == 0) {
10118 if (in_urgent) {
10119 vms.urgentmessages++;
10120 } else {
10121 vms.newmessages++;
10122 }
10123 }
10124 else if (play_folder == 1)
10125 vms.oldmessages++;
10126 cmd = ast_play_and_wait(chan, "vm-undeleted");
10127 }
10128 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10129 if (vms.curmsg < vms.lastmsg) {
10130 vms.curmsg++;
10131 cmd = play_message(chan, vmu, &vms);
10132 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10133 vms.curmsg = 0;
10134 cmd = play_message(chan, vmu, &vms);
10135 } else {
10136
10137
10138
10139
10140 if (in_urgent == 1) {
10141
10142 in_urgent = 0;
10143 res = close_mailbox(&vms, vmu);
10144 if (res == ERROR_LOCK_PATH)
10145 goto out;
10146 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10147 if (res < 0)
10148 goto out;
10149 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10150 vms.curmsg = -1;
10151 if (vms.lastmsg < 0)
10152 cmd = ast_play_and_wait(chan, "vm-nomore");
10153 } else {
10154 cmd = ast_play_and_wait(chan, "vm-nomore");
10155 }
10156 }
10157 }
10158 } else
10159 cmd = 0;
10160 #ifdef IMAP_STORAGE
10161 deleted = 1;
10162 #endif
10163 break;
10164
10165 case '8':
10166 if (vms.lastmsg > -1) {
10167 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10168 if (cmd == ERROR_LOCK_PATH) {
10169 res = cmd;
10170 goto out;
10171 }
10172 } else {
10173
10174
10175
10176
10177 if (in_urgent == 1 && vms.newmessages > 0) {
10178
10179 in_urgent = 0;
10180 res = close_mailbox(&vms, vmu);
10181 if (res == ERROR_LOCK_PATH)
10182 goto out;
10183 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10184 if (res < 0)
10185 goto out;
10186 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10187 vms.curmsg = -1;
10188 if (vms.lastmsg < 0)
10189 cmd = ast_play_and_wait(chan, "vm-nomore");
10190 } else {
10191 cmd = ast_play_and_wait(chan, "vm-nomore");
10192 }
10193 }
10194 break;
10195 case '9':
10196 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10197
10198 cmd = 0;
10199 break;
10200 }
10201 if (useadsi)
10202 adsi_folders(chan, 1, "Save to folder...");
10203 cmd = get_folder2(chan, "vm-savefolder", 1);
10204 box = 0;
10205 if (cmd == '#') {
10206 cmd = 0;
10207 break;
10208 } else if (cmd > 0) {
10209 box = cmd = cmd - '0';
10210 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10211 if (cmd == ERROR_LOCK_PATH) {
10212 res = cmd;
10213 goto out;
10214 #ifndef IMAP_STORAGE
10215 } else if (!cmd) {
10216 vms.deleted[vms.curmsg] = 1;
10217 #endif
10218 } else {
10219 vms.deleted[vms.curmsg] = 0;
10220 vms.heard[vms.curmsg] = 0;
10221 }
10222 }
10223 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10224 if (useadsi)
10225 adsi_message(chan, &vms);
10226 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10227 if (!cmd) {
10228 cmd = ast_play_and_wait(chan, "vm-message");
10229 if (!cmd)
10230 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10231 if (!cmd)
10232 cmd = ast_play_and_wait(chan, "vm-savedto");
10233 if (!cmd)
10234 cmd = vm_play_folder_name(chan, vms.fn);
10235 } else {
10236 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10237 }
10238 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10239 if (vms.curmsg < vms.lastmsg) {
10240 vms.curmsg++;
10241 cmd = play_message(chan, vmu, &vms);
10242 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10243 vms.curmsg = 0;
10244 cmd = play_message(chan, vmu, &vms);
10245 } else {
10246
10247
10248
10249
10250 if (in_urgent == 1 && vms.newmessages > 0) {
10251
10252 in_urgent = 0;
10253 res = close_mailbox(&vms, vmu);
10254 if (res == ERROR_LOCK_PATH)
10255 goto out;
10256 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10257 if (res < 0)
10258 goto out;
10259 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10260 vms.curmsg = -1;
10261 if (vms.lastmsg < 0)
10262 cmd = ast_play_and_wait(chan, "vm-nomore");
10263 } else {
10264 cmd = ast_play_and_wait(chan, "vm-nomore");
10265 }
10266 }
10267 }
10268 break;
10269 case '*':
10270 if (!vms.starting) {
10271 cmd = ast_play_and_wait(chan, "vm-onefor");
10272 if (!strncasecmp(chan->language, "he", 2)) {
10273 cmd = ast_play_and_wait(chan, "vm-for");
10274 }
10275 if (!cmd)
10276 cmd = vm_play_folder_name(chan, vms.vmbox);
10277 if (!cmd)
10278 cmd = ast_play_and_wait(chan, "vm-opts");
10279 if (!cmd)
10280 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10281 } else
10282 cmd = 0;
10283 break;
10284 case '0':
10285 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10286 if (useadsi)
10287 adsi_status(chan, &vms);
10288 break;
10289 default:
10290 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10291 break;
10292 }
10293 }
10294 if ((cmd == 't') || (cmd == '#')) {
10295
10296 res = 0;
10297 } else {
10298
10299 res = -1;
10300 }
10301
10302 out:
10303 if (res > -1) {
10304 ast_stopstream(chan);
10305 adsi_goodbye(chan);
10306 if (valid && res != OPERATOR_EXIT) {
10307 if (silentexit)
10308 res = ast_play_and_wait(chan, "vm-dialout");
10309 else
10310 res = ast_play_and_wait(chan, "vm-goodbye");
10311 }
10312 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10313 res = 0;
10314 }
10315 if (useadsi)
10316 ast_adsi_unload_session(chan);
10317 }
10318 if (vmu)
10319 close_mailbox(&vms, vmu);
10320 if (valid) {
10321 int new = 0, old = 0, urgent = 0;
10322 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10323 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10324
10325 run_externnotify(vmu->context, vmu->mailbox, NULL);
10326 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10327 queue_mwi_event(ext_context, urgent, new, old);
10328 }
10329 #ifdef IMAP_STORAGE
10330
10331 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10332 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10333 ast_mutex_lock(&vms.lock);
10334 #ifdef HAVE_IMAP_TK2006
10335 if (LEVELUIDPLUS (vms.mailstream)) {
10336 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10337 } else
10338 #endif
10339 mail_expunge(vms.mailstream);
10340 ast_mutex_unlock(&vms.lock);
10341 }
10342
10343
10344 if (vmu) {
10345 vmstate_delete(&vms);
10346 }
10347 #endif
10348 if (vmu)
10349 free_user(vmu);
10350 if (vms.deleted)
10351 ast_free(vms.deleted);
10352 if (vms.heard)
10353 ast_free(vms.heard);
10354
10355 #ifdef IMAP_STORAGE
10356 pthread_setspecific(ts_vmstate.key, NULL);
10357 #endif
10358 return res;
10359 }
10360
10361 static int vm_exec(struct ast_channel *chan, const char *data)
10362 {
10363 int res = 0;
10364 char *tmp;
10365 struct leave_vm_options leave_options;
10366 struct ast_flags flags = { 0 };
10367 char *opts[OPT_ARG_ARRAY_SIZE];
10368 AST_DECLARE_APP_ARGS(args,
10369 AST_APP_ARG(argv0);
10370 AST_APP_ARG(argv1);
10371 );
10372
10373 memset(&leave_options, 0, sizeof(leave_options));
10374
10375 if (chan->_state != AST_STATE_UP)
10376 ast_answer(chan);
10377
10378 if (!ast_strlen_zero(data)) {
10379 tmp = ast_strdupa(data);
10380 AST_STANDARD_APP_ARGS(args, tmp);
10381 if (args.argc == 2) {
10382 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10383 return -1;
10384 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10385 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10386 int gain;
10387
10388 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10389 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10390 return -1;
10391 } else {
10392 leave_options.record_gain = (signed char) gain;
10393 }
10394 }
10395 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10396 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10397 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10398 }
10399 }
10400 } else {
10401 char temp[256];
10402 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10403 if (res < 0)
10404 return res;
10405 if (ast_strlen_zero(temp))
10406 return 0;
10407 args.argv0 = ast_strdupa(temp);
10408 }
10409
10410 res = leave_voicemail(chan, args.argv0, &leave_options);
10411 if (res == 't') {
10412 ast_play_and_wait(chan, "vm-goodbye");
10413 res = 0;
10414 }
10415
10416 if (res == OPERATOR_EXIT) {
10417 res = 0;
10418 }
10419
10420 if (res == ERROR_LOCK_PATH) {
10421 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10422 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10423 res = 0;
10424 }
10425
10426 return res;
10427 }
10428
10429 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10430 {
10431 struct ast_vm_user *vmu;
10432
10433 AST_LIST_TRAVERSE(&users, vmu, list) {
10434 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10435 if (strcasecmp(vmu->context, context)) {
10436 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10437 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10438 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10439 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10440 }
10441 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10442 return NULL;
10443 }
10444 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10445 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10446 return NULL;
10447 }
10448 }
10449
10450 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10451 return NULL;
10452
10453 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10454 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10455
10456 AST_LIST_INSERT_TAIL(&users, vmu, list);
10457
10458 return vmu;
10459 }
10460
10461 static int append_mailbox(const char *context, const char *box, const char *data)
10462 {
10463
10464 char *tmp;
10465 char *stringp;
10466 char *s;
10467 struct ast_vm_user *vmu;
10468 char *mailbox_full;
10469 int new = 0, old = 0, urgent = 0;
10470 char secretfn[PATH_MAX] = "";
10471
10472 tmp = ast_strdupa(data);
10473
10474 if (!(vmu = find_or_create(context, box)))
10475 return -1;
10476
10477 populate_defaults(vmu);
10478
10479 stringp = tmp;
10480 if ((s = strsep(&stringp, ","))) {
10481 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10482 }
10483 if (stringp && (s = strsep(&stringp, ","))) {
10484 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10485 }
10486 if (stringp && (s = strsep(&stringp, ","))) {
10487 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10488 }
10489 if (stringp && (s = strsep(&stringp, ","))) {
10490 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10491 }
10492 if (stringp && (s = strsep(&stringp, ","))) {
10493 apply_options(vmu, s);
10494 }
10495
10496 switch (vmu->passwordlocation) {
10497 case OPT_PWLOC_SPOOLDIR:
10498 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10499 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10500 }
10501
10502 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10503 strcpy(mailbox_full, box);
10504 strcat(mailbox_full, "@");
10505 strcat(mailbox_full, context);
10506
10507 inboxcount2(mailbox_full, &urgent, &new, &old);
10508 queue_mwi_event(mailbox_full, urgent, new, old);
10509
10510 return 0;
10511 }
10512
10513 AST_TEST_DEFINE(test_voicemail_vmuser)
10514 {
10515 int res = 0;
10516 struct ast_vm_user *vmu;
10517
10518 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10519 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10520 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10521 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10522 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10523 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10524 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir";
10525 #ifdef IMAP_STORAGE
10526 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10527 "imapfolder=INBOX|imapvmshareid=6000";
10528 #endif
10529
10530 switch (cmd) {
10531 case TEST_INIT:
10532 info->name = "vmuser";
10533 info->category = "/apps/app_voicemail/";
10534 info->summary = "Vmuser unit test";
10535 info->description =
10536 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10537 return AST_TEST_NOT_RUN;
10538 case TEST_EXECUTE:
10539 break;
10540 }
10541
10542 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10543 return AST_TEST_NOT_RUN;
10544 }
10545 ast_set_flag(vmu, VM_ALLOCED);
10546
10547 apply_options(vmu, options_string);
10548
10549 if (!ast_test_flag(vmu, VM_ATTACH)) {
10550 ast_test_status_update(test, "Parse failure for attach option\n");
10551 res = 1;
10552 }
10553 if (strcasecmp(vmu->attachfmt, "wav49")) {
10554 ast_test_status_update(test, "Parse failure for attachftm option\n");
10555 res = 1;
10556 }
10557 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10558 ast_test_status_update(test, "Parse failure for serveremail option\n");
10559 res = 1;
10560 }
10561 if (strcasecmp(vmu->zonetag, "central")) {
10562 ast_test_status_update(test, "Parse failure for tz option\n");
10563 res = 1;
10564 }
10565 if (!ast_test_flag(vmu, VM_DELETE)) {
10566 ast_test_status_update(test, "Parse failure for delete option\n");
10567 res = 1;
10568 }
10569 if (!ast_test_flag(vmu, VM_SAYCID)) {
10570 ast_test_status_update(test, "Parse failure for saycid option\n");
10571 res = 1;
10572 }
10573 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10574 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10575 res = 1;
10576 }
10577 if (!ast_test_flag(vmu, VM_REVIEW)) {
10578 ast_test_status_update(test, "Parse failure for review option\n");
10579 res = 1;
10580 }
10581 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10582 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10583 res = 1;
10584 }
10585 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10586 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10587 res = 1;
10588 }
10589 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10590 ast_test_status_update(test, "Parse failure for operator option\n");
10591 res = 1;
10592 }
10593 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10594 ast_test_status_update(test, "Parse failure for envelope option\n");
10595 res = 1;
10596 }
10597 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10598 ast_test_status_update(test, "Parse failure for moveheard option\n");
10599 res = 1;
10600 }
10601 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10602 ast_test_status_update(test, "Parse failure for sayduration option\n");
10603 res = 1;
10604 }
10605 if (vmu->saydurationm != 5) {
10606 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10607 res = 1;
10608 }
10609 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10610 ast_test_status_update(test, "Parse failure for forcename option\n");
10611 res = 1;
10612 }
10613 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10614 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10615 res = 1;
10616 }
10617 if (strcasecmp(vmu->callback, "somecontext")) {
10618 ast_test_status_update(test, "Parse failure for callbacks option\n");
10619 res = 1;
10620 }
10621 if (strcasecmp(vmu->dialout, "somecontext2")) {
10622 ast_test_status_update(test, "Parse failure for dialout option\n");
10623 res = 1;
10624 }
10625 if (strcasecmp(vmu->exit, "somecontext3")) {
10626 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10627 res = 1;
10628 }
10629 if (vmu->minsecs != 10) {
10630 ast_test_status_update(test, "Parse failure for minsecs option\n");
10631 res = 1;
10632 }
10633 if (vmu->maxsecs != 100) {
10634 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10635 res = 1;
10636 }
10637 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10638 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10639 res = 1;
10640 }
10641 if (vmu->maxdeletedmsg != 50) {
10642 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10643 res = 1;
10644 }
10645 if (vmu->volgain != 1.3) {
10646 ast_test_status_update(test, "Parse failure for volgain option\n");
10647 res = 1;
10648 }
10649 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10650 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10651 res = 1;
10652 }
10653 #ifdef IMAP_STORAGE
10654 apply_options(vmu, option_string2);
10655
10656 if (strcasecmp(vmu->imapuser, "imapuser")) {
10657 ast_test_status_update(test, "Parse failure for imapuser option\n");
10658 res = 1;
10659 }
10660 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10661 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10662 res = 1;
10663 }
10664 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10665 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10666 res = 1;
10667 }
10668 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10669 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10670 res = 1;
10671 }
10672 #endif
10673
10674 free_user(vmu);
10675 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10676 }
10677
10678 static int vm_box_exists(struct ast_channel *chan, const char *data)
10679 {
10680 struct ast_vm_user svm;
10681 char *context, *box;
10682 AST_DECLARE_APP_ARGS(args,
10683 AST_APP_ARG(mbox);
10684 AST_APP_ARG(options);
10685 );
10686 static int dep_warning = 0;
10687
10688 if (ast_strlen_zero(data)) {
10689 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
10690 return -1;
10691 }
10692
10693 if (!dep_warning) {
10694 dep_warning = 1;
10695 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
10696 }
10697
10698 box = ast_strdupa(data);
10699
10700 AST_STANDARD_APP_ARGS(args, box);
10701
10702 if (args.options) {
10703 }
10704
10705 if ((context = strchr(args.mbox, '@'))) {
10706 *context = '\0';
10707 context++;
10708 }
10709
10710 if (find_user(&svm, context, args.mbox)) {
10711 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
10712 } else
10713 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
10714
10715 return 0;
10716 }
10717
10718 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
10719 {
10720 struct ast_vm_user svm;
10721 AST_DECLARE_APP_ARGS(arg,
10722 AST_APP_ARG(mbox);
10723 AST_APP_ARG(context);
10724 );
10725
10726 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
10727
10728 if (ast_strlen_zero(arg.mbox)) {
10729 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
10730 return -1;
10731 }
10732
10733 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
10734 return 0;
10735 }
10736
10737 static struct ast_custom_function mailbox_exists_acf = {
10738 .name = "MAILBOX_EXISTS",
10739 .read = acf_mailbox_exists,
10740 };
10741
10742 static int vmauthenticate(struct ast_channel *chan, const char *data)
10743 {
10744 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
10745 struct ast_vm_user vmus;
10746 char *options = NULL;
10747 int silent = 0, skipuser = 0;
10748 int res = -1;
10749
10750 if (data) {
10751 s = ast_strdupa(data);
10752 user = strsep(&s, ",");
10753 options = strsep(&s, ",");
10754 if (user) {
10755 s = user;
10756 user = strsep(&s, "@");
10757 context = strsep(&s, "");
10758 if (!ast_strlen_zero(user))
10759 skipuser++;
10760 ast_copy_string(mailbox, user, sizeof(mailbox));
10761 }
10762 }
10763
10764 if (options) {
10765 silent = (strchr(options, 's')) != NULL;
10766 }
10767
10768 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
10769 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
10770 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
10771 ast_play_and_wait(chan, "auth-thankyou");
10772 res = 0;
10773 } else if (mailbox[0] == '*') {
10774
10775 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10776 res = 0;
10777 }
10778 }
10779
10780 return res;
10781 }
10782
10783 static char *show_users_realtime(int fd, const char *context)
10784 {
10785 struct ast_config *cfg;
10786 const char *cat = NULL;
10787
10788 if (!(cfg = ast_load_realtime_multientry("voicemail",
10789 "context", context, SENTINEL))) {
10790 return CLI_FAILURE;
10791 }
10792
10793 ast_cli(fd,
10794 "\n"
10795 "=============================================================\n"
10796 "=== Configured Voicemail Users ==============================\n"
10797 "=============================================================\n"
10798 "===\n");
10799
10800 while ((cat = ast_category_browse(cfg, cat))) {
10801 struct ast_variable *var = NULL;
10802 ast_cli(fd,
10803 "=== Mailbox ...\n"
10804 "===\n");
10805 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
10806 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
10807 ast_cli(fd,
10808 "===\n"
10809 "=== ---------------------------------------------------------\n"
10810 "===\n");
10811 }
10812
10813 ast_cli(fd,
10814 "=============================================================\n"
10815 "\n");
10816
10817 ast_config_destroy(cfg);
10818
10819 return CLI_SUCCESS;
10820 }
10821
10822 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
10823 {
10824 int which = 0;
10825 int wordlen;
10826 struct ast_vm_user *vmu;
10827 const char *context = "";
10828
10829
10830 if (pos > 4)
10831 return NULL;
10832 if (pos == 3)
10833 return (state == 0) ? ast_strdup("for") : NULL;
10834 wordlen = strlen(word);
10835 AST_LIST_TRAVERSE(&users, vmu, list) {
10836 if (!strncasecmp(word, vmu->context, wordlen)) {
10837 if (context && strcmp(context, vmu->context) && ++which > state)
10838 return ast_strdup(vmu->context);
10839
10840 context = vmu->context;
10841 }
10842 }
10843 return NULL;
10844 }
10845
10846
10847 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10848 {
10849 struct ast_vm_user *vmu;
10850 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
10851 const char *context = NULL;
10852 int users_counter = 0;
10853
10854 switch (cmd) {
10855 case CLI_INIT:
10856 e->command = "voicemail show users";
10857 e->usage =
10858 "Usage: voicemail show users [for <context>]\n"
10859 " Lists all mailboxes currently set up\n";
10860 return NULL;
10861 case CLI_GENERATE:
10862 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
10863 }
10864
10865 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
10866 return CLI_SHOWUSAGE;
10867 if (a->argc == 5) {
10868 if (strcmp(a->argv[3],"for"))
10869 return CLI_SHOWUSAGE;
10870 context = a->argv[4];
10871 }
10872
10873 if (ast_check_realtime("voicemail")) {
10874 if (!context) {
10875 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
10876 return CLI_SHOWUSAGE;
10877 }
10878 return show_users_realtime(a->fd, context);
10879 }
10880
10881 AST_LIST_LOCK(&users);
10882 if (AST_LIST_EMPTY(&users)) {
10883 ast_cli(a->fd, "There are no voicemail users currently defined\n");
10884 AST_LIST_UNLOCK(&users);
10885 return CLI_FAILURE;
10886 }
10887 if (a->argc == 3)
10888 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10889 else {
10890 int count = 0;
10891 AST_LIST_TRAVERSE(&users, vmu, list) {
10892 if (!strcmp(context, vmu->context))
10893 count++;
10894 }
10895 if (count) {
10896 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10897 } else {
10898 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
10899 AST_LIST_UNLOCK(&users);
10900 return CLI_FAILURE;
10901 }
10902 }
10903 AST_LIST_TRAVERSE(&users, vmu, list) {
10904 int newmsgs = 0, oldmsgs = 0;
10905 char count[12], tmp[256] = "";
10906
10907 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
10908 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
10909 inboxcount(tmp, &newmsgs, &oldmsgs);
10910 snprintf(count, sizeof(count), "%d", newmsgs);
10911 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
10912 users_counter++;
10913 }
10914 }
10915 AST_LIST_UNLOCK(&users);
10916 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
10917 return CLI_SUCCESS;
10918 }
10919
10920
10921 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10922 {
10923 struct vm_zone *zone;
10924 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
10925 char *res = CLI_SUCCESS;
10926
10927 switch (cmd) {
10928 case CLI_INIT:
10929 e->command = "voicemail show zones";
10930 e->usage =
10931 "Usage: voicemail show zones\n"
10932 " Lists zone message formats\n";
10933 return NULL;
10934 case CLI_GENERATE:
10935 return NULL;
10936 }
10937
10938 if (a->argc != 3)
10939 return CLI_SHOWUSAGE;
10940
10941 AST_LIST_LOCK(&zones);
10942 if (!AST_LIST_EMPTY(&zones)) {
10943 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
10944 AST_LIST_TRAVERSE(&zones, zone, list) {
10945 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
10946 }
10947 } else {
10948 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
10949 res = CLI_FAILURE;
10950 }
10951 AST_LIST_UNLOCK(&zones);
10952
10953 return res;
10954 }
10955
10956
10957 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10958 {
10959 switch (cmd) {
10960 case CLI_INIT:
10961 e->command = "voicemail reload";
10962 e->usage =
10963 "Usage: voicemail reload\n"
10964 " Reload voicemail configuration\n";
10965 return NULL;
10966 case CLI_GENERATE:
10967 return NULL;
10968 }
10969
10970 if (a->argc != 2)
10971 return CLI_SHOWUSAGE;
10972
10973 ast_cli(a->fd, "Reloading voicemail configuration...\n");
10974 load_config(1);
10975
10976 return CLI_SUCCESS;
10977 }
10978
10979 static struct ast_cli_entry cli_voicemail[] = {
10980 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
10981 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
10982 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
10983 };
10984
10985 #ifdef IMAP_STORAGE
10986 #define DATA_EXPORT_VM_USERS(USER) \
10987 USER(ast_vm_user, context, AST_DATA_STRING) \
10988 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
10989 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
10990 USER(ast_vm_user, fullname, AST_DATA_STRING) \
10991 USER(ast_vm_user, email, AST_DATA_STRING) \
10992 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
10993 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
10994 USER(ast_vm_user, pager, AST_DATA_STRING) \
10995 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
10996 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
10997 USER(ast_vm_user, language, AST_DATA_STRING) \
10998 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
10999 USER(ast_vm_user, callback, AST_DATA_STRING) \
11000 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11001 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11002 USER(ast_vm_user, exit, AST_DATA_STRING) \
11003 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11004 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11005 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11006 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11007 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11008 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11009 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11010 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11011 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11012 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11013 #else
11014 #define DATA_EXPORT_VM_USERS(USER) \
11015 USER(ast_vm_user, context, AST_DATA_STRING) \
11016 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11017 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11018 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11019 USER(ast_vm_user, email, AST_DATA_STRING) \
11020 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11021 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11022 USER(ast_vm_user, pager, AST_DATA_STRING) \
11023 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11024 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11025 USER(ast_vm_user, language, AST_DATA_STRING) \
11026 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11027 USER(ast_vm_user, callback, AST_DATA_STRING) \
11028 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11029 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11030 USER(ast_vm_user, exit, AST_DATA_STRING) \
11031 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11032 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11033 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11034 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11035 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11036 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11037 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11038 #endif
11039
11040 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11041
11042 #define DATA_EXPORT_VM_ZONES(ZONE) \
11043 ZONE(vm_zone, name, AST_DATA_STRING) \
11044 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11045 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11046
11047 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11048
11049
11050
11051
11052
11053
11054
11055
11056 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11057 struct ast_data *data_root, struct ast_vm_user *user)
11058 {
11059 struct ast_data *data_user, *data_zone;
11060 struct ast_data *data_state;
11061 struct vm_zone *zone = NULL;
11062 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11063 char ext_context[256] = "";
11064
11065 data_user = ast_data_add_node(data_root, "user");
11066 if (!data_user) {
11067 return -1;
11068 }
11069
11070 ast_data_add_structure(ast_vm_user, data_user, user);
11071
11072 AST_LIST_LOCK(&zones);
11073 AST_LIST_TRAVERSE(&zones, zone, list) {
11074 if (!strcmp(zone->name, user->zonetag)) {
11075 break;
11076 }
11077 }
11078 AST_LIST_UNLOCK(&zones);
11079
11080
11081 data_state = ast_data_add_node(data_user, "state");
11082 if (!data_state) {
11083 return -1;
11084 }
11085 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11086 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11087 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11088 ast_data_add_int(data_state, "newmsg", newmsg);
11089 ast_data_add_int(data_state, "oldmsg", oldmsg);
11090
11091 if (zone) {
11092 data_zone = ast_data_add_node(data_user, "zone");
11093 ast_data_add_structure(vm_zone, data_zone, zone);
11094 }
11095
11096 if (!ast_data_search_match(search, data_user)) {
11097 ast_data_remove_node(data_root, data_user);
11098 }
11099
11100 return 0;
11101 }
11102
11103 static int vm_users_data_provider_get(const struct ast_data_search *search,
11104 struct ast_data *data_root)
11105 {
11106 struct ast_vm_user *user;
11107
11108 AST_LIST_LOCK(&users);
11109 AST_LIST_TRAVERSE(&users, user, list) {
11110 vm_users_data_provider_get_helper(search, data_root, user);
11111 }
11112 AST_LIST_UNLOCK(&users);
11113
11114 return 0;
11115 }
11116
11117 static const struct ast_data_handler vm_users_data_provider = {
11118 .version = AST_DATA_HANDLER_VERSION,
11119 .get = vm_users_data_provider_get
11120 };
11121
11122 static const struct ast_data_entry vm_data_providers[] = {
11123 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11124 };
11125
11126 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11127 {
11128 int new = 0, old = 0, urgent = 0;
11129
11130 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11131
11132 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11133 mwi_sub->old_urgent = urgent;
11134 mwi_sub->old_new = new;
11135 mwi_sub->old_old = old;
11136 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11137 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11138 }
11139 }
11140
11141 static void poll_subscribed_mailboxes(void)
11142 {
11143 struct mwi_sub *mwi_sub;
11144
11145 AST_RWLIST_RDLOCK(&mwi_subs);
11146 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11147 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11148 poll_subscribed_mailbox(mwi_sub);
11149 }
11150 }
11151 AST_RWLIST_UNLOCK(&mwi_subs);
11152 }
11153
11154 static void *mb_poll_thread(void *data)
11155 {
11156 while (poll_thread_run) {
11157 struct timespec ts = { 0, };
11158 struct timeval wait;
11159
11160 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11161 ts.tv_sec = wait.tv_sec;
11162 ts.tv_nsec = wait.tv_usec * 1000;
11163
11164 ast_mutex_lock(&poll_lock);
11165 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11166 ast_mutex_unlock(&poll_lock);
11167
11168 if (!poll_thread_run)
11169 break;
11170
11171 poll_subscribed_mailboxes();
11172 }
11173
11174 return NULL;
11175 }
11176
11177 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11178 {
11179 ast_free(mwi_sub);
11180 }
11181
11182 static int handle_unsubscribe(void *datap)
11183 {
11184 struct mwi_sub *mwi_sub;
11185 uint32_t *uniqueid = datap;
11186
11187 AST_RWLIST_WRLOCK(&mwi_subs);
11188 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11189 if (mwi_sub->uniqueid == *uniqueid) {
11190 AST_LIST_REMOVE_CURRENT(entry);
11191 break;
11192 }
11193 }
11194 AST_RWLIST_TRAVERSE_SAFE_END
11195 AST_RWLIST_UNLOCK(&mwi_subs);
11196
11197 if (mwi_sub)
11198 mwi_sub_destroy(mwi_sub);
11199
11200 ast_free(uniqueid);
11201 return 0;
11202 }
11203
11204 static int handle_subscribe(void *datap)
11205 {
11206 unsigned int len;
11207 struct mwi_sub *mwi_sub;
11208 struct mwi_sub_task *p = datap;
11209
11210 len = sizeof(*mwi_sub);
11211 if (!ast_strlen_zero(p->mailbox))
11212 len += strlen(p->mailbox);
11213
11214 if (!ast_strlen_zero(p->context))
11215 len += strlen(p->context) + 1;
11216
11217 if (!(mwi_sub = ast_calloc(1, len)))
11218 return -1;
11219
11220 mwi_sub->uniqueid = p->uniqueid;
11221 if (!ast_strlen_zero(p->mailbox))
11222 strcpy(mwi_sub->mailbox, p->mailbox);
11223
11224 if (!ast_strlen_zero(p->context)) {
11225 strcat(mwi_sub->mailbox, "@");
11226 strcat(mwi_sub->mailbox, p->context);
11227 }
11228
11229 AST_RWLIST_WRLOCK(&mwi_subs);
11230 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11231 AST_RWLIST_UNLOCK(&mwi_subs);
11232 ast_free((void *) p->mailbox);
11233 ast_free((void *) p->context);
11234 ast_free(p);
11235 poll_subscribed_mailbox(mwi_sub);
11236 return 0;
11237 }
11238
11239 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11240 {
11241 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11242 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
11243 return;
11244
11245 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11246 return;
11247
11248 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11249 *uniqueid = u;
11250 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11251 ast_free(uniqueid);
11252 }
11253 }
11254
11255 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11256 {
11257 struct mwi_sub_task *mwist;
11258
11259 if (ast_event_get_type(event) != AST_EVENT_SUB)
11260 return;
11261
11262 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11263 return;
11264
11265 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11266 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11267 return;
11268 }
11269 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11270 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11271 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11272
11273 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11274 ast_free(mwist);
11275 }
11276 }
11277
11278 static void start_poll_thread(void)
11279 {
11280 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11281 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11282 AST_EVENT_IE_END);
11283
11284 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11285 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11286 AST_EVENT_IE_END);
11287
11288 if (mwi_sub_sub)
11289 ast_event_report_subs(mwi_sub_sub);
11290
11291 poll_thread_run = 1;
11292
11293 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
11294 }
11295
11296 static void stop_poll_thread(void)
11297 {
11298 poll_thread_run = 0;
11299
11300 if (mwi_sub_sub) {
11301 ast_event_unsubscribe(mwi_sub_sub);
11302 mwi_sub_sub = NULL;
11303 }
11304
11305 if (mwi_unsub_sub) {
11306 ast_event_unsubscribe(mwi_unsub_sub);
11307 mwi_unsub_sub = NULL;
11308 }
11309
11310 ast_mutex_lock(&poll_lock);
11311 ast_cond_signal(&poll_cond);
11312 ast_mutex_unlock(&poll_lock);
11313
11314 pthread_join(poll_thread, NULL);
11315
11316 poll_thread = AST_PTHREADT_NULL;
11317 }
11318
11319
11320 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11321 {
11322 struct ast_vm_user *vmu = NULL;
11323 const char *id = astman_get_header(m, "ActionID");
11324 char actionid[128] = "";
11325
11326 if (!ast_strlen_zero(id))
11327 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11328
11329 AST_LIST_LOCK(&users);
11330
11331 if (AST_LIST_EMPTY(&users)) {
11332 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11333 AST_LIST_UNLOCK(&users);
11334 return RESULT_SUCCESS;
11335 }
11336
11337 astman_send_ack(s, m, "Voicemail user list will follow");
11338
11339 AST_LIST_TRAVERSE(&users, vmu, list) {
11340 char dirname[256];
11341
11342 #ifdef IMAP_STORAGE
11343 int new, old;
11344 inboxcount(vmu->mailbox, &new, &old);
11345 #endif
11346
11347 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11348 astman_append(s,
11349 "%s"
11350 "Event: VoicemailUserEntry\r\n"
11351 "VMContext: %s\r\n"
11352 "VoiceMailbox: %s\r\n"
11353 "Fullname: %s\r\n"
11354 "Email: %s\r\n"
11355 "Pager: %s\r\n"
11356 "ServerEmail: %s\r\n"
11357 "MailCommand: %s\r\n"
11358 "Language: %s\r\n"
11359 "TimeZone: %s\r\n"
11360 "Callback: %s\r\n"
11361 "Dialout: %s\r\n"
11362 "UniqueID: %s\r\n"
11363 "ExitContext: %s\r\n"
11364 "SayDurationMinimum: %d\r\n"
11365 "SayEnvelope: %s\r\n"
11366 "SayCID: %s\r\n"
11367 "AttachMessage: %s\r\n"
11368 "AttachmentFormat: %s\r\n"
11369 "DeleteMessage: %s\r\n"
11370 "VolumeGain: %.2f\r\n"
11371 "CanReview: %s\r\n"
11372 "CallOperator: %s\r\n"
11373 "MaxMessageCount: %d\r\n"
11374 "MaxMessageLength: %d\r\n"
11375 "NewMessageCount: %d\r\n"
11376 #ifdef IMAP_STORAGE
11377 "OldMessageCount: %d\r\n"
11378 "IMAPUser: %s\r\n"
11379 #endif
11380 "\r\n",
11381 actionid,
11382 vmu->context,
11383 vmu->mailbox,
11384 vmu->fullname,
11385 vmu->email,
11386 vmu->pager,
11387 vmu->serveremail,
11388 vmu->mailcmd,
11389 vmu->language,
11390 vmu->zonetag,
11391 vmu->callback,
11392 vmu->dialout,
11393 vmu->uniqueid,
11394 vmu->exit,
11395 vmu->saydurationm,
11396 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11397 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11398 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11399 vmu->attachfmt,
11400 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11401 vmu->volgain,
11402 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11403 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11404 vmu->maxmsg,
11405 vmu->maxsecs,
11406 #ifdef IMAP_STORAGE
11407 new, old, vmu->imapuser
11408 #else
11409 count_messages(vmu, dirname)
11410 #endif
11411 );
11412 }
11413 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11414
11415 AST_LIST_UNLOCK(&users);
11416
11417 return RESULT_SUCCESS;
11418 }
11419
11420
11421 static void free_vm_users(void)
11422 {
11423 struct ast_vm_user *current;
11424 AST_LIST_LOCK(&users);
11425 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11426 ast_set_flag(current, VM_ALLOCED);
11427 free_user(current);
11428 }
11429 AST_LIST_UNLOCK(&users);
11430 }
11431
11432
11433 static void free_vm_zones(void)
11434 {
11435 struct vm_zone *zcur;
11436 AST_LIST_LOCK(&zones);
11437 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11438 free_zone(zcur);
11439 AST_LIST_UNLOCK(&zones);
11440 }
11441
11442 static const char *substitute_escapes(const char *value)
11443 {
11444 char *current;
11445
11446
11447 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11448
11449 ast_str_reset(str);
11450
11451
11452 for (current = (char *) value; *current; current++) {
11453 if (*current == '\\') {
11454 current++;
11455 if (!*current) {
11456 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11457 break;
11458 }
11459 switch (*current) {
11460 case 'r':
11461 ast_str_append(&str, 0, "\r");
11462 break;
11463 case 'n':
11464 #ifdef IMAP_STORAGE
11465 if (!str->used || str->str[str->used - 1] != '\r') {
11466 ast_str_append(&str, 0, "\r");
11467 }
11468 #endif
11469 ast_str_append(&str, 0, "\n");
11470 break;
11471 case 't':
11472 ast_str_append(&str, 0, "\t");
11473 break;
11474 default:
11475 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11476 break;
11477 }
11478 } else {
11479 ast_str_append(&str, 0, "%c", *current);
11480 }
11481 }
11482
11483 return ast_str_buffer(str);
11484 }
11485
11486 static int load_config(int reload)
11487 {
11488 struct ast_vm_user *current;
11489 struct ast_config *cfg, *ucfg;
11490 char *cat;
11491 struct ast_variable *var;
11492 const char *val;
11493 char *q, *stringp, *tmp;
11494 int x;
11495 int tmpadsi[4];
11496 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11497 char secretfn[PATH_MAX] = "";
11498
11499 ast_unload_realtime("voicemail");
11500 ast_unload_realtime("voicemail_data");
11501
11502 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11503 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11504 return 0;
11505 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11506 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11507 ucfg = NULL;
11508 }
11509 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11510 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11511 ast_config_destroy(ucfg);
11512 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11513 return 0;
11514 }
11515 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11516 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11517 return 0;
11518 } else {
11519 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11520 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11521 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11522 ucfg = NULL;
11523 }
11524 }
11525 #ifdef IMAP_STORAGE
11526 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11527 #endif
11528
11529 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11530 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11531 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11532 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11533 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11534
11535
11536 free_vm_users();
11537
11538
11539 free_vm_zones();
11540
11541 AST_LIST_LOCK(&users);
11542
11543 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11544 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11545
11546 if (cfg) {
11547
11548
11549 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11550 val = "default";
11551 ast_copy_string(userscontext, val, sizeof(userscontext));
11552
11553 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11554 val = "yes";
11555 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11556
11557 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11558 val = "no";
11559 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11560
11561 volgain = 0.0;
11562 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11563 sscanf(val, "%30lf", &volgain);
11564
11565 #ifdef ODBC_STORAGE
11566 strcpy(odbc_database, "asterisk");
11567 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11568 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11569 }
11570 strcpy(odbc_table, "voicemessages");
11571 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11572 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11573 }
11574 #endif
11575
11576 strcpy(mailcmd, SENDMAIL);
11577 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11578 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11579
11580 maxsilence = 0;
11581 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11582 maxsilence = atoi(val);
11583 if (maxsilence > 0)
11584 maxsilence *= 1000;
11585 }
11586
11587 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11588 maxmsg = MAXMSG;
11589 } else {
11590 maxmsg = atoi(val);
11591 if (maxmsg < 0) {
11592 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11593 maxmsg = MAXMSG;
11594 } else if (maxmsg > MAXMSGLIMIT) {
11595 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11596 maxmsg = MAXMSGLIMIT;
11597 }
11598 }
11599
11600 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11601 maxdeletedmsg = 0;
11602 } else {
11603 if (sscanf(val, "%30d", &x) == 1)
11604 maxdeletedmsg = x;
11605 else if (ast_true(val))
11606 maxdeletedmsg = MAXMSG;
11607 else
11608 maxdeletedmsg = 0;
11609
11610 if (maxdeletedmsg < 0) {
11611 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11612 maxdeletedmsg = MAXMSG;
11613 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11614 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11615 maxdeletedmsg = MAXMSGLIMIT;
11616 }
11617 }
11618
11619
11620 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11621 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11622 }
11623
11624
11625 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11626 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11627 }
11628
11629
11630 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11631 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11632 pwdchange = PWDCHANGE_EXTERNAL;
11633 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11634 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11635 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11636 }
11637
11638
11639 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11640 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11641 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11642 }
11643
11644 #ifdef IMAP_STORAGE
11645
11646 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
11647 ast_copy_string(imapserver, val, sizeof(imapserver));
11648 } else {
11649 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
11650 }
11651
11652 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
11653 ast_copy_string(imapport, val, sizeof(imapport));
11654 } else {
11655 ast_copy_string(imapport, "143", sizeof(imapport));
11656 }
11657
11658 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
11659 ast_copy_string(imapflags, val, sizeof(imapflags));
11660 }
11661
11662 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
11663 ast_copy_string(authuser, val, sizeof(authuser));
11664 }
11665
11666 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
11667 ast_copy_string(authpassword, val, sizeof(authpassword));
11668 }
11669
11670 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
11671 if (ast_false(val))
11672 expungeonhangup = 0;
11673 else
11674 expungeonhangup = 1;
11675 } else {
11676 expungeonhangup = 1;
11677 }
11678
11679 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
11680 ast_copy_string(imapfolder, val, sizeof(imapfolder));
11681 } else {
11682 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
11683 }
11684 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
11685 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
11686 }
11687 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
11688 imapgreetings = ast_true(val);
11689 } else {
11690 imapgreetings = 0;
11691 }
11692 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
11693 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
11694 } else {
11695 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
11696 }
11697
11698
11699
11700
11701
11702 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
11703 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
11704 } else {
11705 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
11706 }
11707
11708 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
11709 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
11710 } else {
11711 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
11712 }
11713
11714 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
11715 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
11716 } else {
11717 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
11718 }
11719
11720 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
11721 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
11722 } else {
11723 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
11724 }
11725
11726
11727 imapversion++;
11728 #endif
11729
11730 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
11731 ast_copy_string(externnotify, val, sizeof(externnotify));
11732 ast_debug(1, "found externnotify: %s\n", externnotify);
11733 } else {
11734 externnotify[0] = '\0';
11735 }
11736
11737
11738 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
11739 ast_debug(1, "Enabled SMDI voicemail notification\n");
11740 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
11741 smdi_iface = ast_smdi_interface_find(val);
11742 } else {
11743 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
11744 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
11745 }
11746 if (!smdi_iface) {
11747 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
11748 }
11749 }
11750
11751
11752 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
11753 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
11754 silencethreshold = atoi(val);
11755
11756 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
11757 val = ASTERISK_USERNAME;
11758 ast_copy_string(serveremail, val, sizeof(serveremail));
11759
11760 vmmaxsecs = 0;
11761 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
11762 if (sscanf(val, "%30d", &x) == 1) {
11763 vmmaxsecs = x;
11764 } else {
11765 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11766 }
11767 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
11768 static int maxmessage_deprecate = 0;
11769 if (maxmessage_deprecate == 0) {
11770 maxmessage_deprecate = 1;
11771 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
11772 }
11773 if (sscanf(val, "%30d", &x) == 1) {
11774 vmmaxsecs = x;
11775 } else {
11776 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
11777 }
11778 }
11779
11780 vmminsecs = 0;
11781 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
11782 if (sscanf(val, "%30d", &x) == 1) {
11783 vmminsecs = x;
11784 if (maxsilence / 1000 >= vmminsecs) {
11785 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
11786 }
11787 } else {
11788 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11789 }
11790 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
11791 static int maxmessage_deprecate = 0;
11792 if (maxmessage_deprecate == 0) {
11793 maxmessage_deprecate = 1;
11794 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
11795 }
11796 if (sscanf(val, "%30d", &x) == 1) {
11797 vmminsecs = x;
11798 if (maxsilence / 1000 >= vmminsecs) {
11799 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
11800 }
11801 } else {
11802 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
11803 }
11804 }
11805
11806 val = ast_variable_retrieve(cfg, "general", "format");
11807 if (!val) {
11808 val = "wav";
11809 } else {
11810 tmp = ast_strdupa(val);
11811 val = ast_format_str_reduce(tmp);
11812 if (!val) {
11813 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
11814 val = "wav";
11815 }
11816 }
11817 ast_copy_string(vmfmts, val, sizeof(vmfmts));
11818
11819 skipms = 3000;
11820 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
11821 if (sscanf(val, "%30d", &x) == 1) {
11822 maxgreet = x;
11823 } else {
11824 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
11825 }
11826 }
11827
11828 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
11829 if (sscanf(val, "%30d", &x) == 1) {
11830 skipms = x;
11831 } else {
11832 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
11833 }
11834 }
11835
11836 maxlogins = 3;
11837 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
11838 if (sscanf(val, "%30d", &x) == 1) {
11839 maxlogins = x;
11840 } else {
11841 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
11842 }
11843 }
11844
11845 minpassword = MINPASSWORD;
11846 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
11847 if (sscanf(val, "%30d", &x) == 1) {
11848 minpassword = x;
11849 } else {
11850 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
11851 }
11852 }
11853
11854
11855 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
11856 val = "no";
11857 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
11858
11859
11860 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
11861 val = "no";
11862 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
11863
11864 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
11865 ast_debug(1, "VM_CID Internal context string: %s\n", val);
11866 stringp = ast_strdupa(val);
11867 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
11868 if (!ast_strlen_zero(stringp)) {
11869 q = strsep(&stringp, ",");
11870 while ((*q == ' ')||(*q == '\t'))
11871 q++;
11872 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
11873 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
11874 } else {
11875 cidinternalcontexts[x][0] = '\0';
11876 }
11877 }
11878 }
11879 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
11880 ast_debug(1, "VM Review Option disabled globally\n");
11881 val = "no";
11882 }
11883 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
11884
11885
11886 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
11887 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
11888 val = "no";
11889 } else {
11890 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
11891 }
11892 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
11893 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
11894 ast_debug(1, "VM next message wrap disabled globally\n");
11895 val = "no";
11896 }
11897 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
11898
11899 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
11900 ast_debug(1, "VM Operator break disabled globally\n");
11901 val = "no";
11902 }
11903 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
11904
11905 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
11906 ast_debug(1, "VM CID Info before msg disabled globally\n");
11907 val = "no";
11908 }
11909 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
11910
11911 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
11912 ast_debug(1, "Send Voicemail msg disabled globally\n");
11913 val = "no";
11914 }
11915 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
11916
11917 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
11918 ast_debug(1, "ENVELOPE before msg enabled globally\n");
11919 val = "yes";
11920 }
11921 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
11922
11923 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
11924 ast_debug(1, "Move Heard enabled globally\n");
11925 val = "yes";
11926 }
11927 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
11928
11929 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
11930 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
11931 val = "no";
11932 }
11933 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
11934
11935 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
11936 ast_debug(1, "Duration info before msg enabled globally\n");
11937 val = "yes";
11938 }
11939 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
11940
11941 saydurationminfo = 2;
11942 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
11943 if (sscanf(val, "%30d", &x) == 1) {
11944 saydurationminfo = x;
11945 } else {
11946 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
11947 }
11948 }
11949
11950 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
11951 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
11952 val = "no";
11953 }
11954 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
11955
11956 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
11957 ast_copy_string(dialcontext, val, sizeof(dialcontext));
11958 ast_debug(1, "found dialout context: %s\n", dialcontext);
11959 } else {
11960 dialcontext[0] = '\0';
11961 }
11962
11963 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
11964 ast_copy_string(callcontext, val, sizeof(callcontext));
11965 ast_debug(1, "found callback context: %s\n", callcontext);
11966 } else {
11967 callcontext[0] = '\0';
11968 }
11969
11970 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
11971 ast_copy_string(exitcontext, val, sizeof(exitcontext));
11972 ast_debug(1, "found operator context: %s\n", exitcontext);
11973 } else {
11974 exitcontext[0] = '\0';
11975 }
11976
11977
11978 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
11979 ast_copy_string(vm_password, val, sizeof(vm_password));
11980 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
11981 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
11982 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
11983 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
11984 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
11985 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
11986 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
11987 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
11988 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
11989 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
11990 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
11991 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
11992 }
11993
11994 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
11995 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
11996 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
11997 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
11998 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
11999 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12000 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12001 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12002 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12003 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12004
12005 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12006 val = "no";
12007 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12008
12009 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12010 val = "voicemail.conf";
12011 }
12012 if (!(strcmp(val, "spooldir"))) {
12013 passwordlocation = OPT_PWLOC_SPOOLDIR;
12014 } else {
12015 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12016 }
12017
12018 poll_freq = DEFAULT_POLL_FREQ;
12019 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12020 if (sscanf(val, "%30u", &poll_freq) != 1) {
12021 poll_freq = DEFAULT_POLL_FREQ;
12022 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12023 }
12024 }
12025
12026 poll_mailboxes = 0;
12027 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12028 poll_mailboxes = ast_true(val);
12029
12030 if (ucfg) {
12031 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12032 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12033 continue;
12034 if ((current = find_or_create(userscontext, cat))) {
12035 populate_defaults(current);
12036 apply_options_full(current, ast_variable_browse(ucfg, cat));
12037 ast_copy_string(current->context, userscontext, sizeof(current->context));
12038 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12039 current->passwordlocation = OPT_PWLOC_USERSCONF;
12040 }
12041
12042 switch (current->passwordlocation) {
12043 case OPT_PWLOC_SPOOLDIR:
12044 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12045 read_password_from_file(secretfn, current->password, sizeof(current->password));
12046 }
12047 }
12048 }
12049 ast_config_destroy(ucfg);
12050 }
12051 cat = ast_category_browse(cfg, NULL);
12052 while (cat) {
12053 if (strcasecmp(cat, "general")) {
12054 var = ast_variable_browse(cfg, cat);
12055 if (strcasecmp(cat, "zonemessages")) {
12056
12057 while (var) {
12058 append_mailbox(cat, var->name, var->value);
12059 var = var->next;
12060 }
12061 } else {
12062
12063 while (var) {
12064 struct vm_zone *z;
12065 if ((z = ast_malloc(sizeof(*z)))) {
12066 char *msg_format, *tzone;
12067 msg_format = ast_strdupa(var->value);
12068 tzone = strsep(&msg_format, "|,");
12069 if (msg_format) {
12070 ast_copy_string(z->name, var->name, sizeof(z->name));
12071 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12072 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12073 AST_LIST_LOCK(&zones);
12074 AST_LIST_INSERT_HEAD(&zones, z, list);
12075 AST_LIST_UNLOCK(&zones);
12076 } else {
12077 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12078 ast_free(z);
12079 }
12080 } else {
12081 AST_LIST_UNLOCK(&users);
12082 ast_config_destroy(cfg);
12083 return -1;
12084 }
12085 var = var->next;
12086 }
12087 }
12088 }
12089 cat = ast_category_browse(cfg, cat);
12090 }
12091 memset(fromstring, 0, sizeof(fromstring));
12092 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12093 strcpy(charset, "ISO-8859-1");
12094 if (emailbody) {
12095 ast_free(emailbody);
12096 emailbody = NULL;
12097 }
12098 if (emailsubject) {
12099 ast_free(emailsubject);
12100 emailsubject = NULL;
12101 }
12102 if (pagerbody) {
12103 ast_free(pagerbody);
12104 pagerbody = NULL;
12105 }
12106 if (pagersubject) {
12107 ast_free(pagersubject);
12108 pagersubject = NULL;
12109 }
12110 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12111 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12112 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12113 ast_copy_string(fromstring, val, sizeof(fromstring));
12114 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12115 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12116 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12117 ast_copy_string(charset, val, sizeof(charset));
12118 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12119 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12120 for (x = 0; x < 4; x++) {
12121 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12122 }
12123 }
12124 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12125 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12126 for (x = 0; x < 4; x++) {
12127 memcpy(&adsisec[x], &tmpadsi[x], 1);
12128 }
12129 }
12130 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12131 if (atoi(val)) {
12132 adsiver = atoi(val);
12133 }
12134 }
12135 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12136 ast_copy_string(zonetag, val, sizeof(zonetag));
12137 }
12138 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12139 ast_copy_string(locale, val, sizeof(locale));
12140 }
12141 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12142 emailsubject = ast_strdup(val);
12143 }
12144 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12145 emailbody = ast_strdup(substitute_escapes(val));
12146 }
12147 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12148 pagersubject = ast_strdup(val);
12149 }
12150 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12151 pagerbody = ast_strdup(substitute_escapes(val));
12152 }
12153 AST_LIST_UNLOCK(&users);
12154 ast_config_destroy(cfg);
12155
12156 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12157 start_poll_thread();
12158 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12159 stop_poll_thread();;
12160
12161 return 0;
12162 } else {
12163 AST_LIST_UNLOCK(&users);
12164 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12165 if (ucfg)
12166 ast_config_destroy(ucfg);
12167 return 0;
12168 }
12169 }
12170
12171 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12172 {
12173 int res = -1;
12174 char dir[PATH_MAX];
12175 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12176 ast_debug(2, "About to try retrieving name file %s\n", dir);
12177 RETRIEVE(dir, -1, mailbox, context);
12178 if (ast_fileexists(dir, NULL, NULL)) {
12179 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12180 }
12181 DISPOSE(dir, -1);
12182 return res;
12183 }
12184
12185 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12186 struct ast_config *pwconf;
12187 struct ast_flags config_flags = { 0 };
12188
12189 pwconf = ast_config_load(secretfn, config_flags);
12190 if (pwconf) {
12191 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12192 if (val) {
12193 ast_copy_string(password, val, passwordlen);
12194 return;
12195 }
12196 }
12197 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12198 }
12199
12200 static int write_password_to_file(const char *secretfn, const char *password) {
12201 struct ast_config *conf;
12202 struct ast_category *cat;
12203 struct ast_variable *var;
12204
12205 if (!(conf=ast_config_new())) {
12206 ast_log(LOG_ERROR, "Error creating new config structure\n");
12207 return -1;
12208 }
12209 if (!(cat=ast_category_new("general","",1))) {
12210 ast_log(LOG_ERROR, "Error creating new category structure\n");
12211 return -1;
12212 }
12213 if (!(var=ast_variable_new("password",password,""))) {
12214 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12215 return -1;
12216 }
12217 ast_category_append(conf,cat);
12218 ast_variable_append(cat,var);
12219 if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12220 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12221 return -1;
12222 }
12223 return 0;
12224 }
12225
12226 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12227 {
12228 char *context;
12229 char *args_copy;
12230 int res;
12231
12232 if (ast_strlen_zero(data)) {
12233 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context");
12234 return -1;
12235 }
12236
12237 args_copy = ast_strdupa(data);
12238 if ((context = strchr(args_copy, '@'))) {
12239 *context++ = '\0';
12240 } else {
12241 context = "default";
12242 }
12243
12244 if ((res = sayname(chan, args_copy, context) < 0)) {
12245 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12246 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12247 if (!res) {
12248 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12249 }
12250 }
12251
12252 return res;
12253 }
12254
12255 #ifdef TEST_FRAMEWORK
12256 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12257 {
12258 return 0;
12259 }
12260
12261 static struct ast_frame *fake_read(struct ast_channel *ast)
12262 {
12263 return &ast_null_frame;
12264 }
12265
12266 AST_TEST_DEFINE(test_voicemail_vmsayname)
12267 {
12268 char dir[PATH_MAX];
12269 char dir2[PATH_MAX];
12270 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12271 static const char TEST_EXTENSION[] = "1234";
12272
12273 struct ast_channel *test_channel1 = NULL;
12274 int res = -1;
12275
12276 static const struct ast_channel_tech fake_tech = {
12277 .write = fake_write,
12278 .read = fake_read,
12279 };
12280
12281 switch (cmd) {
12282 case TEST_INIT:
12283 info->name = "vmsayname_exec";
12284 info->category = "/apps/app_voicemail/";
12285 info->summary = "Vmsayname unit test";
12286 info->description =
12287 "This tests passing various parameters to vmsayname";
12288 return AST_TEST_NOT_RUN;
12289 case TEST_EXECUTE:
12290 break;
12291 }
12292
12293 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12294 NULL, NULL, 0, 0, "TestChannel1"))) {
12295 goto exit_vmsayname_test;
12296 }
12297
12298
12299 test_channel1->nativeformats = AST_FORMAT_GSM;
12300 test_channel1->writeformat = AST_FORMAT_GSM;
12301 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12302 test_channel1->readformat = AST_FORMAT_GSM;
12303 test_channel1->rawreadformat = AST_FORMAT_GSM;
12304 test_channel1->tech = &fake_tech;
12305
12306 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12307 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12308 if (!(res = vmsayname_exec(test_channel1, dir))) {
12309 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12310 if (ast_fileexists(dir, NULL, NULL)) {
12311 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12312 res = -1;
12313 goto exit_vmsayname_test;
12314 } else {
12315
12316 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12317 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12318 goto exit_vmsayname_test;
12319 }
12320 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12321 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12322
12323 if ((res = symlink(dir, dir2))) {
12324 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12325 goto exit_vmsayname_test;
12326 }
12327 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12328 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12329 res = vmsayname_exec(test_channel1, dir);
12330
12331
12332 unlink(dir2);
12333 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12334 rmdir(dir2);
12335 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12336 rmdir(dir2);
12337 }
12338 }
12339
12340 exit_vmsayname_test:
12341
12342 if (test_channel1) {
12343 ast_hangup(test_channel1);
12344 }
12345
12346 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12347 }
12348
12349 AST_TEST_DEFINE(test_voicemail_msgcount)
12350 {
12351 int i, j, res = AST_TEST_PASS, syserr;
12352 struct ast_vm_user *vmu;
12353 struct vm_state vms;
12354 #ifdef IMAP_STORAGE
12355 struct ast_channel *chan = NULL;
12356 #endif
12357 struct {
12358 char dir[256];
12359 char file[256];
12360 char txtfile[256];
12361 } tmp[3];
12362 char syscmd[256];
12363 const char origweasels[] = "tt-weasels";
12364 const char testcontext[] = "test";
12365 const char testmailbox[] = "00000000";
12366 const char testspec[] = "00000000@test";
12367 FILE *txt;
12368 int new, old, urgent;
12369 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12370 const int folder2mbox[3] = { 1, 11, 0 };
12371 const int expected_results[3][12] = {
12372
12373 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12374 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12375 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12376 };
12377
12378 switch (cmd) {
12379 case TEST_INIT:
12380 info->name = "test_voicemail_msgcount";
12381 info->category = "/apps/app_voicemail/";
12382 info->summary = "Test Voicemail status checks";
12383 info->description =
12384 "Verify that message counts are correct when retrieved through the public API";
12385 return AST_TEST_NOT_RUN;
12386 case TEST_EXECUTE:
12387 break;
12388 }
12389
12390
12391 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12392 if ((syserr = ast_safe_system(syscmd))) {
12393 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12394 syserr > 0 ? strerror(syserr) : "unable to fork()");
12395 return AST_TEST_FAIL;
12396 }
12397
12398 #ifdef IMAP_STORAGE
12399 if (!(chan = ast_dummy_channel_alloc())) {
12400 ast_test_status_update(test, "Unable to create dummy channel\n");
12401 return AST_TEST_FAIL;
12402 }
12403 #endif
12404
12405 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12406 !(vmu = find_or_create(testcontext, testmailbox))) {
12407 ast_test_status_update(test, "Cannot create vmu structure\n");
12408 ast_unreplace_sigchld();
12409 return AST_TEST_FAIL;
12410 }
12411
12412 populate_defaults(vmu);
12413 memset(&vms, 0, sizeof(vms));
12414
12415
12416 for (i = 0; i < 3; i++) {
12417 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12418 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12419 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12420
12421 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12422 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12423 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12424 if ((syserr = ast_safe_system(syscmd))) {
12425 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12426 syserr > 0 ? strerror(syserr) : "unable to fork()");
12427 ast_unreplace_sigchld();
12428 return AST_TEST_FAIL;
12429 }
12430 }
12431
12432 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12433 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12434 fclose(txt);
12435 } else {
12436 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12437 res = AST_TEST_FAIL;
12438 break;
12439 }
12440 open_mailbox(&vms, vmu, folder2mbox[i]);
12441 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12442
12443
12444 for (j = 0; j < 3; j++) {
12445
12446 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12447 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12448 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12449 res = AST_TEST_FAIL;
12450 }
12451 }
12452
12453 new = old = urgent = 0;
12454 if (ast_app_inboxcount(testspec, &new, &old)) {
12455 ast_test_status_update(test, "inboxcount returned failure\n");
12456 res = AST_TEST_FAIL;
12457 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12458 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12459 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12460 res = AST_TEST_FAIL;
12461 }
12462
12463 new = old = urgent = 0;
12464 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12465 ast_test_status_update(test, "inboxcount2 returned failure\n");
12466 res = AST_TEST_FAIL;
12467 } else if (old != expected_results[i][6 + 0] ||
12468 urgent != expected_results[i][6 + 1] ||
12469 new != expected_results[i][6 + 2] ) {
12470 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12471 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12472 res = AST_TEST_FAIL;
12473 }
12474
12475 new = old = urgent = 0;
12476 for (j = 0; j < 3; j++) {
12477 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12478 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12479 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12480 res = AST_TEST_FAIL;
12481 }
12482 }
12483 }
12484
12485 for (i = 0; i < 3; i++) {
12486
12487
12488
12489 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12490 DISPOSE(tmp[i].dir, 0);
12491 }
12492
12493 if (vms.deleted) {
12494 ast_free(vms.deleted);
12495 }
12496 if (vms.heard) {
12497 ast_free(vms.heard);
12498 }
12499
12500 #ifdef IMAP_STORAGE
12501 chan = ast_channel_release(chan);
12502 #endif
12503
12504
12505 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12506 if ((syserr = ast_safe_system(syscmd))) {
12507 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12508 syserr > 0 ? strerror(syserr) : "unable to fork()");
12509 }
12510
12511 return res;
12512 }
12513
12514 AST_TEST_DEFINE(test_voicemail_notify_endl)
12515 {
12516 int res = AST_TEST_PASS;
12517 char testcontext[] = "test";
12518 char testmailbox[] = "00000000";
12519 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12520 char attach[256], attach2[256];
12521 char buf[256] = "";
12522 struct ast_channel *chan = NULL;
12523 struct ast_vm_user *vmu, vmus = {
12524 .flags = 0,
12525 };
12526 FILE *file;
12527 struct {
12528 char *name;
12529 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12530 void *location;
12531 union {
12532 int intval;
12533 char *strval;
12534 } u;
12535 } test_items[] = {
12536 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12537 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12538 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12539 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12540 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12541 { "attach2", STRPTR, attach2, .u.strval = "" },
12542 { "attach", STRPTR, attach, .u.strval = "" },
12543 };
12544 int which;
12545
12546 switch (cmd) {
12547 case TEST_INIT:
12548 info->name = "test_voicemail_notify_endl";
12549 info->category = "/apps/app_voicemail/";
12550 info->summary = "Test Voicemail notification end-of-line";
12551 info->description =
12552 "Verify that notification emails use a consistent end-of-line character";
12553 return AST_TEST_NOT_RUN;
12554 case TEST_EXECUTE:
12555 break;
12556 }
12557
12558 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12559 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12560
12561 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12562 !(vmu = find_or_create(testcontext, testmailbox))) {
12563 ast_test_status_update(test, "Cannot create vmu structure\n");
12564 return AST_TEST_NOT_RUN;
12565 }
12566
12567 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12568 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12569 return AST_TEST_NOT_RUN;
12570 }
12571
12572 populate_defaults(vmu);
12573 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12574 #ifdef IMAP_STORAGE
12575
12576 #endif
12577
12578 file = tmpfile();
12579 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12580
12581 rewind(file);
12582 if (ftruncate(fileno(file), 0)) {
12583 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12584 res = AST_TEST_FAIL;
12585 break;
12586 }
12587
12588
12589 if (test_items[which].type == INT) {
12590 *((int *) test_items[which].location) = test_items[which].u.intval;
12591 } else if (test_items[which].type == FLAGVAL) {
12592 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12593 ast_clear_flag(vmu, test_items[which].u.intval);
12594 } else {
12595 ast_set_flag(vmu, test_items[which].u.intval);
12596 }
12597 } else if (test_items[which].type == STATIC) {
12598 strcpy(test_items[which].location, test_items[which].u.strval);
12599 } else if (test_items[which].type == STRPTR) {
12600 test_items[which].location = test_items[which].u.strval;
12601 }
12602
12603 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12604 rewind(file);
12605 while (fgets(buf, sizeof(buf), file)) {
12606 if (
12607 #ifdef IMAP_STORAGE
12608 buf[strlen(buf) - 2] != '\r'
12609 #else
12610 buf[strlen(buf) - 2] == '\r'
12611 #endif
12612 || buf[strlen(buf) - 1] != '\n') {
12613 res = AST_TEST_FAIL;
12614 }
12615 }
12616 }
12617 fclose(file);
12618 return res;
12619 }
12620 #endif
12621
12622 static int reload(void)
12623 {
12624 return load_config(1);
12625 }
12626
12627 static int unload_module(void)
12628 {
12629 int res;
12630
12631 res = ast_unregister_application(app);
12632 res |= ast_unregister_application(app2);
12633 res |= ast_unregister_application(app3);
12634 res |= ast_unregister_application(app4);
12635 res |= ast_unregister_application(sayname_app);
12636 res |= ast_custom_function_unregister(&mailbox_exists_acf);
12637 res |= ast_manager_unregister("VoicemailUsersList");
12638 res |= ast_data_unregister(NULL);
12639 #ifdef TEST_FRAMEWORK
12640 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
12641 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
12642 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
12643 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
12644 #endif
12645 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12646 ast_uninstall_vm_functions();
12647 ao2_ref(inprocess_container, -1);
12648
12649 if (poll_thread != AST_PTHREADT_NULL)
12650 stop_poll_thread();
12651
12652 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
12653 ast_unload_realtime("voicemail");
12654 ast_unload_realtime("voicemail_data");
12655
12656 free_vm_users();
12657 free_vm_zones();
12658 return res;
12659 }
12660
12661 static int load_module(void)
12662 {
12663 int res;
12664 my_umask = umask(0);
12665 umask(my_umask);
12666
12667 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
12668 return AST_MODULE_LOAD_DECLINE;
12669 }
12670
12671
12672 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
12673
12674 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
12675 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
12676 }
12677
12678 if ((res = load_config(0)))
12679 return res;
12680
12681 res = ast_register_application_xml(app, vm_exec);
12682 res |= ast_register_application_xml(app2, vm_execmain);
12683 res |= ast_register_application_xml(app3, vm_box_exists);
12684 res |= ast_register_application_xml(app4, vmauthenticate);
12685 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
12686 res |= ast_custom_function_register(&mailbox_exists_acf);
12687 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
12688 #ifdef TEST_FRAMEWORK
12689 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
12690 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
12691 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
12692 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
12693 #endif
12694
12695 if (res)
12696 return res;
12697
12698 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
12699 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
12700
12701 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
12702 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
12703 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
12704
12705 return res;
12706 }
12707
12708 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
12709 {
12710 int cmd = 0;
12711 char destination[80] = "";
12712 int retries = 0;
12713
12714 if (!num) {
12715 ast_verb(3, "Destination number will be entered manually\n");
12716 while (retries < 3 && cmd != 't') {
12717 destination[1] = '\0';
12718 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
12719 if (!cmd)
12720 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
12721 if (!cmd)
12722 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
12723 if (!cmd) {
12724 cmd = ast_waitfordigit(chan, 6000);
12725 if (cmd)
12726 destination[0] = cmd;
12727 }
12728 if (!cmd) {
12729 retries++;
12730 } else {
12731
12732 if (cmd < 0)
12733 return 0;
12734 if (cmd == '*') {
12735 ast_verb(3, "User hit '*' to cancel outgoing call\n");
12736 return 0;
12737 }
12738 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
12739 retries++;
12740 else
12741 cmd = 't';
12742 }
12743 }
12744 if (retries >= 3) {
12745 return 0;
12746 }
12747
12748 } else {
12749 if (option_verbose > 2)
12750 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
12751 ast_copy_string(destination, num, sizeof(destination));
12752 }
12753
12754 if (!ast_strlen_zero(destination)) {
12755 if (destination[strlen(destination) -1 ] == '*')
12756 return 0;
12757 if (option_verbose > 2)
12758 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
12759 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
12760 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
12761 chan->priority = 0;
12762 return 9;
12763 }
12764 return 0;
12765 }
12766
12767
12768
12769
12770
12771
12772
12773
12774
12775
12776
12777
12778
12779
12780 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)
12781 {
12782 int res = 0;
12783 char filename[PATH_MAX];
12784 struct ast_config *msg_cfg = NULL;
12785 const char *origtime, *context;
12786 char *name, *num;
12787 int retries = 0;
12788 char *cid;
12789 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
12790
12791 vms->starting = 0;
12792
12793 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12794
12795
12796 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
12797 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
12798 msg_cfg = ast_config_load(filename, config_flags);
12799 DISPOSE(vms->curdir, vms->curmsg);
12800 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
12801 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
12802 return 0;
12803 }
12804
12805 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
12806 ast_config_destroy(msg_cfg);
12807 return 0;
12808 }
12809
12810 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
12811
12812 context = ast_variable_retrieve(msg_cfg, "message", "context");
12813 if (!strncasecmp("macro", context, 5))
12814 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
12815 switch (option) {
12816 case 3:
12817 if (!res)
12818 res = play_message_datetime(chan, vmu, origtime, filename);
12819 if (!res)
12820 res = play_message_callerid(chan, vms, cid, context, 0);
12821
12822 res = 't';
12823 break;
12824
12825 case 2:
12826
12827 if (ast_strlen_zero(cid))
12828 break;
12829
12830 ast_callerid_parse(cid, &name, &num);
12831 while ((res > -1) && (res != 't')) {
12832 switch (res) {
12833 case '1':
12834 if (num) {
12835
12836 res = dialout(chan, vmu, num, vmu->callback);
12837 if (res) {
12838 ast_config_destroy(msg_cfg);
12839 return 9;
12840 }
12841 } else {
12842 res = '2';
12843 }
12844 break;
12845
12846 case '2':
12847
12848 if (!ast_strlen_zero(vmu->dialout)) {
12849 res = dialout(chan, vmu, NULL, vmu->dialout);
12850 if (res) {
12851 ast_config_destroy(msg_cfg);
12852 return 9;
12853 }
12854 } else {
12855 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
12856 res = ast_play_and_wait(chan, "vm-sorry");
12857 }
12858 ast_config_destroy(msg_cfg);
12859 return res;
12860 case '*':
12861 res = 't';
12862 break;
12863 case '3':
12864 case '4':
12865 case '5':
12866 case '6':
12867 case '7':
12868 case '8':
12869 case '9':
12870 case '0':
12871
12872 res = ast_play_and_wait(chan, "vm-sorry");
12873 retries++;
12874 break;
12875 default:
12876 if (num) {
12877 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
12878 res = ast_play_and_wait(chan, "vm-num-i-have");
12879 if (!res)
12880 res = play_message_callerid(chan, vms, num, vmu->context, 1);
12881 if (!res)
12882 res = ast_play_and_wait(chan, "vm-tocallnum");
12883
12884 if (!ast_strlen_zero(vmu->dialout)) {
12885 if (!res)
12886 res = ast_play_and_wait(chan, "vm-calldiffnum");
12887 }
12888 } else {
12889 res = ast_play_and_wait(chan, "vm-nonumber");
12890 if (!ast_strlen_zero(vmu->dialout)) {
12891 if (!res)
12892 res = ast_play_and_wait(chan, "vm-toenternumber");
12893 }
12894 }
12895 if (!res)
12896 res = ast_play_and_wait(chan, "vm-star-cancel");
12897 if (!res)
12898 res = ast_waitfordigit(chan, 6000);
12899 if (!res) {
12900 retries++;
12901 if (retries > 3)
12902 res = 't';
12903 }
12904 break;
12905
12906 }
12907 if (res == 't')
12908 res = 0;
12909 else if (res == '*')
12910 res = -1;
12911 }
12912 break;
12913
12914 case 1:
12915
12916 if (ast_strlen_zero(cid))
12917 break;
12918
12919 ast_callerid_parse(cid, &name, &num);
12920 if (!num) {
12921 ast_verb(3, "No CID number available, no reply sent\n");
12922 if (!res)
12923 res = ast_play_and_wait(chan, "vm-nonumber");
12924 ast_config_destroy(msg_cfg);
12925 return res;
12926 } else {
12927 struct ast_vm_user vmu2;
12928 if (find_user(&vmu2, vmu->context, num)) {
12929 struct leave_vm_options leave_options;
12930 char mailbox[AST_MAX_EXTENSION * 2 + 2];
12931 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
12932
12933 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
12934
12935 memset(&leave_options, 0, sizeof(leave_options));
12936 leave_options.record_gain = record_gain;
12937 res = leave_voicemail(chan, mailbox, &leave_options);
12938 if (!res)
12939 res = 't';
12940 ast_config_destroy(msg_cfg);
12941 return res;
12942 } else {
12943
12944 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
12945 ast_play_and_wait(chan, "vm-nobox");
12946 res = 't';
12947 ast_config_destroy(msg_cfg);
12948 return res;
12949 }
12950 }
12951 res = 0;
12952
12953 break;
12954 }
12955
12956 #ifndef IMAP_STORAGE
12957 ast_config_destroy(msg_cfg);
12958
12959 if (!res) {
12960 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
12961 vms->heard[msg] = 1;
12962 res = wait_file(chan, vms, vms->fn);
12963 }
12964 #endif
12965 return res;
12966 }
12967
12968 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
12969 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
12970 signed char record_gain, struct vm_state *vms, char *flag)
12971 {
12972
12973 int res = 0;
12974 int cmd = 0;
12975 int max_attempts = 3;
12976 int attempts = 0;
12977 int recorded = 0;
12978 int msg_exists = 0;
12979 signed char zero_gain = 0;
12980 char tempfile[PATH_MAX];
12981 char *acceptdtmf = "#";
12982 char *canceldtmf = "";
12983 int canceleddtmf = 0;
12984
12985
12986
12987
12988 if (duration == NULL) {
12989 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
12990 return -1;
12991 }
12992
12993 if (!outsidecaller)
12994 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
12995 else
12996 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
12997
12998 cmd = '3';
12999
13000 while ((cmd >= 0) && (cmd != 't')) {
13001 switch (cmd) {
13002 case '1':
13003 if (!msg_exists) {
13004
13005 cmd = '3';
13006 break;
13007 } else {
13008
13009 ast_verb(3, "Saving message as is\n");
13010 if (!outsidecaller)
13011 ast_filerename(tempfile, recordfile, NULL);
13012 ast_stream_and_wait(chan, "vm-msgsaved", "");
13013 if (!outsidecaller) {
13014
13015 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13016 DISPOSE(recordfile, -1);
13017 }
13018 cmd = 't';
13019 return res;
13020 }
13021 case '2':
13022
13023 ast_verb(3, "Reviewing the message\n");
13024 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13025 break;
13026 case '3':
13027 msg_exists = 0;
13028
13029 if (recorded == 1)
13030 ast_verb(3, "Re-recording the message\n");
13031 else
13032 ast_verb(3, "Recording the message\n");
13033
13034 if (recorded && outsidecaller) {
13035 cmd = ast_play_and_wait(chan, INTRO);
13036 cmd = ast_play_and_wait(chan, "beep");
13037 }
13038 recorded = 1;
13039
13040 if (record_gain)
13041 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13042 if (ast_test_flag(vmu, VM_OPERATOR))
13043 canceldtmf = "0";
13044 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13045 if (strchr(canceldtmf, cmd)) {
13046
13047 canceleddtmf = 1;
13048 }
13049 if (record_gain)
13050 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13051 if (cmd == -1) {
13052
13053 if (!outsidecaller) {
13054
13055 ast_filedelete(tempfile, NULL);
13056 }
13057 return cmd;
13058 }
13059 if (cmd == '0') {
13060 break;
13061 } else if (cmd == '*') {
13062 break;
13063 #if 0
13064 } else if (vmu->review && (*duration < 5)) {
13065
13066 ast_verb(3, "Message too short\n");
13067 cmd = ast_play_and_wait(chan, "vm-tooshort");
13068 cmd = ast_filedelete(tempfile, NULL);
13069 break;
13070 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
13071
13072 ast_verb(3, "Nothing recorded\n");
13073 cmd = ast_filedelete(tempfile, NULL);
13074 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13075 if (!cmd)
13076 cmd = ast_play_and_wait(chan, "vm-speakup");
13077 break;
13078 #endif
13079 } else {
13080
13081 msg_exists = 1;
13082 cmd = 0;
13083 }
13084 break;
13085 case '4':
13086 if (outsidecaller) {
13087
13088 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13089 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13090 res = ast_play_and_wait(chan, "vm-marked-urgent");
13091 strcpy(flag, "Urgent");
13092 } else if (flag) {
13093 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13094 res = ast_play_and_wait(chan, "vm-urgent-removed");
13095 strcpy(flag, "");
13096 } else {
13097 ast_play_and_wait(chan, "vm-sorry");
13098 }
13099 cmd = 0;
13100 } else {
13101 cmd = ast_play_and_wait(chan, "vm-sorry");
13102 }
13103 break;
13104 case '5':
13105 case '6':
13106 case '7':
13107 case '8':
13108 case '9':
13109 case '*':
13110 case '#':
13111 cmd = ast_play_and_wait(chan, "vm-sorry");
13112 break;
13113 #if 0
13114
13115
13116 case '*':
13117
13118 cmd = ast_play_and_wait(chan, "vm-deleted");
13119 cmd = ast_filedelete(tempfile, NULL);
13120 if (outsidecaller) {
13121 res = vm_exec(chan, NULL);
13122 return res;
13123 }
13124 else
13125 return 1;
13126 #endif
13127 case '0':
13128 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13129 cmd = ast_play_and_wait(chan, "vm-sorry");
13130 break;
13131 }
13132 if (msg_exists || recorded) {
13133 cmd = ast_play_and_wait(chan, "vm-saveoper");
13134 if (!cmd)
13135 cmd = ast_waitfordigit(chan, 3000);
13136 if (cmd == '1') {
13137 ast_filerename(tempfile, recordfile, NULL);
13138 ast_play_and_wait(chan, "vm-msgsaved");
13139 cmd = '0';
13140 } else if (cmd == '4') {
13141 if (flag) {
13142 ast_play_and_wait(chan, "vm-marked-urgent");
13143 strcpy(flag, "Urgent");
13144 }
13145 ast_play_and_wait(chan, "vm-msgsaved");
13146 cmd = '0';
13147 } else {
13148 ast_play_and_wait(chan, "vm-deleted");
13149 DELETE(tempfile, -1, tempfile, vmu);
13150 cmd = '0';
13151 }
13152 }
13153 return cmd;
13154 default:
13155
13156
13157
13158 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13159 return cmd;
13160 if (msg_exists) {
13161 cmd = ast_play_and_wait(chan, "vm-review");
13162 if (!cmd && outsidecaller) {
13163 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13164 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13165 } else if (flag) {
13166 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13167 }
13168 }
13169 } else {
13170 cmd = ast_play_and_wait(chan, "vm-torerecord");
13171 if (!cmd)
13172 cmd = ast_waitfordigit(chan, 600);
13173 }
13174
13175 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13176 cmd = ast_play_and_wait(chan, "vm-reachoper");
13177 if (!cmd)
13178 cmd = ast_waitfordigit(chan, 600);
13179 }
13180 #if 0
13181 if (!cmd)
13182 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13183 #endif
13184 if (!cmd)
13185 cmd = ast_waitfordigit(chan, 6000);
13186 if (!cmd) {
13187 attempts++;
13188 }
13189 if (attempts > max_attempts) {
13190 cmd = 't';
13191 }
13192 }
13193 }
13194 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13195
13196 ast_filedelete(tempfile, NULL);
13197 }
13198
13199 if (cmd != 't' && outsidecaller)
13200 ast_play_and_wait(chan, "vm-goodbye");
13201
13202 return cmd;
13203 }
13204
13205
13206
13207
13208
13209 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13210 .load = load_module,
13211 .unload = unload_module,
13212 .reload = reload,
13213 .nonoptreq = "res_adsi,res_smdi",
13214 );