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