00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #include "asterisk.h"
00072
00073 #ifdef IMAP_STORAGE
00074 #include <ctype.h>
00075 #include <signal.h>
00076 #include <pwd.h>
00077 #ifdef USE_SYSTEM_IMAP
00078 #include <imap/c-client.h>
00079 #include <imap/imap4r1.h>
00080 #include <imap/linkage.h>
00081 #elif defined (USE_SYSTEM_CCLIENT)
00082 #include <c-client/c-client.h>
00083 #include <c-client/imap4r1.h>
00084 #include <c-client/linkage.h>
00085 #else
00086 #include "c-client.h"
00087 #include "imap4r1.h"
00088 #include "linkage.h"
00089 #endif
00090 #endif
00091
00092 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 200945 $")
00093
00094 #include "asterisk/paths.h"
00095 #include <sys/time.h>
00096 #include <sys/stat.h>
00097 #include <sys/mman.h>
00098 #include <time.h>
00099 #include <dirent.h>
00100
00101 #include "asterisk/logger.h"
00102 #include "asterisk/lock.h"
00103 #include "asterisk/file.h"
00104 #include "asterisk/channel.h"
00105 #include "asterisk/pbx.h"
00106 #include "asterisk/config.h"
00107 #include "asterisk/say.h"
00108 #include "asterisk/module.h"
00109 #include "asterisk/adsi.h"
00110 #include "asterisk/app.h"
00111 #include "asterisk/manager.h"
00112 #include "asterisk/dsp.h"
00113 #include "asterisk/localtime.h"
00114 #include "asterisk/cli.h"
00115 #include "asterisk/utils.h"
00116 #include "asterisk/stringfields.h"
00117 #include "asterisk/smdi.h"
00118 #include "asterisk/event.h"
00119
00120 #ifdef ODBC_STORAGE
00121 #include "asterisk/res_odbc.h"
00122 #endif
00123
00124 #ifdef IMAP_STORAGE
00125 #include "asterisk/threadstorage.h"
00126
00127 static char imapserver[48];
00128 static char imapport[8];
00129 static char imapflags[128];
00130 static char imapfolder[64];
00131 static char imapparentfolder[64] = "\0";
00132 static char greetingfolder[64];
00133 static char authuser[32];
00134 static char authpassword[42];
00135
00136 static int expungeonhangup = 1;
00137 static int imapgreetings = 0;
00138 static char delimiter = '\0';
00139
00140 struct vm_state;
00141 struct ast_vm_user;
00142
00143 AST_THREADSTORAGE(ts_vmstate);
00144
00145
00146 static int init_mailstream(struct vm_state *vms, int box);
00147 static void write_file(char *filename, char *buffer, unsigned long len);
00148 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00149 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu);
00150 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00151 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00152 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive);
00153 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00154 static void vmstate_insert(struct vm_state *vms);
00155 static void vmstate_delete(struct vm_state *vms);
00156 static void set_update(MAILSTREAM * stream);
00157 static void init_vm_state(struct vm_state *vms);
00158 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format);
00159 static void get_mailbox_delimiter(MAILSTREAM *stream);
00160 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00161 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00162 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms);
00163 static void update_messages_by_imapuser(const char *user, unsigned long number);
00164
00165 static int imap_remove_file (char *dir, int msgnum);
00166 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00167 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00168 static void check_quota(struct vm_state *vms, char *mailbox);
00169 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00170 struct vmstate {
00171 struct vm_state *vms;
00172 AST_LIST_ENTRY(vmstate) list;
00173 };
00174
00175 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00176
00177 #endif
00178
00179 #define SMDI_MWI_WAIT_TIMEOUT 1000
00180
00181 #define COMMAND_TIMEOUT 5000
00182
00183 #define VOICEMAIL_DIR_MODE 0777
00184 #define VOICEMAIL_FILE_MODE 0666
00185 #define CHUNKSIZE 65536
00186
00187 #define VOICEMAIL_CONFIG "voicemail.conf"
00188 #define ASTERISK_USERNAME "asterisk"
00189
00190
00191
00192
00193 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00194 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00195 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00196 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00197 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00198 #define VALID_DTMF "1234567890*#"
00199
00200
00201
00202 #define SENDMAIL "/usr/sbin/sendmail -t"
00203
00204 #define INTRO "vm-intro"
00205
00206 #define MAXMSG 100
00207 #define MAXMSGLIMIT 9999
00208
00209 #define BASELINELEN 72
00210 #define BASEMAXINLINE 256
00211 #define eol "\r\n"
00212
00213 #define MAX_DATETIME_FORMAT 512
00214 #define MAX_NUM_CID_CONTEXTS 10
00215
00216 #define VM_REVIEW (1 << 0)
00217 #define VM_OPERATOR (1 << 1)
00218 #define VM_SAYCID (1 << 2)
00219 #define VM_SVMAIL (1 << 3)
00220 #define VM_ENVELOPE (1 << 4)
00221 #define VM_SAYDURATION (1 << 5)
00222 #define VM_SKIPAFTERCMD (1 << 6)
00223 #define VM_FORCENAME (1 << 7)
00224 #define VM_FORCEGREET (1 << 8)
00225 #define VM_PBXSKIP (1 << 9)
00226 #define VM_DIRECFORWARD (1 << 10)
00227 #define VM_ATTACH (1 << 11)
00228 #define VM_DELETE (1 << 12)
00229 #define VM_ALLOCED (1 << 13)
00230 #define VM_SEARCH (1 << 14)
00231 #define VM_TEMPGREETWARN (1 << 15)
00232 #define VM_MOVEHEARD (1 << 16)
00233 #define ERROR_LOCK_PATH -100
00234 #define ERROR_MAILBOX_FULL -200
00235
00236
00237 enum {
00238 NEW_FOLDER,
00239 OLD_FOLDER,
00240 WORK_FOLDER,
00241 FAMILY_FOLDER,
00242 FRIENDS_FOLDER,
00243 GREETINGS_FOLDER
00244 } vm_box;
00245
00246 enum {
00247 OPT_SILENT = (1 << 0),
00248 OPT_BUSY_GREETING = (1 << 1),
00249 OPT_UNAVAIL_GREETING = (1 << 2),
00250 OPT_RECORDGAIN = (1 << 3),
00251 OPT_PREPEND_MAILBOX = (1 << 4),
00252 OPT_AUTOPLAY = (1 << 6),
00253 OPT_DTMFEXIT = (1 << 7),
00254 } vm_option_flags;
00255
00256 enum {
00257 OPT_ARG_RECORDGAIN = 0,
00258 OPT_ARG_PLAYFOLDER = 1,
00259 OPT_ARG_DTMFEXIT = 2,
00260
00261 OPT_ARG_ARRAY_SIZE = 3,
00262 } vm_option_args;
00263
00264 AST_APP_OPTIONS(vm_app_options, {
00265 AST_APP_OPTION('s', OPT_SILENT),
00266 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00267 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00268 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00269 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00270 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00271 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00272 });
00273
00274 static int load_config(int reload);
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 struct baseio {
00360 int iocp;
00361 int iolen;
00362 int linelength;
00363 int ateof;
00364 unsigned char iobuf[BASEMAXINLINE];
00365 };
00366
00367
00368
00369 struct ast_vm_user {
00370 char context[AST_MAX_CONTEXT];
00371 char mailbox[AST_MAX_EXTENSION];
00372 char password[80];
00373 char fullname[80];
00374 char email[80];
00375 char pager[80];
00376 char serveremail[80];
00377 char mailcmd[160];
00378 char language[MAX_LANGUAGE];
00379 char zonetag[80];
00380 char callback[80];
00381 char dialout[80];
00382 char uniqueid[80];
00383 char exit[80];
00384 char attachfmt[20];
00385 unsigned int flags;
00386 int saydurationm;
00387 int maxmsg;
00388 int maxdeletedmsg;
00389 int maxsecs;
00390 #ifdef IMAP_STORAGE
00391 char imapuser[80];
00392 char imappassword[80];
00393 char imapvmshareid[80];
00394 #endif
00395 double volgain;
00396 AST_LIST_ENTRY(ast_vm_user) list;
00397 };
00398
00399
00400 struct vm_zone {
00401 AST_LIST_ENTRY(vm_zone) list;
00402 char name[80];
00403 char timezone[80];
00404 char msg_format[512];
00405 };
00406
00407
00408 struct vm_state {
00409 char curbox[80];
00410 char username[80];
00411 char curdir[PATH_MAX];
00412 char vmbox[PATH_MAX];
00413 char fn[PATH_MAX];
00414 char fn2[PATH_MAX];
00415 int *deleted;
00416 int *heard;
00417 int curmsg;
00418 int lastmsg;
00419 int newmessages;
00420 int oldmessages;
00421 int starting;
00422 int repeats;
00423 #ifdef IMAP_STORAGE
00424 ast_mutex_t lock;
00425 int updated;
00426 long msgArray[256];
00427 MAILSTREAM *mailstream;
00428 int vmArrayIndex;
00429 char imapuser[80];
00430 int interactive;
00431 unsigned int quota_limit;
00432 unsigned int quota_usage;
00433 struct vm_state *persist_vms;
00434 #endif
00435 };
00436
00437 #ifdef ODBC_STORAGE
00438 static char odbc_database[80];
00439 static char odbc_table[80];
00440 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00441 #define DISPOSE(a,b) remove_file(a,b)
00442 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
00443 #define EXISTS(a,b,c,d) (message_exists(a,b))
00444 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00445 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00446 #define DELETE(a,b,c,d) (delete_file(a,b))
00447 #else
00448 #ifdef IMAP_STORAGE
00449 #define DISPOSE(a,b) (imap_remove_file(a,b))
00450 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
00451 #define EXISTS(a,b,c,d) (ast_fileexists(c, NULL, d) > 0)
00452 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00453 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00454 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00455 #define DELETE(a,b,c,d) (vm_imap_delete(b,d))
00456 #else
00457 #define RETRIEVE(a,b,c,d)
00458 #define DISPOSE(a,b)
00459 #define STORE(a,b,c,d,e,f,g,h,i)
00460 #define EXISTS(a,b,c,d) (ast_fileexists(c, NULL, d) > 0)
00461 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00462 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00463 #define DELETE(a,b,c,d) (vm_delete(c))
00464 #endif
00465 #endif
00466
00467 static char VM_SPOOL_DIR[PATH_MAX];
00468
00469 static char ext_pass_cmd[128];
00470
00471 static int my_umask;
00472
00473 #define PWDCHANGE_INTERNAL (1 << 1)
00474 #define PWDCHANGE_EXTERNAL (1 << 2)
00475 static int pwdchange = PWDCHANGE_INTERNAL;
00476
00477 #ifdef ODBC_STORAGE
00478 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00479 #else
00480 # ifdef IMAP_STORAGE
00481 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00482 # else
00483 # define tdesc "Comedian Mail (Voicemail System)"
00484 # endif
00485 #endif
00486
00487 static char userscontext[AST_MAX_EXTENSION] = "default";
00488
00489 static char *addesc = "Comedian Mail";
00490
00491 static char *synopsis_vm = "Leave a Voicemail message";
00492
00493 static char *descrip_vm =
00494 " VoiceMail(mailbox[@context][&mailbox[@context]][...][,options]): This\n"
00495 "application allows the calling party to leave a message for the specified\n"
00496 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00497 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00498 "specified mailbox does not exist.\n"
00499 " The Voicemail application will exit if any of the following DTMF digits are\n"
00500 "received:\n"
00501 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00502 " * - Jump to the 'a' extension in the current dialplan context.\n"
00503 " This application will set the following channel variable upon completion:\n"
00504 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00505 " application. The possible values are:\n"
00506 " SUCCESS | USEREXIT | FAILED\n\n"
00507 " Options:\n"
00508 " b - Play the 'busy' greeting to the calling party.\n"
00509 " d([c]) - Accept digits for a new extension in context c, if played during\n"
00510 " the greeting. Context defaults to the current context.\n"
00511 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00512 " message. The units are whole-number decibels (dB).\n"
00513 " Only works on supported technologies, which is DAHDI only.\n"
00514 " s - Skip the playback of instructions for leaving a message to the\n"
00515 " calling party.\n"
00516 " u - Play the 'unavailable' greeting.\n";
00517
00518 static char *synopsis_vmain = "Check Voicemail messages";
00519
00520 static char *descrip_vmain =
00521 " VoiceMailMain([mailbox][@context][,options]): This application allows the\n"
00522 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00523 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00524 "calling party will be prompted to enter one. If a context is not specified,\n"
00525 "the 'default' context will be used.\n\n"
00526 " Options:\n"
00527 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00528 " is entered by the caller.\n"
00529 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00530 " message. The units are whole-number decibels (dB).\n"
00531 " s - Skip checking the passcode for the mailbox.\n"
00532 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00533 " Defaults to INBOX\n";
00534
00535 static char *synopsis_vm_box_exists =
00536 "Check to see if Voicemail mailbox exists";
00537
00538 static char *descrip_vm_box_exists =
00539 " MailboxExists(mailbox[@context][,options]): Check to see if the specified\n"
00540 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00541 "will be used.\n"
00542 " This application will set the following channel variable upon completion:\n"
00543 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00544 " MailboxExists application. Possible values include:\n"
00545 " SUCCESS | FAILED\n\n"
00546 " Options: (none)\n";
00547
00548 static char *synopsis_vmauthenticate = "Authenticate with Voicemail passwords";
00549
00550 static char *descrip_vmauthenticate =
00551 " VMAuthenticate([mailbox][@context][,options]): This application behaves the\n"
00552 "same way as the Authenticate application, but the passwords are taken from\n"
00553 "voicemail.conf.\n"
00554 " If the mailbox is specified, only that mailbox's password will be considered\n"
00555 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00556 "be set with the authenticated mailbox.\n\n"
00557 " Options:\n"
00558 " s - Skip playing the initial prompts.\n";
00559
00560
00561 static char *app = "VoiceMail";
00562
00563
00564 static char *app2 = "VoiceMailMain";
00565
00566 static char *app3 = "MailboxExists";
00567 static char *app4 = "VMAuthenticate";
00568
00569 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00570 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00571 static char zonetag[80];
00572 static int maxsilence;
00573 static int maxmsg;
00574 static int maxdeletedmsg;
00575 static int silencethreshold = 128;
00576 static char serveremail[80];
00577 static char mailcmd[160];
00578 static char externnotify[160];
00579 static struct ast_smdi_interface *smdi_iface = NULL;
00580 static char vmfmts[80];
00581 static double volgain;
00582 static int vmminsecs;
00583 static int vmmaxsecs;
00584 static int maxgreet;
00585 static int skipms;
00586 static int maxlogins;
00587
00588
00589
00590 static unsigned int poll_mailboxes;
00591
00592
00593 static unsigned int poll_freq;
00594
00595 #define DEFAULT_POLL_FREQ 30
00596
00597 AST_MUTEX_DEFINE_STATIC(poll_lock);
00598 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00599 static pthread_t poll_thread = AST_PTHREADT_NULL;
00600 static unsigned char poll_thread_run;
00601
00602
00603 static struct ast_event_sub *mwi_sub_sub;
00604
00605 static struct ast_event_sub *mwi_unsub_sub;
00606
00607
00608
00609
00610
00611
00612
00613
00614 struct mwi_sub {
00615 AST_RWLIST_ENTRY(mwi_sub) entry;
00616 int old_new;
00617 int old_old;
00618 uint32_t uniqueid;
00619 char mailbox[1];
00620 };
00621
00622 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00623
00624
00625 static char listen_control_forward_key[12];
00626 static char listen_control_reverse_key[12];
00627 static char listen_control_pause_key[12];
00628 static char listen_control_restart_key[12];
00629 static char listen_control_stop_key[12];
00630
00631
00632 static char vm_password[80] = "vm-password";
00633 static char vm_newpassword[80] = "vm-newpassword";
00634 static char vm_passchanged[80] = "vm-passchanged";
00635 static char vm_reenterpassword[80] = "vm-reenterpassword";
00636 static char vm_mismatch[80] = "vm-mismatch";
00637
00638 static struct ast_flags globalflags = {0};
00639
00640 static int saydurationminfo;
00641
00642 static char dialcontext[AST_MAX_CONTEXT] = "";
00643 static char callcontext[AST_MAX_CONTEXT] = "";
00644 static char exitcontext[AST_MAX_CONTEXT] = "";
00645
00646 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00647
00648
00649 static char *emailbody = NULL;
00650 static char *emailsubject = NULL;
00651 static char *pagerbody = NULL;
00652 static char *pagersubject = NULL;
00653 static char fromstring[100];
00654 static char pagerfromstring[100];
00655 static char charset[32] = "ISO-8859-1";
00656
00657 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00658 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00659 static int adsiver = 1;
00660 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00661
00662
00663 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00664 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);
00665 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00666 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00667 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00668 signed char record_gain, struct vm_state *vms);
00669 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00670 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00671 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);
00672 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 *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap);
00673 static void apply_options(struct ast_vm_user *vmu, const char *options);
00674 static int is_valid_dtmf(const char *key);
00675
00676 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00677 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00678 #endif
00679
00680 static char *strip_control(const char *input, char *buf, size_t buflen)
00681 {
00682 char *bufptr = buf;
00683 for (; *input; input++) {
00684 if (*input < 32) {
00685 continue;
00686 }
00687 *bufptr++ = *input;
00688 if (bufptr == buf + buflen - 1) {
00689 break;
00690 }
00691 }
00692 *bufptr = '\0';
00693 return buf;
00694 }
00695
00696
00697 static void populate_defaults(struct ast_vm_user *vmu)
00698 {
00699 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00700 if (saydurationminfo)
00701 vmu->saydurationm = saydurationminfo;
00702 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00703 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00704 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00705 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00706 if (vmmaxsecs)
00707 vmu->maxsecs = vmmaxsecs;
00708 if (maxmsg)
00709 vmu->maxmsg = maxmsg;
00710 if (maxdeletedmsg)
00711 vmu->maxdeletedmsg = maxdeletedmsg;
00712 vmu->volgain = volgain;
00713 }
00714
00715 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00716 {
00717 int x;
00718 if (!strcasecmp(var, "attach")) {
00719 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00720 } else if (!strcasecmp(var, "attachfmt")) {
00721 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00722 } else if (!strcasecmp(var, "serveremail")) {
00723 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00724 } else if (!strcasecmp(var, "language")) {
00725 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00726 } else if (!strcasecmp(var, "tz")) {
00727 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00728 #ifdef IMAP_STORAGE
00729 } else if (!strcasecmp(var, "imapuser")) {
00730 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00731 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00732 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00733 } else if (!strcasecmp(var, "imapvmshareid")) {
00734 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
00735 #endif
00736 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00737 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00738 } else if (!strcasecmp(var, "saycid")) {
00739 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00740 } else if (!strcasecmp(var, "sendvoicemail")) {
00741 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00742 } else if (!strcasecmp(var, "review")) {
00743 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00744 } else if (!strcasecmp(var, "tempgreetwarn")) {
00745 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00746 } else if (!strcasecmp(var, "operator")) {
00747 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00748 } else if (!strcasecmp(var, "envelope")) {
00749 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00750 } else if (!strcasecmp(var, "moveheard")) {
00751 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
00752 } else if (!strcasecmp(var, "sayduration")) {
00753 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00754 } else if (!strcasecmp(var, "saydurationm")) {
00755 if (sscanf(value, "%d", &x) == 1) {
00756 vmu->saydurationm = x;
00757 } else {
00758 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
00759 }
00760 } else if (!strcasecmp(var, "forcename")) {
00761 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00762 } else if (!strcasecmp(var, "forcegreetings")) {
00763 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00764 } else if (!strcasecmp(var, "callback")) {
00765 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00766 } else if (!strcasecmp(var, "dialout")) {
00767 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00768 } else if (!strcasecmp(var, "exitcontext")) {
00769 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00770 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
00771 if (vmu->maxsecs <= 0) {
00772 ast_log(LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
00773 vmu->maxsecs = vmmaxsecs;
00774 } else {
00775 vmu->maxsecs = atoi(value);
00776 }
00777 if (!strcasecmp(var, "maxmessage"))
00778 ast_log(LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
00779 } else if (!strcasecmp(var, "maxmsg")) {
00780 vmu->maxmsg = atoi(value);
00781 if (vmu->maxmsg <= 0) {
00782 ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
00783 vmu->maxmsg = MAXMSG;
00784 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00785 ast_log(LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00786 vmu->maxmsg = MAXMSGLIMIT;
00787 }
00788 } else if (!strcasecmp(var, "backupdeleted")) {
00789 if (sscanf(value, "%d", &x) == 1)
00790 vmu->maxdeletedmsg = x;
00791 else if (ast_true(value))
00792 vmu->maxdeletedmsg = MAXMSG;
00793 else
00794 vmu->maxdeletedmsg = 0;
00795
00796 if (vmu->maxdeletedmsg < 0) {
00797 ast_log(LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
00798 vmu->maxdeletedmsg = MAXMSG;
00799 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
00800 ast_log(LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
00801 vmu->maxdeletedmsg = MAXMSGLIMIT;
00802 }
00803 } else if (!strcasecmp(var, "volgain")) {
00804 sscanf(value, "%lf", &vmu->volgain);
00805 } else if (!strcasecmp(var, "options")) {
00806 apply_options(vmu, value);
00807 }
00808 }
00809
00810 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
00811 {
00812 int res;
00813 if (!ast_strlen_zero(vmu->uniqueid)) {
00814 res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL);
00815 if (res > 0) {
00816 ast_copy_string(vmu->password, password, sizeof(vmu->password));
00817 res = 0;
00818 } else if (!res) {
00819 res = -1;
00820 }
00821 return res;
00822 }
00823 return -1;
00824 }
00825
00826 static void apply_options(struct ast_vm_user *vmu, const char *options)
00827 {
00828 char *stringp;
00829 char *s;
00830 char *var, *value;
00831 stringp = ast_strdupa(options);
00832 while ((s = strsep(&stringp, "|"))) {
00833 value = s;
00834 if ((var = strsep(&value, "=")) && value) {
00835 apply_option(vmu, var, value);
00836 }
00837 }
00838 }
00839
00840 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
00841 {
00842 struct ast_variable *tmp;
00843 tmp = var;
00844 while (tmp) {
00845 if (!strcasecmp(tmp->name, "vmsecret")) {
00846 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00847 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
00848 if (ast_strlen_zero(retval->password))
00849 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00850 } else if (!strcasecmp(tmp->name, "uniqueid")) {
00851 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
00852 } else if (!strcasecmp(tmp->name, "pager")) {
00853 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
00854 } else if (!strcasecmp(tmp->name, "email")) {
00855 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
00856 } else if (!strcasecmp(tmp->name, "fullname")) {
00857 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
00858 } else if (!strcasecmp(tmp->name, "context")) {
00859 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
00860 #ifdef IMAP_STORAGE
00861 } else if (!strcasecmp(tmp->name, "imapuser")) {
00862 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
00863 } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
00864 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
00865 } else if (!strcasecmp(tmp->name, "imapvmshareid")) {
00866 ast_copy_string(retval->imapvmshareid, tmp->value, sizeof(retval->imapvmshareid));
00867 #endif
00868 } else
00869 apply_option(retval, tmp->name, tmp->value);
00870 tmp = tmp->next;
00871 }
00872 }
00873
00874 static int is_valid_dtmf(const char *key)
00875 {
00876 int i;
00877 char *local_key = ast_strdupa(key);
00878
00879 for (i = 0; i < strlen(key); ++i) {
00880 if (!strchr(VALID_DTMF, *local_key)) {
00881 ast_log(LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
00882 return 0;
00883 }
00884 local_key++;
00885 }
00886 return 1;
00887 }
00888
00889 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00890 {
00891 struct ast_variable *var;
00892 struct ast_vm_user *retval;
00893
00894 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
00895 if (!ivm)
00896 ast_set_flag(retval, VM_ALLOCED);
00897 else
00898 memset(retval, 0, sizeof(*retval));
00899 if (mailbox)
00900 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
00901 populate_defaults(retval);
00902 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
00903 var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
00904 else
00905 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
00906 if (var) {
00907 apply_options_full(retval, var);
00908 ast_variables_destroy(var);
00909 } else {
00910 if (!ivm)
00911 ast_free(retval);
00912 retval = NULL;
00913 }
00914 }
00915 return retval;
00916 }
00917
00918 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00919 {
00920
00921 struct ast_vm_user *vmu = NULL, *cur;
00922 AST_LIST_LOCK(&users);
00923
00924 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
00925 context = "default";
00926
00927 AST_LIST_TRAVERSE(&users, cur, list) {
00928 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
00929 break;
00930 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
00931 break;
00932 }
00933 if (cur) {
00934
00935 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
00936 memcpy(vmu, cur, sizeof(*vmu));
00937 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
00938 AST_LIST_NEXT(vmu, list) = NULL;
00939 }
00940 } else
00941 vmu = find_user_realtime(ivm, context, mailbox);
00942 AST_LIST_UNLOCK(&users);
00943 return vmu;
00944 }
00945
00946 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
00947 {
00948
00949 struct ast_vm_user *cur;
00950 int res = -1;
00951 AST_LIST_LOCK(&users);
00952 AST_LIST_TRAVERSE(&users, cur, list) {
00953 if ((!context || !strcasecmp(context, cur->context)) &&
00954 (!strcasecmp(mailbox, cur->mailbox)))
00955 break;
00956 }
00957 if (cur) {
00958 ast_copy_string(cur->password, newpass, sizeof(cur->password));
00959 res = 0;
00960 }
00961 AST_LIST_UNLOCK(&users);
00962 return res;
00963 }
00964
00965 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
00966 {
00967 struct ast_config *cfg = NULL;
00968 struct ast_variable *var = NULL;
00969 struct ast_category *cat = NULL;
00970 char *category = NULL, *value = NULL, *new = NULL;
00971 const char *tmp = NULL;
00972 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
00973 if (!change_password_realtime(vmu, newpassword))
00974 return;
00975
00976
00977 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags))) {
00978 while ((category = ast_category_browse(cfg, category))) {
00979 if (!strcasecmp(category, vmu->context)) {
00980 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
00981 ast_log(LOG_WARNING, "We could not find the mailbox.\n");
00982 break;
00983 }
00984 value = strstr(tmp, ",");
00985 if (!value) {
00986 ast_log(LOG_WARNING, "variable has bad format.\n");
00987 break;
00988 }
00989 new = alloca(strlen(value) + strlen(newpassword) + 1);
00990 sprintf(new, "%s%s", newpassword, value);
00991 if (!(cat = ast_category_get(cfg, category))) {
00992 ast_log(LOG_WARNING, "Failed to get category structure.\n");
00993 break;
00994 }
00995 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
00996 }
00997 }
00998
00999 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01000 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01001 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01002 }
01003 category = NULL;
01004 var = NULL;
01005
01006
01007 if ((cfg = ast_config_load("users.conf", config_flags))) {
01008 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01009 while ((category = ast_category_browse(cfg, category))) {
01010 ast_debug(4, "users.conf: %s\n", category);
01011 if (!strcasecmp(category, vmu->mailbox)) {
01012 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01013 ast_debug(3, "looks like we need to make vmsecret!\n");
01014 var = ast_variable_new("vmsecret", newpassword, "");
01015 }
01016 new = alloca(strlen(newpassword) + 1);
01017 sprintf(new, "%s", newpassword);
01018 if (!(cat = ast_category_get(cfg, category))) {
01019 ast_debug(4, "failed to get category!\n");
01020 break;
01021 }
01022 if (!var)
01023 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01024 else
01025 ast_variable_append(cat, var);
01026 }
01027 }
01028
01029 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01030 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01031 config_text_file_save("users.conf", cfg, "AppVoicemail");
01032 }
01033 }
01034
01035 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01036 {
01037 char buf[255];
01038 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01039 if (!ast_safe_system(buf)) {
01040 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01041
01042 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01043 }
01044 }
01045
01046 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01047 {
01048 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01049 }
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061 static int make_file(char *dest, const int len, const char *dir, const int num)
01062 {
01063 return snprintf(dest, len, "%s/msg%04d", dir, num);
01064 }
01065
01066
01067 static FILE *vm_mkftemp(char *template)
01068 {
01069 FILE *p = NULL;
01070 int pfd = mkstemp(template);
01071 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01072 if (pfd > -1) {
01073 p = fdopen(pfd, "w+");
01074 if (!p) {
01075 close(pfd);
01076 pfd = -1;
01077 }
01078 }
01079 return p;
01080 }
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01091 {
01092 mode_t mode = VOICEMAIL_DIR_MODE;
01093 int res;
01094
01095 make_dir(dest, len, context, ext, folder);
01096 if ((res = ast_mkdir(dest, mode))) {
01097 ast_log(LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01098 return -1;
01099 }
01100 return 0;
01101 }
01102
01103 static const char *mbox(int id)
01104 {
01105 static const char *msgs[] = {
01106 #ifdef IMAP_STORAGE
01107 imapfolder,
01108 #else
01109 "INBOX",
01110 #endif
01111 "Old",
01112 "Work",
01113 "Family",
01114 "Friends",
01115 "Cust1",
01116 "Cust2",
01117 "Cust3",
01118 "Cust4",
01119 "Cust5",
01120 "Deleted",
01121 "Urgent"
01122 };
01123 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown";
01124 }
01125
01126 static void free_user(struct ast_vm_user *vmu)
01127 {
01128 if (ast_test_flag(vmu, VM_ALLOCED))
01129 ast_free(vmu);
01130 }
01131
01132
01133
01134 #ifdef IMAP_STORAGE
01135 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu)
01136 {
01137 char arg[10];
01138 struct vm_state *vms;
01139 unsigned long messageNum;
01140
01141
01142 if (msgnum < 0) {
01143 return;
01144 }
01145
01146 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, 0))) {
01147 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);
01148 return;
01149 }
01150
01151
01152
01153 messageNum = vms->msgArray[msgnum];
01154 if (messageNum == 0) {
01155 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01156 return;
01157 }
01158 ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01159
01160 snprintf(arg, sizeof(arg), "%lu", messageNum);
01161 ast_mutex_lock(&vms->lock);
01162 mail_setflag(vms->mailstream, arg, "\\DELETED");
01163 ast_mutex_unlock(&vms->lock);
01164 }
01165
01166 static int imap_retrieve_greeting (const char *dir, const int msgnum, struct ast_vm_user *vmu)
01167 {
01168 struct vm_state *vms_p;
01169 char *file, *filename;
01170 char *attachment;
01171 int ret = 0, i;
01172 BODY *body;
01173
01174
01175
01176
01177 if (msgnum > -1 || !imapgreetings) {
01178 return 0;
01179 } else {
01180 file = strrchr(ast_strdupa(dir), '/');
01181 if (file)
01182 *file++ = '\0';
01183 else {
01184 ast_debug (1, "Failed to procure file name from directory passed.\n");
01185 return -1;
01186 }
01187 }
01188
01189
01190 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, 1)) ||!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, 0))) {
01191 ast_log(LOG_ERROR, "Voicemail state not found!\n");
01192 return -1;
01193 }
01194
01195 ast_mutex_lock(&vms_p->lock);
01196 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01197 if (!vms_p->mailstream) {
01198 ast_log(LOG_ERROR, "IMAP mailstream is NULL\n");
01199 ast_mutex_unlock(&vms_p->lock);
01200 return -1;
01201 }
01202
01203
01204 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01205 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01206
01207 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01208 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01209 } else {
01210 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01211 ast_mutex_unlock(&vms_p->lock);
01212 return -1;
01213 }
01214 filename = strsep(&attachment, ".");
01215 if (!strcmp(filename, file)) {
01216 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01217 vms_p->msgArray[vms_p->curmsg] = i + 1;
01218 save_body(body, vms_p, "2", attachment);
01219 ast_mutex_unlock(&vms_p->lock);
01220 return 0;
01221 }
01222 }
01223 ast_mutex_unlock(&vms_p->lock);
01224
01225 return -1;
01226 }
01227
01228 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01229 {
01230 BODY *body;
01231 char *header_content;
01232 char *attachedfilefmt;
01233 char buf[80];
01234 struct vm_state *vms;
01235 char text_file[PATH_MAX];
01236 FILE *text_file_ptr;
01237 int res = 0;
01238 struct ast_vm_user *vmu;
01239
01240 if (!(vmu = find_user(NULL, context, mailbox))) {
01241 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01242 return -1;
01243 }
01244
01245 if (msgnum < 0) {
01246 if (imapgreetings) {
01247 res = imap_retrieve_greeting(dir, msgnum, vmu);
01248 goto exit;
01249 } else {
01250 res = 0;
01251 goto exit;
01252 }
01253 }
01254
01255
01256
01257
01258 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, 0))) {
01259
01260
01261
01262
01263
01264
01265
01266 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01267 res = -1;
01268 goto exit;
01269 }
01270
01271 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01272
01273
01274 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01275 res = 0;
01276 goto exit;
01277 }
01278
01279 if (option_debug > 2)
01280 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01281 if (vms->msgArray[msgnum] == 0) {
01282 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01283 res = -1;
01284 goto exit;
01285 }
01286
01287
01288 ast_mutex_lock(&vms->lock);
01289 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01290 ast_mutex_unlock(&vms->lock);
01291
01292 if (ast_strlen_zero(header_content)) {
01293 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01294 res = -1;
01295 goto exit;
01296 }
01297
01298 ast_mutex_lock(&vms->lock);
01299 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01300 ast_mutex_unlock(&vms->lock);
01301
01302
01303 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01304 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01305 } else {
01306 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01307 res = -1;
01308 goto exit;
01309 }
01310
01311
01312
01313 strsep(&attachedfilefmt, ".");
01314 if (!attachedfilefmt) {
01315 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01316 res = -1;
01317 goto exit;
01318 }
01319
01320 save_body(body, vms, "2", attachedfilefmt);
01321
01322
01323 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01324
01325 if (!(text_file_ptr = fopen(text_file, "w"))) {
01326 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01327 }
01328
01329 fprintf(text_file_ptr, "%s\n", "[message]");
01330
01331 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01332 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01333 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01334 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01335 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01336 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01337 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01338 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01339 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01340 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01341 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01342 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01343 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01344 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01345 fclose(text_file_ptr);
01346
01347 exit:
01348 free_user(vmu);
01349 return res;
01350 }
01351
01352 static int folder_int(const char *folder)
01353 {
01354
01355 if (!folder)
01356 return 0;
01357 if (!strcasecmp(folder, imapfolder))
01358 return 0;
01359 else if (!strcasecmp(folder, "Old"))
01360 return 1;
01361 else if (!strcasecmp(folder, "Work"))
01362 return 2;
01363 else if (!strcasecmp(folder, "Family"))
01364 return 3;
01365 else if (!strcasecmp(folder, "Friends"))
01366 return 4;
01367 else if (!strcasecmp(folder, "Cust1"))
01368 return 5;
01369 else if (!strcasecmp(folder, "Cust2"))
01370 return 6;
01371 else if (!strcasecmp(folder, "Cust3"))
01372 return 7;
01373 else if (!strcasecmp(folder, "Cust4"))
01374 return 8;
01375 else if (!strcasecmp(folder, "Cust5"))
01376 return 9;
01377 else
01378 return 0;
01379 }
01380
01381 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms)
01382 {
01383 char *myserveremail = serveremail;
01384 char fn[PATH_MAX];
01385 char mailbox[256];
01386 char *stringp;
01387 FILE *p = NULL;
01388 char tmp[80] = "/tmp/astmail-XXXXXX";
01389 long len;
01390 void *buf;
01391 int tempcopy = 0;
01392 STRING str;
01393
01394
01395 fmt = ast_strdupa(fmt);
01396 stringp = fmt;
01397 strsep(&stringp, "|");
01398
01399 if (!ast_strlen_zero(vmu->serveremail))
01400 myserveremail = vmu->serveremail;
01401
01402 if (msgnum > -1)
01403 make_file(fn, sizeof(fn), dir, msgnum);
01404 else
01405 ast_copy_string (fn, dir, sizeof(fn));
01406
01407 if (ast_strlen_zero(vmu->email)) {
01408
01409
01410
01411
01412
01413 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01414 tempcopy = 1;
01415 }
01416
01417 if (!strcmp(fmt, "wav49"))
01418 fmt = "WAV";
01419 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
01420
01421
01422
01423 if (!(p = vm_mkftemp(tmp))) {
01424 ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01425 if (tempcopy)
01426 *(vmu->email) = '\0';
01427 return -1;
01428 }
01429
01430 if (msgnum < 0 && imapgreetings) {
01431 init_mailstream(vms, GREETINGS_FOLDER);
01432 imap_delete_old_greeting(fn, vms);
01433 }
01434
01435 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX", S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1);
01436
01437 len = ftell(p);
01438 rewind(p);
01439 if (!(buf = ast_malloc(len + 1))) {
01440 ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
01441 fclose(p);
01442 if (tempcopy)
01443 *(vmu->email) = '\0';
01444 return -1;
01445 }
01446 if (fread(buf, len, 1, p) < len) {
01447 if (ferror(p)) {
01448 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
01449 return -1;
01450 }
01451 }
01452 ((char *)buf)[len] = '\0';
01453 INIT(&str, mail_string, buf, len);
01454 init_mailstream(vms, NEW_FOLDER);
01455 imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
01456 if (!mail_append(vms->mailstream, mailbox, &str))
01457 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01458 fclose(p);
01459 unlink(tmp);
01460 ast_free(buf);
01461 ast_debug(3, "%s stored\n", fn);
01462
01463 if (tempcopy)
01464 *(vmu->email) = '\0';
01465
01466 return 0;
01467
01468 }
01469
01470 static int messagecount(const char *context, const char *mailbox, const char *folder)
01471 {
01472 SEARCHPGM *pgm;
01473 SEARCHHEADER *hdr;
01474
01475 struct ast_vm_user *vmu, vmus;
01476 struct vm_state *vms_p;
01477 int ret = 0;
01478 int fold = folder_int(folder);
01479
01480 if (ast_strlen_zero(mailbox))
01481 return 0;
01482
01483
01484
01485 vmu = find_user(&vmus, context, mailbox);
01486 if (!vmu) {
01487 ast_log(LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
01488 return -1;
01489 } else {
01490
01491 if (vmu->imapuser[0] == '\0') {
01492 ast_log(LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01493 return -1;
01494 }
01495 }
01496
01497
01498 if (vmu->imapuser[0] == '\0') {
01499 ast_log(LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01500 free_user(vmu);
01501 return -1;
01502 }
01503
01504
01505 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
01506 if (!vms_p) {
01507 vms_p = get_vm_state_by_mailbox(mailbox, 1);
01508 }
01509 if (vms_p) {
01510 ast_debug(3, "Returning before search - user is logged in\n");
01511 if (fold == 0) {
01512 return vms_p->newmessages;
01513 }
01514 if (fold == 1) {
01515 return vms_p->oldmessages;
01516 }
01517 }
01518
01519
01520 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
01521 if (!vms_p) {
01522 vms_p = get_vm_state_by_mailbox(mailbox, 0);
01523 }
01524
01525 if (!vms_p) {
01526 vms_p = create_vm_state_from_user(vmu);
01527 }
01528 ret = init_mailstream(vms_p, fold);
01529 if (!vms_p->mailstream) {
01530 ast_log(LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
01531 return -1;
01532 }
01533 if (ret == 0) {
01534 ast_mutex_lock(&vms_p->lock);
01535 pgm = mail_newsearchpgm ();
01536 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
01537 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
01538 pgm->header = hdr;
01539 if (fold != 1) {
01540 pgm->unseen = 1;
01541 pgm->seen = 0;
01542 }
01543
01544
01545
01546 else {
01547 pgm->unseen = 0;
01548 pgm->seen = 1;
01549 }
01550 pgm->undeleted = 1;
01551 pgm->deleted = 0;
01552
01553 vms_p->vmArrayIndex = 0;
01554 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01555 if (fold == 0)
01556 vms_p->newmessages = vms_p->vmArrayIndex;
01557 if (fold == 1)
01558 vms_p->oldmessages = vms_p->vmArrayIndex;
01559
01560 mail_free_searchpgm(&pgm);
01561 ast_mutex_unlock(&vms_p->lock);
01562 vms_p->updated = 0;
01563 return vms_p->vmArrayIndex;
01564 } else {
01565 ast_mutex_lock(&vms_p->lock);
01566 mail_ping(vms_p->mailstream);
01567 ast_mutex_unlock(&vms_p->lock);
01568 }
01569 return 0;
01570 }
01571 static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs)
01572 {
01573 char tmp[PATH_MAX] = "";
01574 char *mailboxnc;
01575 char *context;
01576 char *mb;
01577 char *cur;
01578 if (newmsgs)
01579 *newmsgs = 0;
01580 if (oldmsgs)
01581 *oldmsgs = 0;
01582
01583 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
01584
01585 if (ast_strlen_zero(mailbox_context))
01586 return 0;
01587
01588 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01589 context = strchr(tmp, '@');
01590 if (strchr(mailbox_context, ',')) {
01591 int tmpnew, tmpold;
01592 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01593 mb = tmp;
01594 while ((cur = strsep(&mb, ", "))) {
01595 if (!ast_strlen_zero(cur)) {
01596 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
01597 return -1;
01598 else {
01599 if (newmsgs)
01600 *newmsgs += tmpnew;
01601 if (oldmsgs)
01602 *oldmsgs += tmpold;
01603 }
01604 }
01605 }
01606 return 0;
01607 }
01608 if (context) {
01609 *context = '\0';
01610 mailboxnc = tmp;
01611 context++;
01612 } else {
01613 context = "default";
01614 mailboxnc = (char *)mailbox_context;
01615 }
01616 if (newmsgs) {
01617 if ((*newmsgs = messagecount(context, mailboxnc, imapfolder)) < 0)
01618 return -1;
01619 }
01620 if (oldmsgs) {
01621 if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0)
01622 return -1;
01623 }
01624 return 0;
01625 }
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637 static int has_voicemail(const char *mailbox, const char *folder)
01638 {
01639 char tmp[256], *tmp2, *mbox, *context;
01640 ast_copy_string(tmp, mailbox, sizeof(tmp));
01641 tmp2 = tmp;
01642 if (strchr(tmp2, ',')) {
01643 while ((mbox = strsep(&tmp2, ","))) {
01644 if (!ast_strlen_zero(mbox)) {
01645 if (has_voicemail(mbox, folder))
01646 return 1;
01647 }
01648 }
01649 }
01650 if ((context= strchr(tmp, '@')))
01651 *context++ = '\0';
01652 else
01653 context = "default";
01654 return messagecount(context, tmp, folder) ? 1 : 0;
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 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)
01673 {
01674 struct vm_state *sendvms = NULL, *destvms = NULL;
01675 char messagestring[10];
01676 if (msgnum >= recip->maxmsg) {
01677 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
01678 return -1;
01679 }
01680 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
01681 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
01682 return -1;
01683 }
01684 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
01685 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
01686 return -1;
01687 }
01688 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
01689 ast_mutex_lock(&sendvms->lock);
01690 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) {
01691 ast_mutex_unlock(&sendvms->lock);
01692 return 0;
01693 }
01694 ast_mutex_unlock(&sendvms->lock);
01695 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
01696 return -1;
01697 }
01698
01699 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
01700 {
01701 char tmp[256], *t = tmp;
01702 size_t left = sizeof(tmp);
01703
01704 if (box == OLD_FOLDER) {
01705 ast_copy_string(vms->curbox, mbox(NEW_FOLDER), sizeof(vms->curbox));
01706 } else {
01707 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
01708 }
01709
01710 if (box == NEW_FOLDER) {
01711 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
01712 } else {
01713 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(box));
01714 }
01715
01716
01717 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
01718
01719
01720 if (!ast_strlen_zero(authuser))
01721 ast_build_string(&t, &left, "/authuser=%s", authuser);
01722
01723
01724 if (!ast_strlen_zero(imapflags))
01725 ast_build_string(&t, &left, "/%s", imapflags);
01726
01727
01728 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
01729 if (box == NEW_FOLDER || box == OLD_FOLDER)
01730 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
01731 else if (box == GREETINGS_FOLDER)
01732 snprintf(spec, len, "%s%s", tmp, greetingfolder);
01733 else {
01734 if (!ast_strlen_zero(imapparentfolder)) {
01735
01736 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(box));
01737 } else {
01738 snprintf(spec, len, "%s%s", tmp, mbox(box));
01739 }
01740 }
01741 }
01742
01743 static int init_mailstream(struct vm_state *vms, int box)
01744 {
01745 MAILSTREAM *stream = NIL;
01746 long debug;
01747 char tmp[256];
01748
01749 if (!vms) {
01750 ast_log (LOG_ERROR,"vm_state is NULL!\n");
01751 return -1;
01752 }
01753 if (option_debug > 2)
01754 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
01755 if (vms->mailstream == NIL || !vms->mailstream) {
01756 if (option_debug)
01757 ast_log (LOG_DEBUG,"mailstream not set.\n");
01758 } else {
01759 stream = vms->mailstream;
01760 }
01761
01762 debug = NIL;
01763
01764 if (delimiter == '\0') {
01765 char *cp;
01766 #ifdef USE_SYSTEM_IMAP
01767 #include <imap/linkage.c>
01768 #elif defined(USE_SYSTEM_CCLIENT)
01769 #include <c-client/linkage.c>
01770 #else
01771 #include "linkage.c"
01772 #endif
01773
01774 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
01775 ast_mutex_lock(&vms->lock);
01776 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01777 ast_mutex_unlock(&vms->lock);
01778 if (stream == NIL) {
01779 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
01780 return -1;
01781 }
01782 get_mailbox_delimiter(stream);
01783
01784 for (cp = imapfolder; *cp; cp++)
01785 if (*cp == '/')
01786 *cp = delimiter;
01787 }
01788
01789 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
01790 if (option_debug > 2)
01791 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
01792 ast_mutex_lock(&vms->lock);
01793 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01794 ast_mutex_unlock(&vms->lock);
01795 if (vms->mailstream == NIL) {
01796 return -1;
01797 } else {
01798 return 0;
01799 }
01800 }
01801
01802 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
01803 {
01804 SEARCHPGM *pgm;
01805 SEARCHHEADER *hdr;
01806 int ret, urgent = 0;
01807
01808
01809 if (box == 11) {
01810 box = NEW_FOLDER;
01811 urgent = 1;
01812 }
01813
01814 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
01815 ast_debug(3,"Before init_mailstream, user is %s\n",vmu->imapuser);
01816
01817 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
01818 ast_log(LOG_ERROR, "Could not initialize mailstream\n");
01819 return -1;
01820 }
01821
01822 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
01823
01824
01825 if (box == 0) {
01826 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
01827 check_quota(vms,(char *)mbox(box));
01828 }
01829
01830 ast_mutex_lock(&vms->lock);
01831 pgm = mail_newsearchpgm();
01832
01833
01834 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
01835 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
01836 pgm->header = hdr;
01837 pgm->deleted = 0;
01838 pgm->undeleted = 1;
01839
01840
01841 if (box == NEW_FOLDER && urgent == 1) {
01842 pgm->unseen = 1;
01843 pgm->seen = 0;
01844 pgm->flagged = 1;
01845 pgm->unflagged = 0;
01846 } else if (box == NEW_FOLDER && urgent == 0) {
01847 pgm->unseen = 1;
01848 pgm->seen = 0;
01849 pgm->flagged = 0;
01850 pgm->unflagged = 1;
01851 } else if (box == OLD_FOLDER) {
01852 pgm->seen = 1;
01853 pgm->unseen = 0;
01854 }
01855
01856 ast_debug(3,"Before mail_search_full, user is %s\n",vmu->imapuser);
01857
01858 vms->vmArrayIndex = 0;
01859 mail_search_full (vms->mailstream, NULL, pgm, NIL);
01860 vms->lastmsg = vms->vmArrayIndex - 1;
01861 mail_free_searchpgm(&pgm);
01862
01863 ast_mutex_unlock(&vms->lock);
01864 return 0;
01865 }
01866
01867 static void write_file(char *filename, char *buffer, unsigned long len)
01868 {
01869 FILE *output;
01870
01871 output = fopen (filename, "w");
01872 if (fwrite(buffer, len, 1, output) != 1) {
01873 if (ferror(output)) {
01874 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
01875 }
01876 }
01877 fclose (output);
01878 }
01879
01880 static void update_messages_by_imapuser(const char *user, unsigned long number)
01881 {
01882 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
01883
01884 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
01885 return;
01886 }
01887
01888 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
01889 vms->msgArray[vms->vmArrayIndex++] = number;
01890 }
01891
01892 void mm_searched(MAILSTREAM *stream, unsigned long number)
01893 {
01894 char *mailbox = stream->mailbox, buf[1024] = "", *user;
01895
01896 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
01897 return;
01898
01899 update_messages_by_imapuser(user, number);
01900 }
01901
01902 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
01903 {
01904 struct ast_variable *var;
01905 struct ast_vm_user *vmu;
01906
01907 vmu = ast_calloc(1, sizeof *vmu);
01908 if (!vmu)
01909 return NULL;
01910 ast_set_flag(vmu, VM_ALLOCED);
01911 populate_defaults(vmu);
01912
01913 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
01914 if (var) {
01915 apply_options_full(vmu, var);
01916 ast_variables_destroy(var);
01917 return vmu;
01918 } else {
01919 free(vmu);
01920 return NULL;
01921 }
01922 }
01923
01924
01925
01926 void mm_exists(MAILSTREAM * stream, unsigned long number)
01927 {
01928
01929 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
01930 if (number == 0) return;
01931 set_update(stream);
01932 }
01933
01934
01935 void mm_expunged(MAILSTREAM * stream, unsigned long number)
01936 {
01937
01938 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
01939 if (number == 0) return;
01940 set_update(stream);
01941 }
01942
01943
01944 void mm_flags(MAILSTREAM * stream, unsigned long number)
01945 {
01946
01947 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
01948 if (number == 0) return;
01949 set_update(stream);
01950 }
01951
01952
01953 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
01954 {
01955 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
01956 mm_log (string, errflg);
01957 }
01958
01959
01960 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
01961 {
01962 if (delimiter == '\0') {
01963 delimiter = delim;
01964 }
01965
01966 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
01967 if (attributes & LATT_NOINFERIORS)
01968 ast_debug(5, "no inferiors\n");
01969 if (attributes & LATT_NOSELECT)
01970 ast_debug(5, "no select\n");
01971 if (attributes & LATT_MARKED)
01972 ast_debug(5, "marked\n");
01973 if (attributes & LATT_UNMARKED)
01974 ast_debug(5, "unmarked\n");
01975 }
01976
01977
01978 void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes)
01979 {
01980 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
01981 if (attributes & LATT_NOINFERIORS)
01982 ast_debug(5, "no inferiors\n");
01983 if (attributes & LATT_NOSELECT)
01984 ast_debug(5, "no select\n");
01985 if (attributes & LATT_MARKED)
01986 ast_debug(5, "marked\n");
01987 if (attributes & LATT_UNMARKED)
01988 ast_debug(5, "unmarked\n");
01989 }
01990
01991
01992 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
01993 {
01994 ast_log(LOG_NOTICE, " Mailbox %s", mailbox);
01995 if (status->flags & SA_MESSAGES)
01996 ast_log(LOG_NOTICE, ", %lu messages", status->messages);
01997 if (status->flags & SA_RECENT)
01998 ast_log(LOG_NOTICE, ", %lu recent", status->recent);
01999 if (status->flags & SA_UNSEEN)
02000 ast_log(LOG_NOTICE, ", %lu unseen", status->unseen);
02001 if (status->flags & SA_UIDVALIDITY)
02002 ast_log(LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02003 if (status->flags & SA_UIDNEXT)
02004 ast_log(LOG_NOTICE, ", %lu next UID", status->uidnext);
02005 ast_log(LOG_NOTICE, "\n");
02006 }
02007
02008
02009 void mm_log(char *string, long errflg)
02010 {
02011 switch ((short) errflg) {
02012 case NIL:
02013 ast_debug(1,"IMAP Info: %s\n", string);
02014 break;
02015 case PARSE:
02016 case WARN:
02017 ast_log(LOG_WARNING, "IMAP Warning: %s\n", string);
02018 break;
02019 case ERROR:
02020 ast_log(LOG_ERROR, "IMAP Error: %s\n", string);
02021 break;
02022 }
02023 }
02024
02025
02026 void mm_dlog(char *string)
02027 {
02028 ast_log(LOG_NOTICE, "%s\n", string);
02029 }
02030
02031
02032 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02033 {
02034 struct ast_vm_user *vmu;
02035
02036 ast_debug(4, "Entering callback mm_login\n");
02037
02038 ast_copy_string(user, mb->user, MAILTMPLEN);
02039
02040
02041 if (!ast_strlen_zero(authpassword)) {
02042 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02043 } else {
02044 AST_LIST_TRAVERSE(&users, vmu, list) {
02045 if (!strcasecmp(mb->user, vmu->imapuser)) {
02046 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02047 break;
02048 }
02049 }
02050 if (!vmu) {
02051 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02052 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02053 free_user(vmu);
02054 }
02055 }
02056 }
02057 }
02058
02059
02060 void mm_critical(MAILSTREAM * stream)
02061 {
02062 }
02063
02064
02065 void mm_nocritical(MAILSTREAM * stream)
02066 {
02067 }
02068
02069
02070 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02071 {
02072 kill (getpid (), SIGSTOP);
02073 return NIL;
02074 }
02075
02076
02077 void mm_fatal(char *string)
02078 {
02079 ast_log(LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02080 }
02081
02082
02083 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02084 {
02085 struct vm_state *vms;
02086 char *mailbox = stream->mailbox, *user;
02087 char buf[1024] = "";
02088 unsigned long usage = 0, limit = 0;
02089
02090 while (pquota) {
02091 usage = pquota->usage;
02092 limit = pquota->limit;
02093 pquota = pquota->next;
02094 }
02095
02096 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)))) {
02097 ast_log(LOG_ERROR, "No state found.\n");
02098 return;
02099 }
02100
02101 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02102
02103 vms->quota_usage = usage;
02104 vms->quota_limit = limit;
02105 }
02106
02107 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02108 {
02109 char *start, *eol_pnt;
02110 int taglen;
02111
02112 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02113 return NULL;
02114
02115 taglen = strlen(tag) + 1;
02116 if (taglen < 1)
02117 return NULL;
02118
02119 if (!(start = strstr(header, tag)))
02120 return NULL;
02121
02122
02123 memset(buf, 0, len);
02124
02125 ast_copy_string(buf, start+taglen, len);
02126 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02127 *eol_pnt = '\0';
02128 return buf;
02129 }
02130
02131 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02132 {
02133 char *start, *quote, *eol_pnt;
02134
02135 if (ast_strlen_zero(mailbox))
02136 return NULL;
02137
02138 if (!(start = strstr(mailbox, "/user=")))
02139 return NULL;
02140
02141 ast_copy_string(buf, start+6, len);
02142
02143 if (!(quote = strchr(buf, '\"'))) {
02144 if (!(eol_pnt = strchr(buf, '/')))
02145 eol_pnt = strchr(buf,'}');
02146 *eol_pnt = '\0';
02147 return buf;
02148 } else {
02149 eol_pnt = strchr(buf+1,'\"');
02150 *eol_pnt = '\0';
02151 return buf+1;
02152 }
02153 }
02154
02155 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02156 {
02157 struct vm_state *vms_p;
02158
02159 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02160 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02161 return vms_p;
02162 }
02163 if (option_debug > 4)
02164 ast_log(LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
02165 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02166 return NULL;
02167 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02168 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02169 vms_p->mailstream = NIL;
02170 if (option_debug > 4)
02171 ast_log(LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
02172 vms_p->updated = 1;
02173
02174 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
02175 init_vm_state(vms_p);
02176 vmstate_insert(vms_p);
02177 return vms_p;
02178 }
02179
02180 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02181 {
02182 struct vmstate *vlist = NULL;
02183
02184 if (interactive) {
02185 struct vm_state *vms;
02186 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02187 vms = pthread_getspecific(ts_vmstate.key);
02188 return vms;
02189 }
02190
02191 AST_LIST_LOCK(&vmstates);
02192 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02193 if (!vlist->vms) {
02194 ast_debug(3, "error: vms is NULL for %s\n", user);
02195 continue;
02196 }
02197 if (!vlist->vms->imapuser) {
02198 ast_debug(3, "error: imapuser is NULL for %s\n", user);
02199 continue;
02200 }
02201
02202 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
02203 AST_LIST_UNLOCK(&vmstates);
02204 return vlist->vms;
02205 }
02206 }
02207 AST_LIST_UNLOCK(&vmstates);
02208
02209 ast_debug(3, "%s not found in vmstates\n", user);
02210
02211 return NULL;
02212 }
02213
02214 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive)
02215 {
02216
02217 struct vmstate *vlist = NULL;
02218
02219 if (interactive) {
02220 struct vm_state *vms;
02221 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02222 vms = pthread_getspecific(ts_vmstate.key);
02223 return vms;
02224 }
02225
02226 AST_LIST_LOCK(&vmstates);
02227 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02228 if (!vlist->vms) {
02229 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
02230 continue;
02231 }
02232 if (!vlist->vms->username) {
02233 ast_debug(3, "error: username is NULL for %s\n", mailbox);
02234 continue;
02235 }
02236
02237 ast_debug(3, "comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n", mailbox, interactive, vlist->vms->username, vlist->vms->interactive);
02238
02239 if (!strcmp(vlist->vms->username,mailbox) && vlist->vms->interactive == interactive) {
02240 ast_debug(3, "Found it!\n");
02241 AST_LIST_UNLOCK(&vmstates);
02242 return vlist->vms;
02243 }
02244 }
02245 AST_LIST_UNLOCK(&vmstates);
02246
02247 ast_debug(3, "%s not found in vmstates\n", mailbox);
02248
02249 return NULL;
02250 }
02251
02252 static void vmstate_insert(struct vm_state *vms)
02253 {
02254 struct vmstate *v;
02255 struct vm_state *altvms;
02256
02257
02258
02259
02260 if (vms->interactive == 1) {
02261 altvms = get_vm_state_by_mailbox(vms->username,0);
02262 if (altvms) {
02263 ast_debug(3, "Duplicate mailbox %s, copying message info...\n",vms->username);
02264 vms->newmessages = altvms->newmessages;
02265 vms->oldmessages = altvms->oldmessages;
02266 vms->vmArrayIndex = altvms->vmArrayIndex;
02267 vms->lastmsg = altvms->lastmsg;
02268 vms->curmsg = altvms->curmsg;
02269
02270 vms->persist_vms = altvms;
02271
02272 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
02273 vms->mailstream = altvms->mailstream;
02274 #else
02275 vms->mailstream = NIL;
02276 #endif
02277 }
02278 return;
02279 }
02280
02281 if (!(v = ast_calloc(1, sizeof(*v))))
02282 return;
02283
02284 v->vms = vms;
02285
02286 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02287
02288 AST_LIST_LOCK(&vmstates);
02289 AST_LIST_INSERT_TAIL(&vmstates, v, list);
02290 AST_LIST_UNLOCK(&vmstates);
02291 }
02292
02293 static void vmstate_delete(struct vm_state *vms)
02294 {
02295 struct vmstate *vc = NULL;
02296 struct vm_state *altvms = NULL;
02297
02298
02299
02300 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
02301 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
02302 altvms->newmessages = vms->newmessages;
02303 altvms->oldmessages = vms->oldmessages;
02304 altvms->updated = 1;
02305 vms->mailstream = mail_close(vms->mailstream);
02306
02307
02308 return;
02309 }
02310
02311 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02312
02313 AST_LIST_LOCK(&vmstates);
02314 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
02315 if (vc->vms == vms) {
02316 AST_LIST_REMOVE_CURRENT(list);
02317 break;
02318 }
02319 }
02320 AST_LIST_TRAVERSE_SAFE_END
02321 AST_LIST_UNLOCK(&vmstates);
02322
02323 if (vc) {
02324 ast_mutex_destroy(&vc->vms->lock);
02325 ast_free(vc);
02326 }
02327 else
02328 ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02329 }
02330
02331 static void set_update(MAILSTREAM * stream)
02332 {
02333 struct vm_state *vms;
02334 char *mailbox = stream->mailbox, *user;
02335 char buf[1024] = "";
02336
02337 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
02338 if (user && option_debug > 2)
02339 ast_log(LOG_WARNING, "User %s mailbox not found for update.\n", user);
02340 return;
02341 }
02342
02343 ast_debug(3, "User %s mailbox set for update.\n", user);
02344
02345 vms->updated = 1;
02346 }
02347
02348 static void init_vm_state(struct vm_state *vms)
02349 {
02350 int x;
02351 vms->vmArrayIndex = 0;
02352 for (x = 0; x < 256; x++) {
02353 vms->msgArray[x] = 0;
02354 }
02355 ast_mutex_init(&vms->lock);
02356 }
02357
02358 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format)
02359 {
02360 char *body_content;
02361 char *body_decoded;
02362 unsigned long len;
02363 unsigned long newlen;
02364 char filename[256];
02365
02366 if (!body || body == NIL)
02367 return -1;
02368 ast_mutex_lock(&vms->lock);
02369 body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02370 ast_mutex_unlock(&vms->lock);
02371 if (body_content != NIL) {
02372 snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format);
02373
02374 body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
02375 write_file (filename, (char *) body_decoded, newlen);
02376 }
02377 return 0;
02378 }
02379
02380
02381
02382
02383
02384
02385
02386 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02387 char tmp[50];
02388 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02389 mail_list(stream, tmp, "*");
02390 }
02391
02392
02393
02394
02395
02396
02397
02398
02399 static void check_quota(struct vm_state *vms, char *mailbox) {
02400 ast_mutex_lock(&vms->lock);
02401 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02402 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02403 if (vms && vms->mailstream != NULL) {
02404 imap_getquotaroot(vms->mailstream, mailbox);
02405 } else {
02406 ast_log(LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
02407 }
02408 ast_mutex_unlock(&vms->lock);
02409 }
02410
02411 #endif
02412
02413
02414
02415
02416
02417 static int vm_lock_path(const char *path)
02418 {
02419 switch (ast_lock_path(path)) {
02420 case AST_LOCK_TIMEOUT:
02421 return -1;
02422 default:
02423 return 0;
02424 }
02425 }
02426
02427
02428 #ifdef ODBC_STORAGE
02429 struct generic_prepare_struct {
02430 char *sql;
02431 int argc;
02432 char **argv;
02433 };
02434
02435 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02436 {
02437 struct generic_prepare_struct *gps = data;
02438 int res, i;
02439 SQLHSTMT stmt;
02440
02441 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02442 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02443 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02444 return NULL;
02445 }
02446 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02447 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02448 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02449 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02450 return NULL;
02451 }
02452 for (i = 0; i < gps->argc; i++)
02453 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02454
02455 return stmt;
02456 }
02457
02458 static int retrieve_file(char *dir, int msgnum)
02459 {
02460 int x = 0;
02461 int res;
02462 int fd = -1;
02463 size_t fdlen = 0;
02464 void *fdm = MAP_FAILED;
02465 SQLSMALLINT colcount = 0;
02466 SQLHSTMT stmt;
02467 char sql[PATH_MAX];
02468 char fmt[80] = "";
02469 char *c;
02470 char coltitle[256];
02471 SQLSMALLINT collen;
02472 SQLSMALLINT datatype;
02473 SQLSMALLINT decimaldigits;
02474 SQLSMALLINT nullable;
02475 SQLULEN colsize;
02476 SQLLEN colsize2;
02477 FILE *f = NULL;
02478 char rowdata[80];
02479 char fn[PATH_MAX];
02480 char full_fn[PATH_MAX];
02481 char msgnums[80];
02482 char *argv[] = { dir, msgnums };
02483 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02484
02485 struct odbc_obj *obj;
02486 obj = ast_odbc_request_obj(odbc_database, 0);
02487 if (obj) {
02488 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02489 c = strchr(fmt, '|');
02490 if (c)
02491 *c = '\0';
02492 if (!strcasecmp(fmt, "wav49"))
02493 strcpy(fmt, "WAV");
02494 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02495 if (msgnum > -1)
02496 make_file(fn, sizeof(fn), dir, msgnum);
02497 else
02498 ast_copy_string(fn, dir, sizeof(fn));
02499 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02500
02501 if (!(f = fopen(full_fn, "w+"))) {
02502 ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02503 goto yuck;
02504 }
02505
02506 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02507 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
02508 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02509 if (!stmt) {
02510 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02511 ast_odbc_release_obj(obj);
02512 goto yuck;
02513 }
02514 res = SQLFetch(stmt);
02515 if (res == SQL_NO_DATA) {
02516 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02517 ast_odbc_release_obj(obj);
02518 goto yuck;
02519 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02520 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02521 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02522 ast_odbc_release_obj(obj);
02523 goto yuck;
02524 }
02525 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
02526 if (fd < 0) {
02527 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
02528 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02529 ast_odbc_release_obj(obj);
02530 goto yuck;
02531 }
02532 res = SQLNumResultCols(stmt, &colcount);
02533 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02534 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
02535 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02536 ast_odbc_release_obj(obj);
02537 goto yuck;
02538 }
02539 if (f)
02540 fprintf(f, "[message]\n");
02541 for (x = 0; x < colcount; x++) {
02542 rowdata[0] = '\0';
02543 collen = sizeof(coltitle);
02544 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
02545 &datatype, &colsize, &decimaldigits, &nullable);
02546 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02547 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
02548 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02549 ast_odbc_release_obj(obj);
02550 goto yuck;
02551 }
02552 if (!strcasecmp(coltitle, "recording")) {
02553 off_t offset;
02554 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
02555 fdlen = colsize2;
02556 if (fd > -1) {
02557 char tmp[1] = "";
02558 lseek(fd, fdlen - 1, SEEK_SET);
02559 if (write(fd, tmp, 1) != 1) {
02560 close(fd);
02561 fd = -1;
02562 continue;
02563 }
02564
02565 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
02566 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
02567 ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
02568 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02569 ast_odbc_release_obj(obj);
02570 goto yuck;
02571 } else {
02572 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
02573 munmap(fdm, CHUNKSIZE);
02574 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02575 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02576 unlink(full_fn);
02577 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02578 ast_odbc_release_obj(obj);
02579 goto yuck;
02580 }
02581 }
02582 }
02583 if (truncate(full_fn, fdlen) < 0) {
02584 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
02585 }
02586 }
02587 } else {
02588 SQLLEN ind;
02589 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &ind);
02590 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02591 SQLINTEGER nativeerror = 0;
02592 SQLSMALLINT diagbytes = 0;
02593 unsigned char state[10], diagnostic[256];
02594 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
02595 ast_log(LOG_WARNING, "SQL Get Data error: %s: %s!\n[%s]\n\n", state, diagnostic, sql);
02596 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02597 ast_odbc_release_obj(obj);
02598 goto yuck;
02599 }
02600 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
02601 fprintf(f, "%s=%s\n", coltitle, rowdata);
02602 }
02603 }
02604 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02605 ast_odbc_release_obj(obj);
02606 } else
02607 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02608 yuck:
02609 if (f)
02610 fclose(f);
02611 if (fd > -1)
02612 close(fd);
02613 return x - 1;
02614 }
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02627 {
02628 int x = 0;
02629 int res;
02630 SQLHSTMT stmt;
02631 char sql[PATH_MAX];
02632 char rowdata[20];
02633 char *argv[] = { dir };
02634 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02635
02636 struct odbc_obj *obj;
02637 obj = ast_odbc_request_obj(odbc_database, 0);
02638 if (obj) {
02639 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
02640 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02641 if (!stmt) {
02642 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02643 ast_odbc_release_obj(obj);
02644 goto yuck;
02645 }
02646 res = SQLFetch(stmt);
02647 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02648 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02649 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02650 ast_odbc_release_obj(obj);
02651 goto yuck;
02652 }
02653 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02654 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02655 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02656 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02657 ast_odbc_release_obj(obj);
02658 goto yuck;
02659 }
02660 if (sscanf(rowdata, "%d", &x) != 1)
02661 ast_log(LOG_WARNING, "Failed to read message count!\n");
02662 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02663 ast_odbc_release_obj(obj);
02664 } else
02665 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02666 yuck:
02667 return x - 1;
02668 }
02669
02670 static int message_exists(char *dir, int msgnum)
02671 {
02672 int x = 0;
02673 int res;
02674 SQLHSTMT stmt;
02675 char sql[PATH_MAX];
02676 char rowdata[20];
02677 char msgnums[20];
02678 char *argv[] = { dir, msgnums };
02679 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02680
02681 struct odbc_obj *obj;
02682 obj = ast_odbc_request_obj(odbc_database, 0);
02683 if (obj) {
02684 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02685 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
02686 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02687 if (!stmt) {
02688 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02689 ast_odbc_release_obj(obj);
02690 goto yuck;
02691 }
02692 res = SQLFetch(stmt);
02693 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02694 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02695 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02696 ast_odbc_release_obj(obj);
02697 goto yuck;
02698 }
02699 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02700 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02701 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02702 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02703 ast_odbc_release_obj(obj);
02704 goto yuck;
02705 }
02706 if (sscanf(rowdata, "%d", &x) != 1)
02707 ast_log(LOG_WARNING, "Failed to read message count!\n");
02708 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02709 ast_odbc_release_obj(obj);
02710 } else
02711 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02712 yuck:
02713 return x;
02714 }
02715
02716 static int count_messages(struct ast_vm_user *vmu, char *dir)
02717 {
02718 return last_message_index(vmu, dir) + 1;
02719 }
02720
02721 static void delete_file(char *sdir, int smsg)
02722 {
02723 SQLHSTMT stmt;
02724 char sql[PATH_MAX];
02725 char msgnums[20];
02726 char *argv[] = { sdir, msgnums };
02727 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02728
02729 struct odbc_obj *obj;
02730 obj = ast_odbc_request_obj(odbc_database, 0);
02731 if (obj) {
02732 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02733 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
02734 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02735 if (!stmt)
02736 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02737 else
02738 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02739 ast_odbc_release_obj(obj);
02740 } else
02741 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02742 return;
02743 }
02744
02745 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
02746 {
02747 SQLHSTMT stmt;
02748 char sql[512];
02749 char msgnums[20];
02750 char msgnumd[20];
02751 struct odbc_obj *obj;
02752 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
02753 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02754
02755 delete_file(ddir, dmsg);
02756 obj = ast_odbc_request_obj(odbc_database, 0);
02757 if (obj) {
02758 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02759 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02760 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
02761 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02762 if (!stmt)
02763 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
02764 else
02765 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02766 ast_odbc_release_obj(obj);
02767 } else
02768 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02769 return;
02770 }
02771
02772 struct insert_cb_struct {
02773 char *dir;
02774 char *msgnum;
02775 void *recording;
02776 size_t recordinglen;
02777 SQLLEN indlen;
02778 const char *context;
02779 const char *macrocontext;
02780 const char *callerid;
02781 const char *origtime;
02782 const char *duration;
02783 char *mailboxuser;
02784 char *mailboxcontext;
02785 const char *category;
02786 char *sql;
02787 };
02788
02789 static SQLHSTMT insert_cb(struct odbc_obj *obj, void *vd)
02790 {
02791 struct insert_cb_struct *d = vd;
02792 int res;
02793 SQLHSTMT stmt;
02794
02795 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02796 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02797 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02798 return NULL;
02799 }
02800
02801 res = SQLPrepare(stmt, (unsigned char *)d->sql, SQL_NTS);
02802 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02803 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", d->sql);
02804 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02805 return NULL;
02806 }
02807
02808 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->dir), 0, (void *)d->dir, 0, NULL);
02809 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->msgnum), 0, (void *)d->msgnum, 0, NULL);
02810 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, d->recordinglen, 0, (void *)d->recording, 0, &d->indlen);
02811 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->context), 0, (void *)d->context, 0, NULL);
02812 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->macrocontext), 0, (void *)d->macrocontext, 0, NULL);
02813 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->callerid), 0, (void *)d->callerid, 0, NULL);
02814 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->origtime), 0, (void *)d->origtime, 0, NULL);
02815 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->duration), 0, (void *)d->duration, 0, NULL);
02816 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxuser), 0, (void *)d->mailboxuser, 0, NULL);
02817 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxcontext), 0, (void *)d->mailboxcontext, 0, NULL);
02818 if (!ast_strlen_zero(d->category)) {
02819 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->category), 0, (void *)d->category, 0, NULL);
02820 }
02821
02822 return stmt;
02823 }
02824
02825 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
02826 {
02827 int x = 0;
02828 int fd = -1;
02829 void *fdm = MAP_FAILED;
02830 size_t fdlen = -1;
02831 SQLHSTMT stmt;
02832 char sql[PATH_MAX];
02833 char msgnums[20];
02834 char fn[PATH_MAX];
02835 char full_fn[PATH_MAX];
02836 char fmt[80] = "";
02837 char *c;
02838 struct insert_cb_struct d = {
02839 .dir = dir,
02840 .msgnum = msgnums,
02841 .context = "",
02842 .macrocontext = "",
02843 .callerid = "",
02844 .origtime = "",
02845 .duration = "",
02846 .mailboxuser = mailboxuser,
02847 .mailboxcontext = mailboxcontext,
02848 .category = "",
02849 .sql = sql
02850 };
02851 struct ast_config *cfg = NULL;
02852 struct odbc_obj *obj;
02853 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
02854
02855 delete_file(dir, msgnum);
02856 obj = ast_odbc_request_obj(odbc_database, 0);
02857 if (obj) {
02858 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02859 c = strchr(fmt, '|');
02860 if (c)
02861 *c = '\0';
02862 if (!strcasecmp(fmt, "wav49"))
02863 strcpy(fmt, "WAV");
02864 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02865 if (msgnum > -1)
02866 make_file(fn, sizeof(fn), dir, msgnum);
02867 else
02868 ast_copy_string(fn, dir, sizeof(fn));
02869 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02870 cfg = ast_config_load(full_fn, config_flags);
02871 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02872 fd = open(full_fn, O_RDWR);
02873 if (fd < 0) {
02874 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
02875 ast_odbc_release_obj(obj);
02876 goto yuck;
02877 }
02878 if (cfg) {
02879 d.context = ast_variable_retrieve(cfg, "message", "context");
02880 if (!d.context) d.context = "";
02881 d.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
02882 if (!d.macrocontext) d.macrocontext = "";
02883 d.callerid = ast_variable_retrieve(cfg, "message", "callerid");
02884 if (!d.callerid) d.callerid = "";
02885 d.origtime = ast_variable_retrieve(cfg, "message", "origtime");
02886 if (!d.origtime) d.origtime = "";
02887 d.duration = ast_variable_retrieve(cfg, "message", "duration");
02888 if (!d.duration) d.duration = "";
02889 d.category = ast_variable_retrieve(cfg, "message", "category");
02890 if (!d.category) d.category = "";
02891 }
02892 fdlen = lseek(fd, 0, SEEK_END);
02893 lseek(fd, 0, SEEK_SET);
02894 printf("Length is %zd\n", fdlen);
02895 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
02896 if (fdm == MAP_FAILED) {
02897 ast_log(LOG_WARNING, "Memory map failed!\n");
02898 ast_odbc_release_obj(obj);
02899 goto yuck;
02900 }
02901 d.recording = fdm;
02902 d.recordinglen = d.indlen = fdlen;
02903 if (!ast_strlen_zero(d.category))
02904 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
02905 else
02906 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)", odbc_table);
02907 stmt = ast_odbc_prepare_and_execute(obj, insert_cb, &d);
02908 if (stmt) {
02909 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02910 }
02911 ast_odbc_release_obj(obj);
02912 } else
02913 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02914 yuck:
02915 if (cfg)
02916 ast_config_destroy(cfg);
02917 if (fdm != MAP_FAILED)
02918 munmap(fdm, fdlen);
02919 if (fd > -1)
02920 close(fd);
02921 return x;
02922 }
02923
02924 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
02925 {
02926 SQLHSTMT stmt;
02927 char sql[PATH_MAX];
02928 char msgnums[20];
02929 char msgnumd[20];
02930 struct odbc_obj *obj;
02931 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
02932 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02933
02934 delete_file(ddir, dmsg);
02935 obj = ast_odbc_request_obj(odbc_database, 0);
02936 if (obj) {
02937 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02938 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02939 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
02940 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02941 if (!stmt)
02942 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02943 else
02944 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02945 ast_odbc_release_obj(obj);
02946 } else
02947 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02948 return;
02949 }
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962 static int remove_file(char *dir, int msgnum)
02963 {
02964 char fn[PATH_MAX];
02965 char full_fn[PATH_MAX];
02966 char msgnums[80];
02967
02968 if (msgnum > -1) {
02969 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02970 make_file(fn, sizeof(fn), dir, msgnum);
02971 } else
02972 ast_copy_string(fn, dir, sizeof(fn));
02973 ast_filedelete(fn, NULL);
02974 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02975 unlink(full_fn);
02976 return 0;
02977 }
02978 #else
02979 #ifndef IMAP_STORAGE
02980 static int count_messages(struct ast_vm_user *vmu, char *dir)
02981 {
02982
02983
02984 int vmcount = 0;
02985 DIR *vmdir = NULL;
02986 struct dirent *vment = NULL;
02987
02988 if (vm_lock_path(dir))
02989 return ERROR_LOCK_PATH;
02990
02991 if ((vmdir = opendir(dir))) {
02992 while ((vment = readdir(vmdir))) {
02993 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
02994 vmcount++;
02995 }
02996 closedir(vmdir);
02997 }
02998 ast_unlock_path(dir);
02999
03000 return vmcount;
03001 }
03002
03003 static void rename_file(char *sfn, char *dfn)
03004 {
03005 char stxt[PATH_MAX];
03006 char dtxt[PATH_MAX];
03007 ast_filerename(sfn, dfn, NULL);
03008 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03009 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03010 if (ast_check_realtime("voicemail_data")) {
03011 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, NULL);
03012 }
03013 rename(stxt, dtxt);
03014 }
03015 #endif
03016
03017 #ifndef IMAP_STORAGE
03018
03019
03020
03021
03022 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03023 {
03024 int x;
03025 unsigned char map[MAXMSGLIMIT] = "";
03026 DIR *msgdir;
03027 struct dirent *msgdirent;
03028 int msgdirint;
03029
03030
03031
03032
03033
03034 msgdir = opendir(dir);
03035 while ((msgdirent = readdir(msgdir))) {
03036 if (sscanf(msgdirent->d_name, "msg%d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03037 map[msgdirint] = 1;
03038 }
03039 closedir(msgdir);
03040
03041 for (x = 0; x < vmu->maxmsg; x++) {
03042 if (map[x] == 0)
03043 break;
03044 }
03045
03046 return x - 1;
03047 }
03048
03049 #endif
03050 #endif
03051
03052 static int copy(char *infile, char *outfile)
03053 {
03054 int ifd;
03055 int ofd;
03056 int res;
03057 int len;
03058 char buf[4096];
03059
03060 #ifdef HARDLINK_WHEN_POSSIBLE
03061
03062 if (link(infile, outfile)) {
03063 #endif
03064 if ((ifd = open(infile, O_RDONLY)) < 0) {
03065 ast_log(LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03066 return -1;
03067 }
03068 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03069 ast_log(LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03070 close(ifd);
03071 return -1;
03072 }
03073 do {
03074 len = read(ifd, buf, sizeof(buf));
03075 if (len < 0) {
03076 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03077 close(ifd);
03078 close(ofd);
03079 unlink(outfile);
03080 }
03081 if (len) {
03082 res = write(ofd, buf, len);
03083 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03084 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03085 close(ifd);
03086 close(ofd);
03087 unlink(outfile);
03088 }
03089 }
03090 } while (len);
03091 close(ifd);
03092 close(ofd);
03093 return 0;
03094 #ifdef HARDLINK_WHEN_POSSIBLE
03095 } else {
03096
03097 return 0;
03098 }
03099 #endif
03100 }
03101
03102 static void copy_plain_file(char *frompath, char *topath)
03103 {
03104 char frompath2[PATH_MAX], topath2[PATH_MAX];
03105 struct ast_variable *tmp, *var = NULL;
03106 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
03107 ast_filecopy(frompath, topath, NULL);
03108 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
03109 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
03110 if (ast_check_realtime("voicemail_data")) {
03111 var = ast_load_realtime("voicemail_data", "filename", frompath, NULL);
03112
03113 for (tmp = var; tmp; tmp = tmp->next) {
03114 if (!strcasecmp(tmp->name, "origmailbox")) {
03115 origmailbox = tmp->value;
03116 } else if (!strcasecmp(tmp->name, "context")) {
03117 context = tmp->value;
03118 } else if (!strcasecmp(tmp->name, "macrocontext")) {
03119 macrocontext = tmp->value;
03120 } else if (!strcasecmp(tmp->name, "exten")) {
03121 exten = tmp->value;
03122 } else if (!strcasecmp(tmp->name, "priority")) {
03123 priority = tmp->value;
03124 } else if (!strcasecmp(tmp->name, "callerchan")) {
03125 callerchan = tmp->value;
03126 } else if (!strcasecmp(tmp->name, "callerid")) {
03127 callerid = tmp->value;
03128 } else if (!strcasecmp(tmp->name, "origdate")) {
03129 origdate = tmp->value;
03130 } else if (!strcasecmp(tmp->name, "origtime")) {
03131 origtime = tmp->value;
03132 } else if (!strcasecmp(tmp->name, "category")) {
03133 category = tmp->value;
03134 } else if (!strcasecmp(tmp->name, "duration")) {
03135 duration = tmp->value;
03136 }
03137 }
03138 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, NULL);
03139 }
03140 copy(frompath2, topath2);
03141 ast_variables_destroy(var);
03142 }
03143
03144
03145 #if (!defined(ODBC_STORAGE) && !defined(IMAP_STORAGE))
03146
03147
03148
03149
03150
03151
03152
03153
03154 static int vm_delete(char *file)
03155 {
03156 char *txt;
03157 int txtsize = 0;
03158
03159 txtsize = (strlen(file) + 5) * sizeof(char);
03160 txt = alloca(txtsize);
03161
03162
03163
03164 if (ast_check_realtime("voicemail_data")) {
03165 ast_destroy_realtime("voicemail_data", "filename", file, NULL);
03166 }
03167 snprintf(txt, txtsize, "%s.txt", file);
03168 unlink(txt);
03169 return ast_filedelete(file, NULL);
03170 }
03171 #endif
03172 static int inbuf(struct baseio *bio, FILE *fi)
03173 {
03174 int l;
03175
03176 if (bio->ateof)
03177 return 0;
03178
03179 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
03180 if (ferror(fi))
03181 return -1;
03182
03183 bio->ateof = 1;
03184 return 0;
03185 }
03186
03187 bio->iolen = l;
03188 bio->iocp = 0;
03189
03190 return 1;
03191 }
03192
03193 static int inchar(struct baseio *bio, FILE *fi)
03194 {
03195 if (bio->iocp >= bio->iolen) {
03196 if (!inbuf(bio, fi))
03197 return EOF;
03198 }
03199
03200 return bio->iobuf[bio->iocp++];
03201 }
03202
03203 static int ochar(struct baseio *bio, int c, FILE *so)
03204 {
03205 if (bio->linelength >= BASELINELEN) {
03206 if (fputs(eol, so) == EOF)
03207 return -1;
03208
03209 bio->linelength= 0;
03210 }
03211
03212 if (putc(((unsigned char)c), so) == EOF)
03213 return -1;
03214
03215 bio->linelength++;
03216
03217 return 1;
03218 }
03219
03220 static int base_encode(char *filename, FILE *so)
03221 {
03222 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
03223 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
03224 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
03225 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
03226 int i, hiteof = 0;
03227 FILE *fi;
03228 struct baseio bio;
03229
03230 memset(&bio, 0, sizeof(bio));
03231 bio.iocp = BASEMAXINLINE;
03232
03233 if (!(fi = fopen(filename, "rb"))) {
03234 ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
03235 return -1;
03236 }
03237
03238 while (!hiteof) {
03239 unsigned char igroup[3], ogroup[4];
03240 int c, n;
03241
03242 igroup[0] = igroup[1] = igroup[2] = 0;
03243
03244 for (n = 0; n < 3; n++) {
03245 if ((c = inchar(&bio, fi)) == EOF) {
03246 hiteof = 1;
03247 break;
03248 }
03249
03250 igroup[n] = (unsigned char)c;
03251 }
03252
03253 if (n > 0) {
03254 ogroup[0] = dtable[igroup[0] >> 2];
03255 ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
03256 ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
03257 ogroup[3] = dtable[igroup[2] & 0x3F];
03258
03259 if (n < 3) {
03260 ogroup[3] = '=';
03261
03262 if (n < 2)
03263 ogroup[2] = '=';
03264 }
03265
03266 for (i = 0; i < 4; i++)
03267 ochar(&bio, ogroup[i], so);
03268 }
03269 }
03270
03271 fclose(fi);
03272
03273 if (fputs(eol, so) == EOF)
03274 return 0;
03275
03276 return 1;
03277 }
03278
03279 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, char *passdata, size_t passdatasize, const char *category)
03280 {
03281 char callerid[256];
03282 char fromdir[256], fromfile[256];
03283 struct ast_config *msg_cfg;
03284 const char *origcallerid, *origtime;
03285 char origcidname[80], origcidnum[80], origdate[80];
03286 int inttime;
03287 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03288
03289
03290 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
03291 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
03292 snprintf(passdata, passdatasize, "%d", msgnum);
03293 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
03294 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
03295 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
03296 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
03297 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
03298 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
03299 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
03300 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
03301 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
03302
03303
03304 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03305 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
03306 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03307 strcat(fromfile, ".txt");
03308 }
03309 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
03310 if (option_debug > 0) {
03311 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
03312 }
03313 return;
03314 }
03315
03316 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03317 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
03318 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
03319 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
03320 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
03321 }
03322
03323 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%d", &inttime) == 1) {
03324 struct timeval tv = { inttime, };
03325 struct ast_tm tm;
03326 ast_localtime(&tv, &tm, NULL);
03327 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03328 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
03329 }
03330 ast_config_destroy(msg_cfg);
03331 }
03332
03333 static char *quote(const char *from, char *to, size_t len)
03334 {
03335 char *ptr = to;
03336 *ptr++ = '"';
03337 for (; ptr < to + len - 1; from++) {
03338 if (*from == '"')
03339 *ptr++ = '\\';
03340 else if (*from == '\0')
03341 break;
03342 *ptr++ = *from;
03343 }
03344 if (ptr < to + len - 1)
03345 *ptr++ = '"';
03346 *ptr = '\0';
03347 return to;
03348 }
03349
03350
03351
03352
03353
03354 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
03355 {
03356 const struct vm_zone *z = NULL;
03357 struct timeval t = ast_tvnow();
03358
03359
03360 if (!ast_strlen_zero(vmu->zonetag)) {
03361
03362 AST_LIST_LOCK(&zones);
03363 AST_LIST_TRAVERSE(&zones, z, list) {
03364 if (!strcmp(z->name, vmu->zonetag))
03365 break;
03366 }
03367 AST_LIST_UNLOCK(&zones);
03368 }
03369 ast_localtime(&t, tm, z ? z->timezone : NULL);
03370 return tm;
03371 }
03372
03373
03374
03375
03376
03377 static int check_mime(const char *str)
03378 {
03379 for (; *str; str++) {
03380 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
03381 return 1;
03382 }
03383 }
03384 return 0;
03385 }
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403 static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
03404 {
03405 char tmp[80];
03406 int first_section = 1;
03407 size_t endlen = 0, tmplen = 0;
03408 *end = '\0';
03409
03410 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03411 for (; *start; start++) {
03412 int need_encoding = 0;
03413 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
03414 need_encoding = 1;
03415 }
03416 if ((first_section && need_encoding && preamble + tmplen > 70) ||
03417 (first_section && !need_encoding && preamble + tmplen > 72) ||
03418 (!first_section && need_encoding && tmplen > 70) ||
03419 (!first_section && !need_encoding && tmplen > 72)) {
03420
03421 endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
03422 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
03423 first_section = 0;
03424 }
03425 if (need_encoding && *start == ' ') {
03426 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
03427 } else if (need_encoding) {
03428 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
03429 } else {
03430 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
03431 }
03432 }
03433 snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
03434 return end;
03435 }
03436
03437
03438
03439
03440
03441
03442
03443
03444
03445
03446
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457 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 *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap)
03458 {
03459 char date[256];
03460 char host[MAXHOSTNAMELEN] = "";
03461 char who[256];
03462 char bound[256];
03463 char fname[256];
03464 char dur[256];
03465 char tmpcmd[256];
03466 struct ast_tm tm;
03467 char enc_cidnum[256] = "", enc_cidname[256] = "";
03468 char *passdata = NULL, *passdata2;
03469 size_t len_passdata = 0, len_passdata2, tmplen;
03470 char *greeting_attachment;
03471
03472 #ifdef IMAP_STORAGE
03473 #define ENDL "\r\n"
03474 #else
03475 #define ENDL "\n"
03476 #endif
03477
03478
03479 len_passdata2 = strlen(vmu->fullname);
03480 if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
03481 len_passdata2 = tmplen;
03482 }
03483 if ((tmplen = strlen(fromstring)) > len_passdata2) {
03484 len_passdata2 = tmplen;
03485 }
03486 len_passdata2 = len_passdata2 * 3 + 200;
03487 passdata2 = alloca(len_passdata2);
03488
03489 if (!ast_strlen_zero(cidnum)) {
03490 strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
03491 }
03492 if (!ast_strlen_zero(cidname)) {
03493 strip_control(cidname, enc_cidname, sizeof(enc_cidname));
03494 }
03495 gethostname(host, sizeof(host) - 1);
03496
03497 if (strchr(srcemail, '@'))
03498 ast_copy_string(who, srcemail, sizeof(who));
03499 else
03500 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03501
03502 greeting_attachment = strrchr(ast_strdupa(attach), '/');
03503 if (greeting_attachment)
03504 *greeting_attachment++ = '\0';
03505
03506 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03507 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03508 fprintf(p, "Date: %s" ENDL, date);
03509
03510
03511 ast_strftime(date, sizeof(date), emaildateformat, &tm);
03512
03513 if (!ast_strlen_zero(fromstring)) {
03514 struct ast_channel *ast;
03515 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03516 char *ptr;
03517 memset(passdata2, 0, len_passdata2);
03518 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category);
03519 pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
03520 len_passdata = strlen(passdata2) * 3 + 300;
03521 passdata = alloca(len_passdata);
03522 if (check_mime(passdata2)) {
03523 int first_line = 1;
03524 encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
03525 while ((ptr = strchr(passdata, ' '))) {
03526 *ptr = '\0';
03527 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
03528 first_line = 0;
03529 passdata = ptr + 1;
03530 }
03531 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
03532 } else {
03533 fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
03534 }
03535 ast_channel_free(ast);
03536 } else {
03537 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03538 }
03539 } else {
03540 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
03541 }
03542
03543 if (check_mime(vmu->fullname)) {
03544 int first_line = 1;
03545 char *ptr;
03546 encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
03547 while ((ptr = strchr(passdata2, ' '))) {
03548 *ptr = '\0';
03549 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
03550 first_line = 0;
03551 passdata2 = ptr + 1;
03552 }
03553 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
03554 } else {
03555 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
03556 }
03557 if (!ast_strlen_zero(emailsubject)) {
03558 struct ast_channel *ast;
03559 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03560 int vmlen = strlen(emailsubject) * 3 + 200;
03561
03562 if (vmlen > len_passdata) {
03563 passdata = alloca(vmlen);
03564 len_passdata = vmlen;
03565 }
03566
03567 memset(passdata, 0, len_passdata);
03568 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category);
03569 pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata);
03570 if (check_mime(passdata)) {
03571 int first_line = 1;
03572 char *ptr;
03573 encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
03574 while ((ptr = strchr(passdata2, ' '))) {
03575 *ptr = '\0';
03576 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03577 first_line = 0;
03578 passdata2 = ptr + 1;
03579 }
03580 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
03581 } else {
03582 fprintf(p, "Subject: %s" ENDL, passdata);
03583 }
03584 ast_channel_free(ast);
03585 } else {
03586 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03587 }
03588 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
03589 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03590 } else {
03591 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03592 }
03593
03594 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
03595 if (imap) {
03596
03597 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
03598
03599 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
03600 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
03601 #ifdef IMAP_STORAGE
03602 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
03603 #else
03604 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
03605 #endif
03606 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
03607 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
03608 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
03609 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
03610 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
03611 if (!ast_strlen_zero(category)) {
03612 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
03613 } else {
03614 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
03615 }
03616 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
03617 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
03618 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
03619 }
03620 if (!ast_strlen_zero(cidnum)) {
03621 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
03622 }
03623 if (!ast_strlen_zero(cidname)) {
03624 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
03625 }
03626 fprintf(p, "MIME-Version: 1.0" ENDL);
03627 if (attach_user_voicemail) {
03628
03629 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
03630
03631 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
03632 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
03633 fprintf(p, "--%s" ENDL, bound);
03634 }
03635 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
03636 if (emailbody) {
03637 struct ast_channel *ast;
03638 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03639 char *passdata;
03640 int vmlen = strlen(emailbody) * 3 + 200;
03641 passdata = alloca(vmlen);
03642 memset(passdata, 0, vmlen);
03643 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03644 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
03645 fprintf(p, "%s" ENDL, passdata);
03646 ast_channel_free(ast);
03647 } else
03648 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03649 } else if (msgnum > -1) {
03650 if (strcmp(vmu->mailbox, mailbox)) {
03651
03652 struct ast_config *msg_cfg;
03653 const char *v;
03654 int inttime;
03655 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
03656 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03657
03658 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03659 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
03660 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03661 strcat(fromfile, ".txt");
03662 }
03663 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
03664 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03665 ast_copy_string(origcallerid, v, sizeof(origcallerid));
03666 }
03667
03668
03669
03670 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%d", &inttime) == 1) {
03671 struct timeval tv = { inttime, };
03672 struct ast_tm tm;
03673 ast_localtime(&tv, &tm, NULL);
03674 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03675 }
03676 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
03677 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
03678 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
03679 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
03680 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
03681 date, origcallerid, origdate);
03682 ast_config_destroy(msg_cfg);
03683 } else {
03684 goto plain_message;
03685 }
03686 } else {
03687 plain_message:
03688 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
03689 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
03690 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
03691 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
03692 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
03693 }
03694 } else {
03695 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
03696 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
03697 }
03698 if (attach_user_voicemail) {
03699
03700 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
03701 char tmpdir[256], newtmp[256];
03702 int tmpfd = -1;
03703
03704 if (vmu->volgain < -.001 || vmu->volgain > .001) {
03705 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
03706 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
03707 tmpfd = mkstemp(newtmp);
03708 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
03709 ast_debug(3, "newtmp: %s\n", newtmp);
03710 if (tmpfd > -1) {
03711 int soxstatus;
03712 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
03713 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
03714 attach = newtmp;
03715 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
03716 } else {
03717 ast_log(LOG_WARNING, "Sox failed to reencode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
03718 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
03719 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
03720 }
03721 }
03722 }
03723 fprintf(p, "--%s" ENDL, bound);
03724 if (msgnum > -1)
03725 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
03726 else
03727 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
03728 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
03729 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
03730 if (msgnum > -1)
03731 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
03732 else
03733 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
03734 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
03735 base_encode(fname, p);
03736 fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
03737 if (tmpfd > -1) {
03738 unlink(fname);
03739 close(tmpfd);
03740 unlink(newtmp);
03741 }
03742 }
03743 #undef ENDL
03744 }
03745
03746 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 *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
03747 {
03748 FILE *p = NULL;
03749 char tmp[80] = "/tmp/astmail-XXXXXX";
03750 char tmp2[256];
03751
03752 if (vmu && ast_strlen_zero(vmu->email)) {
03753 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
03754 return(0);
03755 }
03756 if (!strcmp(format, "wav49"))
03757 format = "WAV";
03758 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));
03759
03760
03761 if ((p = vm_mkftemp(tmp)) == NULL) {
03762 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03763 return -1;
03764 } else {
03765 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
03766 fclose(p);
03767 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03768 ast_safe_system(tmp2);
03769 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
03770 }
03771 return 0;
03772 }
03773
03774 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)
03775 {
03776 char date[256];
03777 char host[MAXHOSTNAMELEN] = "";
03778 char who[256];
03779 char dur[PATH_MAX];
03780 char tmp[80] = "/tmp/astmail-XXXXXX";
03781 char tmp2[PATH_MAX];
03782 struct ast_tm tm;
03783 FILE *p;
03784
03785 if ((p = vm_mkftemp(tmp)) == NULL) {
03786 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03787 return -1;
03788 }
03789 gethostname(host, sizeof(host) - 1);
03790 if (strchr(srcemail, '@'))
03791 ast_copy_string(who, srcemail, sizeof(who));
03792 else
03793 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03794 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03795 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03796 fprintf(p, "Date: %s\n", date);
03797
03798 if (*pagerfromstring) {
03799 struct ast_channel *ast;
03800 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03801 char *passdata;
03802 int vmlen = strlen(fromstring) * 3 + 200;
03803 passdata = alloca(vmlen);
03804 memset(passdata, 0, vmlen);
03805 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03806 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
03807 fprintf(p, "From: %s <%s>\n", passdata, who);
03808 ast_channel_free(ast);
03809 } else
03810 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03811 } else
03812 fprintf(p, "From: Asterisk PBX <%s>\n", who);
03813 fprintf(p, "To: %s\n", pager);
03814 if (pagersubject) {
03815 struct ast_channel *ast;
03816 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03817 char *passdata;
03818 int vmlen = strlen(pagersubject) * 3 + 200;
03819 passdata = alloca(vmlen);
03820 memset(passdata, 0, vmlen);
03821 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03822 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
03823 fprintf(p, "Subject: %s\n\n", passdata);
03824 ast_channel_free(ast);
03825 } else
03826 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03827 } else
03828 fprintf(p, "Subject: New VM\n\n");
03829
03830 ast_strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
03831 if (pagerbody) {
03832 struct ast_channel *ast;
03833 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
03834 char *passdata;
03835 int vmlen = strlen(pagerbody) * 3 + 200;
03836 passdata = alloca(vmlen);
03837 memset(passdata, 0, vmlen);
03838 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category);
03839 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
03840 fprintf(p, "%s\n", passdata);
03841 ast_channel_free(ast);
03842 } else
03843 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03844 } else {
03845 fprintf(p, "New %s long msg in box %s\n"
03846 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
03847 }
03848 fclose(p);
03849 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03850 ast_safe_system(tmp2);
03851 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
03852 return 0;
03853 }
03854
03855 static int get_date(char *s, int len)
03856 {
03857 struct ast_tm tm;
03858 struct timeval t = ast_tvnow();
03859
03860 ast_localtime(&t, &tm, "UTC");
03861
03862 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
03863 }
03864
03865 static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char *filename, char *ecodes)
03866 {
03867 int res = -2;
03868
03869 #ifdef ODBC_STORAGE
03870 int success =
03871 #endif
03872 RETRIEVE(filename, -1, vmu->mailbox, vmu->context);
03873 if (ast_fileexists(filename, NULL, NULL) > 0) {
03874 res = ast_streamfile(chan, filename, chan->language);
03875 if (res > -1)
03876 res = ast_waitstream(chan, ecodes);
03877 #ifdef ODBC_STORAGE
03878 if (success == -1) {
03879
03880 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
03881 store_file(filename, vmu->mailbox, vmu->context, -1);
03882 }
03883 #endif
03884 }
03885 DISPOSE(filename, -1);
03886
03887 return res;
03888 }
03889
03890 static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, char *ext, int busy, char *ecodes)
03891 {
03892 int res;
03893 char fn[PATH_MAX];
03894 char dest[PATH_MAX];
03895
03896 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, ext);
03897
03898 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, ""))) {
03899 ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
03900 return -1;
03901 }
03902
03903 res = play_greeting(chan, vmu, fn, ecodes);
03904 if (res == -2) {
03905
03906 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
03907 if (res)
03908 return res;
03909 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
03910 }
03911 if (res)
03912 return res;
03913
03914 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
03915 return res;
03916 }
03917
03918 static void free_zone(struct vm_zone *z)
03919 {
03920 ast_free(z);
03921 }
03922
03923 #ifdef ODBC_STORAGE
03924
03925 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03926 {
03927 int x = -1;
03928 int res;
03929 SQLHSTMT stmt;
03930 char sql[PATH_MAX];
03931 char rowdata[20];
03932 char tmp[PATH_MAX] = "";
03933 struct odbc_obj *obj;
03934 char *context;
03935 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03936
03937 if (newmsgs)
03938 *newmsgs = 0;
03939 if (oldmsgs)
03940 *oldmsgs = 0;
03941
03942
03943 if (ast_strlen_zero(mailbox))
03944 return 0;
03945
03946 ast_copy_string(tmp, mailbox, sizeof(tmp));
03947
03948 context = strchr(tmp, '@');
03949 if (context) {
03950 *context = '\0';
03951 context++;
03952 } else
03953 context = "default";
03954
03955 obj = ast_odbc_request_obj(odbc_database, 0);
03956 if (obj) {
03957 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
03958 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03959 if (!stmt) {
03960 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03961 ast_odbc_release_obj(obj);
03962 goto yuck;
03963 }
03964 res = SQLFetch(stmt);
03965 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03966 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03967 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03968 ast_odbc_release_obj(obj);
03969 goto yuck;
03970 }
03971 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03972 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03973 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03974 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03975 ast_odbc_release_obj(obj);
03976 goto yuck;
03977 }
03978 *newmsgs = atoi(rowdata);
03979 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03980
03981 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
03982 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03983 if (!stmt) {
03984 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03985 ast_odbc_release_obj(obj);
03986 goto yuck;
03987 }
03988 res = SQLFetch(stmt);
03989 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03990 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03991 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03992 ast_odbc_release_obj(obj);
03993 goto yuck;
03994 }
03995 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03996 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03997 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03998 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03999 ast_odbc_release_obj(obj);
04000 goto yuck;
04001 }
04002 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04003 ast_odbc_release_obj(obj);
04004 *oldmsgs = atoi(rowdata);
04005 x = 0;
04006 } else
04007 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04008
04009 yuck:
04010 return x;
04011 }
04012
04013 static int messagecount(const char *context, const char *mailbox, const char *folder)
04014 {
04015 struct odbc_obj *obj = NULL;
04016 int nummsgs = 0;
04017 int res;
04018 SQLHSTMT stmt = NULL;
04019 char sql[PATH_MAX];
04020 char rowdata[20];
04021 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04022 if (!folder)
04023 folder = "INBOX";
04024
04025 if (ast_strlen_zero(mailbox))
04026 return 0;
04027
04028 obj = ast_odbc_request_obj(odbc_database, 0);
04029 if (obj) {
04030 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
04031 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04032 if (!stmt) {
04033 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04034 goto yuck;
04035 }
04036 res = SQLFetch(stmt);
04037 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04038 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04039 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04040 goto yuck;
04041 }
04042 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04043 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04044 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04045 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04046 goto yuck;
04047 }
04048 nummsgs = atoi(rowdata);
04049 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04050 } else
04051 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04052
04053 yuck:
04054 if (obj)
04055 ast_odbc_release_obj(obj);
04056 return nummsgs;
04057 }
04058
04059 static int has_voicemail(const char *mailbox, const char *folder)
04060 {
04061 char tmp[256], *tmp2 = tmp, *mbox, *context;
04062 ast_copy_string(tmp, mailbox, sizeof(tmp));
04063 while ((context = mbox = strsep(&tmp2, ","))) {
04064 strsep(&context, "@");
04065 if (ast_strlen_zero(context))
04066 context = "default";
04067 if (messagecount(context, mbox, folder))
04068 return 1;
04069 }
04070 return 0;
04071 }
04072
04073 #elif defined(IMAP_STORAGE)
04074
04075 #endif
04076 #ifndef IMAP_STORAGE
04077
04078 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)
04079 {
04080 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04081 const char *frombox = mbox(imbox);
04082 int recipmsgnum;
04083
04084 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04085
04086 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04087
04088 if (!dir)
04089 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04090 else
04091 ast_copy_string(fromdir, dir, sizeof(fromdir));
04092
04093 make_file(frompath, sizeof(frompath), fromdir, msgnum);
04094 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04095
04096 if (vm_lock_path(todir))
04097 return ERROR_LOCK_PATH;
04098
04099 recipmsgnum = last_message_index(recip, todir) + 1;
04100 if (recipmsgnum < recip->maxmsg) {
04101 make_file(topath, sizeof(topath), todir, recipmsgnum);
04102 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04103 } else {
04104 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04105 }
04106 ast_unlock_path(todir);
04107 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04108
04109 return 0;
04110 }
04111 #endif
04112 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
04113 static int messagecount(const char *context, const char *mailbox, const char *folder)
04114 {
04115 return __has_voicemail(context, mailbox, folder, 0);
04116 }
04117
04118
04119 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
04120 {
04121 DIR *dir;
04122 struct dirent *de;
04123 char fn[256];
04124 int ret = 0;
04125
04126
04127 if (ast_strlen_zero(mailbox))
04128 return 0;
04129
04130 if (ast_strlen_zero(folder))
04131 folder = "INBOX";
04132 if (ast_strlen_zero(context))
04133 context = "default";
04134
04135 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
04136
04137 if (!(dir = opendir(fn)))
04138 return 0;
04139
04140 while ((de = readdir(dir))) {
04141 if (!strncasecmp(de->d_name, "msg", 3)) {
04142 if (shortcircuit) {
04143 ret = 1;
04144 break;
04145 } else if (!strncasecmp(de->d_name + 8, "txt", 3))
04146 ret++;
04147 }
04148 }
04149
04150 closedir(dir);
04151
04152 return ret;
04153 }
04154
04155
04156 static int has_voicemail(const char *mailbox, const char *folder)
04157 {
04158 char tmp[256], *tmp2 = tmp, *mbox, *context;
04159 ast_copy_string(tmp, mailbox, sizeof(tmp));
04160 while ((mbox = strsep(&tmp2, ","))) {
04161 if ((context = strchr(mbox, '@')))
04162 *context++ = '\0';
04163 else
04164 context = "default";
04165 if (__has_voicemail(context, mbox, folder, 1))
04166 return 1;
04167 }
04168 return 0;
04169 }
04170
04171
04172 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04173 {
04174 char tmp[256];
04175 char *context;
04176
04177
04178 if (ast_strlen_zero(mailbox))
04179 return 0;
04180
04181 if (newmsgs)
04182 *newmsgs = 0;
04183 if (oldmsgs)
04184 *oldmsgs = 0;
04185
04186 if (strchr(mailbox, ',')) {
04187 int tmpnew, tmpold;
04188 char *mb, *cur;
04189
04190 ast_copy_string(tmp, mailbox, sizeof(tmp));
04191 mb = tmp;
04192 while ((cur = strsep(&mb, ", "))) {
04193 if (!ast_strlen_zero(cur)) {
04194 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
04195 return -1;
04196 else {
04197 if (newmsgs)
04198 *newmsgs += tmpnew;
04199 if (oldmsgs)
04200 *oldmsgs += tmpold;
04201 }
04202 }
04203 }
04204 return 0;
04205 }
04206
04207 ast_copy_string(tmp, mailbox, sizeof(tmp));
04208
04209 if ((context = strchr(tmp, '@')))
04210 *context++ = '\0';
04211 else
04212 context = "default";
04213
04214 if (newmsgs)
04215 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
04216 if (oldmsgs)
04217 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
04218
04219 return 0;
04220 }
04221
04222 #endif
04223
04224 static void run_externnotify(char *context, char *extension)
04225 {
04226 char arguments[255];
04227 char ext_context[256] = "";
04228 int newvoicemails = 0, oldvoicemails = 0;
04229 struct ast_smdi_mwi_message *mwi_msg;
04230
04231 if (!ast_strlen_zero(context))
04232 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
04233 else
04234 ast_copy_string(ext_context, extension, sizeof(ext_context));
04235
04236 if (smdi_iface) {
04237 if (ast_app_has_voicemail(ext_context, NULL))
04238 ast_smdi_mwi_set(smdi_iface, extension);
04239 else
04240 ast_smdi_mwi_unset(smdi_iface, extension);
04241
04242 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
04243 ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
04244 if (!strncmp(mwi_msg->cause, "INV", 3))
04245 ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
04246 else if (!strncmp(mwi_msg->cause, "BLK", 3))
04247 ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
04248 ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
04249 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
04250 } else {
04251 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
04252 }
04253 }
04254
04255 if (!ast_strlen_zero(externnotify)) {
04256 if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
04257 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
04258 } else {
04259 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
04260 ast_debug(1, "Executing %s\n", arguments);
04261 ast_safe_system(arguments);
04262 }
04263 }
04264 }
04265
04266 struct leave_vm_options {
04267 unsigned int flags;
04268 signed char record_gain;
04269 char *exitcontext;
04270 };
04271
04272 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
04273 {
04274 #ifdef IMAP_STORAGE
04275 int newmsgs, oldmsgs;
04276 #endif
04277 char txtfile[PATH_MAX], tmptxtfile[PATH_MAX];
04278 struct vm_state *vms = NULL;
04279 char callerid[256];
04280 FILE *txt;
04281 char date[256];
04282 int txtdes;
04283 int res = 0;
04284 int msgnum;
04285 int duration = 0;
04286 int ausemacro = 0;
04287 int ousemacro = 0;
04288 int ouseexten = 0;
04289 int rtmsgid = 0;
04290 char tmpid[16];
04291 char tmpdur[16];
04292 char priority[16];
04293 char origtime[16];
04294 char dir[PATH_MAX], tmpdir[PATH_MAX];
04295 char fn[PATH_MAX];
04296 char prefile[PATH_MAX] = "";
04297 char tempfile[PATH_MAX] = "";
04298 char ext_context[256] = "";
04299 char fmt[80];
04300 char *context;
04301 char ecodes[17] = "#";
04302 char *tmpptr;
04303 struct ast_str *tmp = ast_str_create(16);
04304 struct ast_vm_user *vmu;
04305 struct ast_vm_user svm;
04306 const char *category = NULL, *code, *alldtmf = "0123456789ABCD*#";
04307
04308 ast_str_set(&tmp, 0, "%s", ext);
04309 ext = ast_str_buffer(tmp);
04310 if ((context = strchr(ext, '@'))) {
04311 *context++ = '\0';
04312 tmpptr = strchr(context, '&');
04313 } else {
04314 tmpptr = strchr(ext, '&');
04315 }
04316
04317 if (tmpptr) {
04318 *tmpptr++ = '\0';
04319 }
04320
04321 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
04322
04323 ast_debug(3, "Before find_user\n");
04324 if (!(vmu = find_user(&svm, context, ext))) {
04325 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
04326 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04327 ast_free(tmp);
04328 return res;
04329 }
04330
04331 if (strcmp(vmu->context, "default")) {
04332 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
04333 } else {
04334 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
04335 }
04336 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
04337 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
04338 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
04339 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
04340 }
04341 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
04342 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
04343 ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
04344 ast_free(tmp);
04345 return -1;
04346 }
04347 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
04348 if (ast_fileexists(tempfile, NULL, NULL) > 0) {
04349 ast_copy_string(prefile, tempfile, sizeof(prefile));
04350 }
04351 DISPOSE(tempfile, -1);
04352
04353 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
04354
04355
04356 if (ast_test_flag(vmu, VM_OPERATOR)) {
04357 if (!ast_strlen_zero(vmu->exit)) {
04358 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
04359 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04360 ouseexten = 1;
04361 }
04362 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
04363 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04364 ouseexten = 1;
04365 } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
04366 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
04367 ousemacro = 1;
04368 }
04369 }
04370
04371 if (!ast_strlen_zero(vmu->exit)) {
04372 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num)) {
04373 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04374 }
04375 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num)) {
04376 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04377 } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
04378 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
04379 ausemacro = 1;
04380 }
04381
04382 if (ast_test_flag(options, OPT_DTMFEXIT)) {
04383 for (code = alldtmf; *code; code++) {
04384 char e[2] = "";
04385 e[0] = *code;
04386 if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num)) {
04387 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
04388 }
04389 }
04390 }
04391
04392
04393 if (!ast_strlen_zero(prefile)) {
04394 res = play_greeting(chan, vmu, prefile, ecodes);
04395 if (res == -2) {
04396
04397 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
04398 res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
04399 }
04400 if (res < 0) {
04401 ast_debug(1, "Hang up during prefile playback\n");
04402 free_user(vmu);
04403 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04404 ast_free(tmp);
04405 return -1;
04406 }
04407 }
04408 if (res == '#') {
04409
04410 ast_set_flag(options, OPT_SILENT);
04411 res = 0;
04412 }
04413 if (!res && !ast_test_flag(options, OPT_SILENT)) {
04414 res = ast_stream_and_wait(chan, INTRO, ecodes);
04415 if (res == '#') {
04416 ast_set_flag(options, OPT_SILENT);
04417 res = 0;
04418 }
04419 }
04420 if (res > 0) {
04421 ast_stopstream(chan);
04422 }
04423
04424
04425 if (res == '*') {
04426 chan->exten[0] = 'a';
04427 chan->exten[1] = '\0';
04428 if (!ast_strlen_zero(vmu->exit)) {
04429 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04430 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
04431 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04432 }
04433 chan->priority = 0;
04434 free_user(vmu);
04435 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04436 ast_free(tmp);
04437 return 0;
04438 }
04439
04440
04441 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
04442 transfer:
04443 if (ouseexten || ousemacro) {
04444 chan->exten[0] = 'o';
04445 chan->exten[1] = '\0';
04446 if (!ast_strlen_zero(vmu->exit)) {
04447 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
04448 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
04449 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
04450 }
04451 ast_play_and_wait(chan, "transfer");
04452 chan->priority = 0;
04453 free_user(vmu);
04454 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04455 }
04456 ast_free(tmp);
04457 return 0;
04458 }
04459
04460
04461 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
04462 if (!ast_strlen_zero(options->exitcontext)) {
04463 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
04464 }
04465 free_user(vmu);
04466 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
04467 return res;
04468 }
04469
04470 if (res < 0) {
04471 free_user(vmu);
04472 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04473 ast_free(tmp);
04474 return -1;
04475 }
04476
04477 ast_copy_string(fmt, vmfmts, sizeof(fmt));
04478 if (!ast_strlen_zero(fmt)) {
04479 msgnum = 0;
04480
04481 #ifdef IMAP_STORAGE
04482
04483
04484 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
04485 if (res < 0) {
04486 ast_log(LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
04487 ast_free(tmp);
04488 return -1;
04489 }
04490 if (!(vms = get_vm_state_by_mailbox(ext, 0))) {
04491
04492
04493
04494
04495 if (!(vms = create_vm_state_from_user(vmu))) {
04496 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
04497 ast_free(tmp);
04498 return -1;
04499 }
04500 }
04501 vms->newmessages++;
04502
04503
04504 msgnum = newmsgs + oldmsgs;
04505 ast_debug(3, "Messagecount set to %d\n", msgnum);
04506 snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
04507
04508 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04509
04510
04511 check_quota(vms, imapfolder);
04512 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
04513 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
04514 ast_play_and_wait(chan, "vm-mailboxfull");
04515 ast_free(tmp);
04516 return -1;
04517 }
04518
04519
04520 if (msgnum >= vmu->maxmsg) {
04521 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
04522 ast_play_and_wait(chan, "vm-mailboxfull");
04523 ast_free(tmp);
04524 return -1;
04525 }
04526 #else
04527 if (count_messages(vmu, dir) >= vmu->maxmsg) {
04528 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04529 if (!res) {
04530 res = ast_waitstream(chan, "");
04531 }
04532 ast_log(LOG_WARNING, "No more messages possible\n");
04533 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04534 goto leave_vm_out;
04535 }
04536
04537 #endif
04538 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
04539 txtdes = mkstemp(tmptxtfile);
04540 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
04541 if (txtdes < 0) {
04542 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
04543 if (!res) {
04544 res = ast_waitstream(chan, "");
04545 }
04546 ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
04547 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04548 goto leave_vm_out;
04549 }
04550
04551
04552 if (res >= 0) {
04553
04554 res = ast_stream_and_wait(chan, "beep", "");
04555 }
04556
04557
04558 if (ast_check_realtime("voicemail_data")) {
04559 snprintf(priority, sizeof(priority), "%d", chan->priority);
04560 snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL));
04561 get_date(date, sizeof(date));
04562 rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", category ? category : "", NULL);
04563 }
04564
04565
04566 txt = fdopen(txtdes, "w+");
04567 if (txt) {
04568 get_date(date, sizeof(date));
04569 fprintf(txt,
04570 ";\n"
04571 "; Message Information file\n"
04572 ";\n"
04573 "[message]\n"
04574 "origmailbox=%s\n"
04575 "context=%s\n"
04576 "macrocontext=%s\n"
04577 "exten=%s\n"
04578 "priority=%d\n"
04579 "callerchan=%s\n"
04580 "callerid=%s\n"
04581 "origdate=%s\n"
04582 "origtime=%ld\n"
04583 "category=%s\n",
04584 ext,
04585 chan->context,
04586 chan->macrocontext,
04587 chan->exten,
04588 chan->priority,
04589 chan->name,
04590 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
04591 date, (long)time(NULL),
04592 category ? category : "");
04593 } else {
04594 ast_log(LOG_WARNING, "Error opening text file for output\n");
04595 }
04596 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms);
04597
04598 if (txt) {
04599 if (duration < vmminsecs) {
04600 fclose(txt);
04601 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs);
04602 ast_filedelete(tmptxtfile, NULL);
04603 unlink(tmptxtfile);
04604 if (ast_check_realtime("voicemail_data")) {
04605 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
04606 ast_destroy_realtime("voicemail_data", "id", tmpid, NULL);
04607 }
04608 } else {
04609 fprintf(txt, "duration=%d\n", duration);
04610 fclose(txt);
04611 if (vm_lock_path(dir)) {
04612 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
04613
04614 ast_filedelete(tmptxtfile, NULL);
04615 unlink(tmptxtfile);
04616 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
04617 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
04618 unlink(tmptxtfile);
04619 ast_unlock_path(dir);
04620 if (ast_check_realtime("voicemail_data")) {
04621 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
04622 ast_destroy_realtime("voicemail_data", "id", tmpid, NULL);
04623 }
04624 } else {
04625 #ifndef IMAP_STORAGE
04626 msgnum = last_message_index(vmu, dir) + 1;
04627 #endif
04628 make_file(fn, sizeof(fn), dir, msgnum);
04629
04630
04631 #ifndef IMAP_STORAGE
04632 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
04633 #else
04634 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04635 #endif
04636
04637 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
04638 ast_filerename(tmptxtfile, fn, NULL);
04639 rename(tmptxtfile, txtfile);
04640
04641
04642
04643 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0) {
04644 ast_log(LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
04645 }
04646
04647 ast_unlock_path(dir);
04648 if (ast_check_realtime("voicemail_data")) {
04649 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
04650 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
04651 ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, NULL);
04652 }
04653
04654
04655
04656 if (ast_fileexists(fn, NULL, NULL) > 0) {
04657 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
04658 }
04659
04660
04661 while (tmpptr) {
04662 struct ast_vm_user recipu, *recip;
04663 char *exten, *context;
04664
04665 exten = strsep(&tmpptr, "&");
04666 context = strchr(exten, '@');
04667 if (context) {
04668 *context = '\0';
04669 context++;
04670 }
04671 if ((recip = find_user(&recipu, context, exten))) {
04672 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir);
04673 free_user(recip);
04674 }
04675 }
04676
04677 if (ast_fileexists(fn, NULL, NULL)) {
04678 #ifdef IMAP_STORAGE
04679 notify_new_message(chan, vmu, vms, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04680 #else
04681 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04682 #endif
04683 DISPOSE(dir, msgnum);
04684 }
04685 }
04686 }
04687 }
04688 if (res == '0') {
04689 goto transfer;
04690 } else if (res > 0) {
04691 res = 0;
04692 }
04693
04694 if (duration < vmminsecs) {
04695
04696 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04697 } else {
04698 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
04699 }
04700 } else {
04701 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
04702 }
04703 leave_vm_out:
04704 free_user(vmu);
04705
04706 ast_free(tmp);
04707 return res;
04708 }
04709
04710 #ifndef IMAP_STORAGE
04711 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir)
04712 {
04713
04714
04715 int x, dest;
04716 char sfn[PATH_MAX];
04717 char dfn[PATH_MAX];
04718
04719 if (vm_lock_path(dir))
04720 return ERROR_LOCK_PATH;
04721
04722 for (x = 0, dest = 0; x < vmu->maxmsg; x++) {
04723 make_file(sfn, sizeof(sfn), dir, x);
04724 if (EXISTS(dir, x, sfn, NULL)) {
04725
04726 if (x != dest) {
04727 make_file(dfn, sizeof(dfn), dir, dest);
04728 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
04729 }
04730
04731 dest++;
04732 }
04733 }
04734 ast_unlock_path(dir);
04735
04736 return 0;
04737 }
04738 #endif
04739
04740 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
04741 {
04742 int d;
04743 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
04744 return d;
04745 }
04746
04747 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
04748 {
04749 #ifdef IMAP_STORAGE
04750
04751
04752 char sequence[10];
04753 char mailbox[256];
04754 int res;
04755
04756
04757 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
04758
04759 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(box));
04760 ast_mutex_lock(&vms->lock);
04761
04762 if (box == OLD_FOLDER) {
04763 mail_setflag(vms->mailstream, sequence, "\\Seen");
04764 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
04765 } else if (box == NEW_FOLDER) {
04766 mail_clearflag(vms->mailstream, sequence, "\\Seen");
04767 mail_setflag(vms->mailstream, sequence, "\\Unseen");
04768 }
04769 if (!strcasecmp(mbox(NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
04770 ast_mutex_unlock(&vms->lock);
04771 return 0;
04772 }
04773
04774 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
04775 ast_debug(5, "Checking if folder exists: %s\n",mailbox);
04776 if (mail_create(vms->mailstream, mailbox) == NIL)
04777 ast_debug(5, "Folder exists.\n");
04778 else
04779 ast_log(LOG_NOTICE, "Folder %s created!\n",mbox(box));
04780 res = !mail_copy(vms->mailstream, sequence, (char *)mbox(box));
04781 ast_mutex_unlock(&vms->lock);
04782 return res;
04783 #else
04784 char *dir = vms->curdir;
04785 char *username = vms->username;
04786 char *context = vmu->context;
04787 char sfn[PATH_MAX];
04788 char dfn[PATH_MAX];
04789 char ddir[PATH_MAX];
04790 const char *dbox = mbox(box);
04791 int x, i;
04792 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
04793
04794 if (vm_lock_path(ddir))
04795 return ERROR_LOCK_PATH;
04796
04797 x = last_message_index(vmu, ddir) + 1;
04798
04799 if (box == 10 && x >= vmu->maxdeletedmsg) {
04800 x--;
04801 for (i = 1; i <= x; i++) {
04802
04803 make_file(sfn, sizeof(sfn), ddir, i);
04804 make_file(dfn, sizeof(dfn), ddir, i - 1);
04805 if (EXISTS(ddir, i, sfn, NULL)) {
04806 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
04807 } else
04808 break;
04809 }
04810 } else {
04811 if (x >= vmu->maxmsg) {
04812 ast_unlock_path(ddir);
04813 return ERROR_MAILBOX_FULL;
04814 }
04815 }
04816 make_file(sfn, sizeof(sfn), dir, msg);
04817 make_file(dfn, sizeof(dfn), ddir, x);
04818 if (strcmp(sfn, dfn)) {
04819 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
04820 }
04821 ast_unlock_path(ddir);
04822 #endif
04823 return 0;
04824 }
04825
04826 static int adsi_logo(unsigned char *buf)
04827 {
04828 int bytes = 0;
04829 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
04830 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
04831 return bytes;
04832 }
04833
04834 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
04835 {
04836 unsigned char buf[256];
04837 int bytes = 0;
04838 int x;
04839 char num[5];
04840
04841 *useadsi = 0;
04842 bytes += ast_adsi_data_mode(buf + bytes);
04843 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04844
04845 bytes = 0;
04846 bytes += adsi_logo(buf);
04847 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04848 #ifdef DISPLAY
04849 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
04850 #endif
04851 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04852 bytes += ast_adsi_data_mode(buf + bytes);
04853 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04854
04855 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
04856 bytes = 0;
04857 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
04858 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04859 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04860 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04861 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04862 return 0;
04863 }
04864
04865 #ifdef DISPLAY
04866
04867 bytes = 0;
04868 bytes += ast_adsi_logo(buf);
04869 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04870 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
04871 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04872 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04873 #endif
04874 bytes = 0;
04875 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
04876 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
04877 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
04878 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
04879 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
04880 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
04881 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04882
04883 #ifdef DISPLAY
04884
04885 bytes = 0;
04886 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
04887 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04888
04889 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04890 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04891 #endif
04892
04893 bytes = 0;
04894
04895 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
04896 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
04897 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
04898 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
04899 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
04900 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
04901 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04902
04903 #ifdef DISPLAY
04904
04905 bytes = 0;
04906 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
04907 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04908 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04909 #endif
04910
04911 bytes = 0;
04912 for (x = 0; x < 5; x++) {
04913 snprintf(num, sizeof(num), "%d", x);
04914 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
04915 }
04916 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
04917 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04918
04919 #ifdef DISPLAY
04920
04921 bytes = 0;
04922 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
04923 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04924 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04925 #endif
04926
04927 if (ast_adsi_end_download(chan)) {
04928 bytes = 0;
04929 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
04930 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04931 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04932 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04933 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04934 return 0;
04935 }
04936 bytes = 0;
04937 bytes += ast_adsi_download_disconnect(buf + bytes);
04938 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04939 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04940
04941 ast_debug(1, "Done downloading scripts...\n");
04942
04943 #ifdef DISPLAY
04944
04945 bytes = 0;
04946 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
04947 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04948 #endif
04949 ast_debug(1, "Restarting session...\n");
04950
04951 bytes = 0;
04952
04953 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
04954 *useadsi = 1;
04955 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
04956 } else
04957 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
04958
04959 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04960 return 0;
04961 }
04962
04963 static void adsi_begin(struct ast_channel *chan, int *useadsi)
04964 {
04965 int x;
04966 if (!ast_adsi_available(chan))
04967 return;
04968 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
04969 if (x < 0)
04970 return;
04971 if (!x) {
04972 if (adsi_load_vmail(chan, useadsi)) {
04973 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
04974 return;
04975 }
04976 } else
04977 *useadsi = 1;
04978 }
04979
04980 static void adsi_login(struct ast_channel *chan)
04981 {
04982 unsigned char buf[256];
04983 int bytes = 0;
04984 unsigned char keys[8];
04985 int x;
04986 if (!ast_adsi_available(chan))
04987 return;
04988
04989 for (x = 0; x < 8; x++)
04990 keys[x] = 0;
04991
04992 keys[3] = ADSI_KEY_APPS + 3;
04993
04994 bytes += adsi_logo(buf + bytes);
04995 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
04996 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
04997 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04998 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
04999 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
05000 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
05001 bytes += ast_adsi_set_keys(buf + bytes, keys);
05002 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05003 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05004 }
05005
05006 static void adsi_password(struct ast_channel *chan)
05007 {
05008 unsigned char buf[256];
05009 int bytes = 0;
05010 unsigned char keys[8];
05011 int x;
05012 if (!ast_adsi_available(chan))
05013 return;
05014
05015 for (x = 0; x < 8; x++)
05016 keys[x] = 0;
05017
05018 keys[3] = ADSI_KEY_APPS + 3;
05019
05020 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05021 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
05022 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
05023 bytes += ast_adsi_set_keys(buf + bytes, keys);
05024 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05025 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05026 }
05027
05028 static void adsi_folders(struct ast_channel *chan, int start, char *label)
05029 {
05030 unsigned char buf[256];
05031 int bytes = 0;
05032 unsigned char keys[8];
05033 int x, y;
05034
05035 if (!ast_adsi_available(chan))
05036 return;
05037
05038 for (x = 0; x < 5; x++) {
05039 y = ADSI_KEY_APPS + 12 + start + x;
05040 if (y > ADSI_KEY_APPS + 12 + 4)
05041 y = 0;
05042 keys[x] = ADSI_KEY_SKT | y;
05043 }
05044 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
05045 keys[6] = 0;
05046 keys[7] = 0;
05047
05048 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
05049 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
05050 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05051 bytes += ast_adsi_set_keys(buf + bytes, keys);
05052 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05053
05054 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05055 }
05056
05057 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
05058 {
05059 int bytes = 0;
05060 unsigned char buf[256];
05061 char buf1[256], buf2[256];
05062 char fn2[PATH_MAX];
05063
05064 char cid[256] = "";
05065 char *val;
05066 char *name, *num;
05067 char datetime[21] = "";
05068 FILE *f;
05069
05070 unsigned char keys[8];
05071
05072 int x;
05073
05074 if (!ast_adsi_available(chan))
05075 return;
05076
05077
05078 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
05079 f = fopen(fn2, "r");
05080 if (f) {
05081 while (!feof(f)) {
05082 if (!fgets((char *)buf, sizeof(buf), f)) {
05083 continue;
05084 }
05085 if (!feof(f)) {
05086 char *stringp = NULL;
05087 stringp = (char *)buf;
05088 strsep(&stringp, "=");
05089 val = strsep(&stringp, "=");
05090 if (!ast_strlen_zero(val)) {
05091 if (!strcmp((char *)buf, "callerid"))
05092 ast_copy_string(cid, val, sizeof(cid));
05093 if (!strcmp((char *)buf, "origdate"))
05094 ast_copy_string(datetime, val, sizeof(datetime));
05095 }
05096 }
05097 }
05098 fclose(f);
05099 }
05100
05101 for (x = 0; x < 5; x++)
05102 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05103 keys[6] = 0x0;
05104 keys[7] = 0x0;
05105
05106 if (!vms->curmsg) {
05107
05108 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05109 }
05110 if (vms->curmsg >= vms->lastmsg) {
05111
05112 if (vms->curmsg) {
05113
05114 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05115 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05116
05117 } else {
05118
05119 keys[3] = 1;
05120 }
05121 }
05122
05123 if (!ast_strlen_zero(cid)) {
05124 ast_callerid_parse(cid, &name, &num);
05125 if (!name)
05126 name = num;
05127 } else
05128 name = "Unknown Caller";
05129
05130
05131
05132 if (vms->deleted[vms->curmsg])
05133 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05134
05135
05136 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05137 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
05138 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
05139 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
05140
05141 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05142 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05143 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
05144 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
05145 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05146 bytes += ast_adsi_set_keys(buf + bytes, keys);
05147 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05148
05149 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05150 }
05151
05152 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
05153 {
05154 int bytes = 0;
05155 unsigned char buf[256];
05156 unsigned char keys[8];
05157
05158 int x;
05159
05160 if (!ast_adsi_available(chan))
05161 return;
05162
05163
05164 for (x = 0; x < 5; x++)
05165 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05166
05167 keys[6] = 0x0;
05168 keys[7] = 0x0;
05169
05170 if (!vms->curmsg) {
05171
05172 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05173 }
05174 if (vms->curmsg >= vms->lastmsg) {
05175
05176 if (vms->curmsg) {
05177
05178 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05179 } else {
05180
05181 keys[3] = 1;
05182 }
05183 }
05184
05185
05186 if (vms->deleted[vms->curmsg])
05187 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05188
05189
05190 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05191 bytes += ast_adsi_set_keys(buf + bytes, keys);
05192 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05193
05194 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05195 }
05196
05197 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
05198 {
05199 unsigned char buf[256] = "";
05200 char buf1[256] = "", buf2[256] = "";
05201 int bytes = 0;
05202 unsigned char keys[8];
05203 int x;
05204
05205 char *newm = (vms->newmessages == 1) ? "message" : "messages";
05206 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
05207 if (!ast_adsi_available(chan))
05208 return;
05209 if (vms->newmessages) {
05210 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
05211 if (vms->oldmessages) {
05212 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
05213 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
05214 } else {
05215 snprintf(buf2, sizeof(buf2), "%s.", newm);
05216 }
05217 } else if (vms->oldmessages) {
05218 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
05219 snprintf(buf2, sizeof(buf2), "%s.", oldm);
05220 } else {
05221 strcpy(buf1, "You have no messages.");
05222 buf2[0] = ' ';
05223 buf2[1] = '\0';
05224 }
05225 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05226 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05227 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05228
05229 for (x = 0; x < 6; x++)
05230 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05231 keys[6] = 0;
05232 keys[7] = 0;
05233
05234
05235 if (vms->lastmsg < 0)
05236 keys[0] = 1;
05237 bytes += ast_adsi_set_keys(buf + bytes, keys);
05238
05239 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05240
05241 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05242 }
05243
05244 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
05245 {
05246 unsigned char buf[256] = "";
05247 char buf1[256] = "", buf2[256] = "";
05248 int bytes = 0;
05249 unsigned char keys[8];
05250 int x;
05251
05252 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
05253
05254 if (!ast_adsi_available(chan))
05255 return;
05256
05257
05258 for (x = 0; x < 6; x++)
05259 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
05260
05261 keys[6] = 0;
05262 keys[7] = 0;
05263
05264 if ((vms->lastmsg + 1) < 1)
05265 keys[0] = 0;
05266
05267 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
05268 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
05269
05270 if (vms->lastmsg + 1)
05271 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
05272 else
05273 strcpy(buf2, "no messages.");
05274 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05275 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05276 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
05277 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05278 bytes += ast_adsi_set_keys(buf + bytes, keys);
05279
05280 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05281
05282 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05283
05284 }
05285
05286
05287
05288
05289
05290
05291
05292
05293
05294
05295
05296
05297
05298
05299
05300 static void adsi_goodbye(struct ast_channel *chan)
05301 {
05302 unsigned char buf[256];
05303 int bytes = 0;
05304
05305 if (!ast_adsi_available(chan))
05306 return;
05307 bytes += adsi_logo(buf + bytes);
05308 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
05309 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
05310 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05311 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05312
05313 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05314 }
05315
05316
05317
05318
05319
05320 static int get_folder(struct ast_channel *chan, int start)
05321 {
05322 int x;
05323 int d;
05324 char fn[PATH_MAX];
05325 d = ast_play_and_wait(chan, "vm-press");
05326 if (d)
05327 return d;
05328 for (x = start; x < 5; x++) {
05329 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
05330 return d;
05331 d = ast_play_and_wait(chan, "vm-for");
05332 if (d)
05333 return d;
05334 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
05335 d = vm_play_folder_name(chan, fn);
05336 if (d)
05337 return d;
05338 d = ast_waitfordigit(chan, 500);
05339 if (d)
05340 return d;
05341 }
05342 d = ast_play_and_wait(chan, "vm-tocancel");
05343 if (d)
05344 return d;
05345 d = ast_waitfordigit(chan, 4000);
05346 return d;
05347 }
05348
05349 static int get_folder2(struct ast_channel *chan, char *fn, int start)
05350 {
05351 int res = 0;
05352 res = ast_play_and_wait(chan, fn);
05353 while (((res < '0') || (res > '9')) &&
05354 (res != '#') && (res >= 0)) {
05355 res = get_folder(chan, 0);
05356 }
05357 return res;
05358 }
05359
05360 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts,
05361 char *context, signed char record_gain, long *duration, struct vm_state *vms)
05362 {
05363 int cmd = 0;
05364 int retries = 0, prepend_duration = 0, already_recorded = 0;
05365 signed char zero_gain = 0;
05366 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
05367 struct ast_config *msg_cfg;
05368 const char *duration_str;
05369 char msgfile[PATH_MAX], backup[PATH_MAX];
05370 char textfile[PATH_MAX];
05371
05372
05373 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
05374 strcpy(textfile, msgfile);
05375 strcpy(backup, msgfile);
05376 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
05377 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
05378
05379 if ((msg_cfg = ast_config_load(textfile, config_flags)) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
05380 *duration = atoi(duration_str);
05381 } else {
05382 *duration = 0;
05383 }
05384
05385 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
05386 if (cmd)
05387 retries = 0;
05388 switch (cmd) {
05389 case '1':
05390
05391 prepend_duration = 0;
05392
05393
05394 if (!msg_cfg) {
05395 cmd = 0;
05396 break;
05397 }
05398
05399
05400 if (already_recorded)
05401 ast_filecopy(backup, msgfile, NULL);
05402 else
05403 ast_filecopy(msgfile, backup, NULL);
05404 already_recorded = 1;
05405
05406 if (record_gain)
05407 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
05408
05409 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence);
05410 if (record_gain)
05411 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
05412
05413 if (prepend_duration) {
05414 struct ast_category *msg_cat;
05415
05416 char duration_str[12];
05417
05418 prepend_duration += *duration;
05419 msg_cat = ast_category_get(msg_cfg, "message");
05420 snprintf(duration_str, sizeof(duration_str), "%d", prepend_duration);
05421 if (!ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
05422 config_text_file_save(textfile, msg_cfg, "app_voicemail");
05423 STORE(curdir, vmu->mailbox, context, curmsg, chan, vmu, vmfmts, prepend_duration, vms);
05424 }
05425 }
05426
05427 break;
05428 case '2':
05429 cmd = 't';
05430 break;
05431 case '*':
05432 cmd = '*';
05433 break;
05434 default:
05435 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
05436
05437 if (!cmd)
05438 cmd = ast_play_and_wait(chan, "vm-starmain");
05439
05440 if (!cmd)
05441 cmd = ast_waitfordigit(chan, 6000);
05442 if (!cmd)
05443 retries++;
05444 if (retries > 3)
05445 cmd = 't';
05446 }
05447 }
05448
05449 if (msg_cfg)
05450 ast_config_destroy(msg_cfg);
05451 if (already_recorded)
05452 ast_filedelete(backup, NULL);
05453 if (prepend_duration)
05454 *duration = prepend_duration;
05455
05456 if (cmd == 't' || cmd == 'S')
05457 cmd = 0;
05458 return cmd;
05459 }
05460
05461 static void queue_mwi_event(const char *mbox, int new, int old)
05462 {
05463 struct ast_event *event;
05464 char *mailbox, *context;
05465
05466
05467 context = mailbox = ast_strdupa(mbox);
05468 strsep(&context, "@");
05469 if (ast_strlen_zero(context))
05470 context = "default";
05471
05472 if (!(event = ast_event_new(AST_EVENT_MWI,
05473 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
05474 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
05475 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, new,
05476 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
05477 AST_EVENT_IE_END))) {
05478 return;
05479 }
05480
05481 ast_event_queue_and_cache(event,
05482 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR,
05483 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR,
05484 AST_EVENT_IE_END);
05485 }
05486
05487 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)
05488 {
05489 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
05490 int newmsgs = 0, oldmsgs = 0;
05491 const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
05492 char *myserveremail = serveremail;
05493
05494 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
05495 make_file(fn, sizeof(fn), todir, msgnum);
05496 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
05497
05498 if (!ast_strlen_zero(vmu->attachfmt)) {
05499 if (strstr(fmt, vmu->attachfmt))
05500 fmt = vmu->attachfmt;
05501 else
05502 ast_log(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);
05503 }
05504
05505
05506 fmt = ast_strdupa(fmt);
05507 stringp = fmt;
05508 strsep(&stringp, "|");
05509
05510 if (!ast_strlen_zero(vmu->serveremail))
05511 myserveremail = vmu->serveremail;
05512
05513 if (!ast_strlen_zero(vmu->email)) {
05514 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
05515 if (!attach_user_voicemail)
05516 attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
05517
05518 if (attach_user_voicemail)
05519 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
05520
05521
05522 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
05523
05524 if (attach_user_voicemail)
05525 DISPOSE(todir, msgnum);
05526 }
05527
05528 if (!ast_strlen_zero(vmu->pager)) {
05529 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category);
05530 }
05531
05532 if (ast_test_flag(vmu, VM_DELETE))
05533 DELETE(todir, msgnum, fn, vmu);
05534
05535
05536 if (ast_app_has_voicemail(ext_context, NULL))
05537 ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
05538
05539 queue_mwi_event(ext_context, newmsgs, oldmsgs);
05540
05541 manager_event(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);
05542 run_externnotify(vmu->context, vmu->mailbox);
05543
05544 return 0;
05545 }
05546
05547 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int flag, signed char record_gain)
05548 {
05549 #ifdef IMAP_STORAGE
05550 int todircount = 0;
05551 struct vm_state *dstvms;
05552 #endif
05553 char username[70] = "";
05554 char fn[PATH_MAX];
05555 char ecodes[16] = "#";
05556 int res = 0, cmd = 0;
05557 struct ast_vm_user *receiver = NULL, *vmtmp;
05558 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
05559 char *stringp;
05560 const char *s;
05561 int saved_messages = 0, found = 0;
05562 int valid_extensions = 0;
05563 char *dir;
05564 int curmsg;
05565
05566 if (vms == NULL) return -1;
05567 dir = vms->curdir;
05568 curmsg = vms->curmsg;
05569
05570 while (!res && !valid_extensions) {
05571 int use_directory = 0;
05572 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
05573 int done = 0;
05574 int retries = 0;
05575 cmd = 0;
05576 while ((cmd >= 0) && !done) {
05577 if (cmd)
05578 retries = 0;
05579 switch (cmd) {
05580 case '1':
05581 use_directory = 0;
05582 done = 1;
05583 break;
05584 case '2':
05585 use_directory = 1;
05586 done = 1;
05587 break;
05588 case '*':
05589 cmd = 't';
05590 done = 1;
05591 break;
05592 default:
05593
05594 cmd = ast_play_and_wait(chan, "vm-forward");
05595 if (!cmd)
05596 cmd = ast_waitfordigit(chan, 3000);
05597 if (!cmd)
05598 retries++;
05599 if (retries > 3) {
05600 cmd = 't';
05601 done = 1;
05602 }
05603
05604 }
05605 }
05606 if (cmd < 0 || cmd == 't')
05607 break;
05608 }
05609
05610 if (use_directory) {
05611
05612
05613 char old_context[sizeof(chan->context)];
05614 char old_exten[sizeof(chan->exten)];
05615 int old_priority;
05616 struct ast_app* app;
05617
05618 app = pbx_findapp("Directory");
05619 if (app) {
05620 char vmcontext[256];
05621
05622 memcpy(old_context, chan->context, sizeof(chan->context));
05623 memcpy(old_exten, chan->exten, sizeof(chan->exten));
05624 old_priority = chan->priority;
05625
05626
05627 snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default");
05628 res = pbx_exec(chan, app, vmcontext);
05629
05630 ast_copy_string(username, chan->exten, sizeof(username));
05631
05632
05633 memcpy(chan->context, old_context, sizeof(chan->context));
05634 memcpy(chan->exten, old_exten, sizeof(chan->exten));
05635 chan->priority = old_priority;
05636
05637 } else {
05638 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
05639 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
05640 }
05641 } else {
05642
05643 res = ast_streamfile(chan, "vm-extension", chan->language);
05644 if (res)
05645 break;
05646 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
05647 break;
05648 }
05649
05650
05651 if (ast_strlen_zero(username))
05652 continue;
05653 stringp = username;
05654 s = strsep(&stringp, "*");
05655
05656 valid_extensions = 1;
05657 while (s) {
05658
05659 if ((flag == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
05660 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
05661 found++;
05662 } else {
05663 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
05664 free_user(receiver);
05665 }
05666 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
05667 valid_extensions = 0;
05668 break;
05669 }
05670
05671
05672 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
05673 RETRIEVE(fn, -1, s, receiver->context);
05674 if (ast_fileexists(fn, NULL, NULL) > 0) {
05675 res = ast_stream_and_wait(chan, fn, ecodes);
05676 if (res) {
05677 DISPOSE(fn, -1);
05678 return res;
05679 }
05680 } else {
05681 res = ast_say_digit_str(chan, s, ecodes, chan->language);
05682 }
05683 DISPOSE(fn, -1);
05684
05685 s = strsep(&stringp, "*");
05686 }
05687
05688 if (valid_extensions)
05689 break;
05690
05691 res = ast_play_and_wait(chan, "pbx-invalid");
05692 }
05693
05694 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
05695 return res;
05696 if (flag==1) {
05697 struct leave_vm_options leave_options;
05698 char mailbox[AST_MAX_EXTENSION * 2 + 2];
05699
05700 if (context)
05701 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
05702 else
05703 ast_copy_string(mailbox, username, sizeof(mailbox));
05704
05705
05706 memset(&leave_options, 0, sizeof(leave_options));
05707 leave_options.record_gain = record_gain;
05708 cmd = leave_voicemail(chan, mailbox, &leave_options);
05709 } else {
05710
05711 long duration = 0;
05712 char origmsgfile[PATH_MAX], msgfile[PATH_MAX];
05713 struct vm_state vmstmp;
05714 memcpy(&vmstmp, vms, sizeof(vmstmp));
05715
05716 make_file(origmsgfile, sizeof(origmsgfile), dir, curmsg);
05717 create_dirpath(vmstmp.curdir, sizeof(vmstmp.curdir), sender->context, vmstmp.username, "tmp");
05718 make_file(msgfile, sizeof(msgfile), vmstmp.curdir, curmsg);
05719
05720 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
05721
05722
05723 copy_plain_file(origmsgfile, msgfile);
05724
05725 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp);
05726 if (!cmd) {
05727 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
05728 #ifdef IMAP_STORAGE
05729 char *myserveremail = serveremail;
05730 int attach_user_voicemail;
05731
05732 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, 0);
05733 if (!dstvms) {
05734 dstvms = create_vm_state_from_user(vmtmp);
05735 }
05736 if (dstvms) {
05737 init_mailstream(dstvms, 0);
05738 if (!dstvms->mailstream) {
05739 ast_log(LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
05740 } else {
05741 STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
05742 run_externnotify(vmtmp->context, vmtmp->mailbox);
05743 }
05744 } else {
05745 ast_log(LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
05746 }
05747 if (!ast_strlen_zero(vmtmp->serveremail))
05748 myserveremail = vmtmp->serveremail;
05749 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
05750
05751 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
05752 #else
05753 copy_message(chan, sender, -1, curmsg, duration, vmtmp, fmt, vmstmp.curdir);
05754 #endif
05755 saved_messages++;
05756 AST_LIST_REMOVE_CURRENT(list);
05757 free_user(vmtmp);
05758 if (res)
05759 break;
05760 }
05761 AST_LIST_TRAVERSE_SAFE_END;
05762 if (saved_messages > 0) {
05763
05764
05765
05766
05767
05768
05769
05770
05771 res = ast_play_and_wait(chan, "vm-msgsaved");
05772 }
05773 }
05774
05775 DISPOSE(dir, curmsg);
05776 }
05777
05778
05779 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
05780 free_user(vmtmp);
05781 return res ? res : cmd;
05782 }
05783
05784 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
05785 {
05786 int res;
05787 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
05788 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
05789 return res;
05790 }
05791
05792 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
05793 {
05794 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);
05795 }
05796
05797 static int play_message_category(struct ast_channel *chan, const char *category)
05798 {
05799 int res = 0;
05800
05801 if (!ast_strlen_zero(category))
05802 res = ast_play_and_wait(chan, category);
05803
05804 if (res) {
05805 ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
05806 res = 0;
05807 }
05808
05809 return res;
05810 }
05811
05812 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
05813 {
05814 int res = 0;
05815 struct vm_zone *the_zone = NULL;
05816 time_t t;
05817
05818 if (ast_get_time_t(origtime, &t, 0, NULL)) {
05819 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
05820 return 0;
05821 }
05822
05823
05824 if (!ast_strlen_zero(vmu->zonetag)) {
05825
05826 struct vm_zone *z;
05827 AST_LIST_LOCK(&zones);
05828 AST_LIST_TRAVERSE(&zones, z, list) {
05829 if (!strcmp(z->name, vmu->zonetag)) {
05830 the_zone = z;
05831 break;
05832 }
05833 }
05834 AST_LIST_UNLOCK(&zones);
05835 }
05836
05837
05838 #if 0
05839
05840 ast_localtime(&t, &time_now, NULL);
05841 tv_now = ast_tvnow();
05842 ast_localtime(&tv_now, &time_then, NULL);
05843
05844
05845 if (time_now.tm_year == time_then.tm_year)
05846 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
05847 else
05848 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
05849 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
05850
05851
05852 #endif
05853 if (the_zone) {
05854 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
05855 }
05856 else if (!strcasecmp(chan->language,"pl"))
05857 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
05858 else if (!strcasecmp(chan->language, "se"))
05859 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
05860 else if (!strcasecmp(chan->language, "no"))
05861 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05862 else if (!strcasecmp(chan->language, "de"))
05863 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05864 else if (!strcasecmp(chan->language, "nl"))
05865 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
05866 else if (!strcasecmp(chan->language, "it"))
05867 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);
05868 else if (!strcasecmp(chan->language, "gr"))
05869 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
05870 else if (!strcasecmp(chan->language, "pt_BR"))
05871 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);
05872 else if (!strcasecmp(chan->language, "tw"))
05873 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
05874 else {
05875 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
05876 }
05877 #if 0
05878 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
05879 #endif
05880 return res;
05881 }
05882
05883
05884
05885 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
05886 {
05887 int res = 0;
05888 int i;
05889 char *callerid, *name;
05890 char prefile[PATH_MAX] = "";
05891
05892
05893
05894
05895
05896
05897
05898
05899
05900 if ((cid == NULL)||(context == NULL))
05901 return res;
05902
05903
05904 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
05905 ast_callerid_parse(cid, &name, &callerid);
05906 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
05907
05908
05909 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++) {
05910 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
05911 if ((strcmp(cidinternalcontexts[i], context) == 0))
05912 break;
05913 }
05914 if (i != MAX_NUM_CID_CONTEXTS) {
05915 if (!res) {
05916 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
05917 if (!ast_strlen_zero(prefile)) {
05918
05919 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05920 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
05921 if (!callback)
05922 res = wait_file2(chan, vms, "vm-from");
05923 res = ast_stream_and_wait(chan, prefile, "");
05924 } else {
05925 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
05926
05927 if (!callback)
05928 res = wait_file2(chan, vms, "vm-from-extension");
05929 res = ast_say_digit_str(chan, callerid, "", chan->language);
05930 }
05931 }
05932 }
05933 } else if (!res) {
05934 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
05935
05936 if (!callback)
05937 res = wait_file2(chan, vms, "vm-from-phonenumber");
05938 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
05939 }
05940 } else {
05941
05942 ast_debug(1, "VM-CID: From an unknown number\n");
05943
05944 res = wait_file2(chan, vms, "vm-unknown-caller");
05945 }
05946 return res;
05947 }
05948
05949 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
05950 {
05951 int res = 0;
05952 int durationm;
05953 int durations;
05954
05955 if (duration == NULL)
05956 return res;
05957
05958
05959 durations = atoi(duration);
05960 durationm = durations / 60;
05961
05962 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
05963
05964 if ((!res) && (durationm >= minduration)) {
05965 res = wait_file2(chan, vms, "vm-duration");
05966
05967
05968 if (!strcasecmp(chan->language, "pl")) {
05969 div_t num = div(durationm, 10);
05970
05971 if (durationm == 1) {
05972 res = ast_play_and_wait(chan, "digits/1z");
05973 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
05974 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05975 if (num.rem == 2) {
05976 if (!num.quot) {
05977 res = ast_play_and_wait(chan, "digits/2-ie");
05978 } else {
05979 res = say_and_wait(chan, durationm - 2 , chan->language);
05980 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05981 }
05982 } else {
05983 res = say_and_wait(chan, durationm, chan->language);
05984 }
05985 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
05986 } else {
05987 res = say_and_wait(chan, durationm, chan->language);
05988 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
05989 }
05990
05991 } else {
05992 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
05993 res = wait_file2(chan, vms, "vm-minutes");
05994 }
05995 }
05996 return res;
05997 }
05998
05999 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
06000 {
06001 int res = 0;
06002 char filename[256], *cid;
06003 const char *origtime, *context, *category, *duration;
06004 struct ast_config *msg_cfg;
06005 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06006
06007 vms->starting = 0;
06008 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06009 adsi_message(chan, vms);
06010 if (!vms->curmsg)
06011 res = wait_file2(chan, vms, "vm-first");
06012 else if (vms->curmsg == vms->lastmsg)
06013 res = wait_file2(chan, vms, "vm-last");
06014 if (!res) {
06015
06016 if (!strcasecmp(chan->language, "pl")) {
06017 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06018 int ten, one;
06019 char nextmsg[256];
06020 ten = (vms->curmsg + 1) / 10;
06021 one = (vms->curmsg + 1) % 10;
06022
06023 if (vms->curmsg < 20) {
06024 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
06025 res = wait_file2(chan, vms, nextmsg);
06026 } else {
06027 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
06028 res = wait_file2(chan, vms, nextmsg);
06029 if (one > 0) {
06030 if (!res) {
06031 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
06032 res = wait_file2(chan, vms, nextmsg);
06033 }
06034 }
06035 }
06036 }
06037 if (!res)
06038 res = wait_file2(chan, vms, "vm-message");
06039 } else {
06040 if (!strcasecmp(chan->language, "se"))
06041 res = wait_file2(chan, vms, "vm-meddelandet");
06042 else {
06043 res = wait_file2(chan, vms, "vm-message");
06044 }
06045 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
06046 if (!res) {
06047 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
06048 }
06049 }
06050 }
06051 }
06052
06053
06054 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
06055 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
06056 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
06057 msg_cfg = ast_config_load(filename, config_flags);
06058 if (!msg_cfg) {
06059 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06060 return 0;
06061 }
06062
06063 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
06064 ast_log(LOG_WARNING, "No origtime?!\n");
06065 DISPOSE(vms->curdir, vms->curmsg);
06066 ast_config_destroy(msg_cfg);
06067 return 0;
06068 }
06069
06070 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
06071 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
06072 category = ast_variable_retrieve(msg_cfg, "message", "category");
06073
06074 context = ast_variable_retrieve(msg_cfg, "message", "context");
06075 if (!strncasecmp("macro", context, 5))
06076 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
06077 if (!res) {
06078 res = play_message_category(chan, category);
06079 }
06080 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
06081 res = play_message_datetime(chan, vmu, origtime, filename);
06082 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
06083 res = play_message_callerid(chan, vms, cid, context, 0);
06084 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
06085 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
06086
06087 if (res == '1')
06088 res = 0;
06089 ast_config_destroy(msg_cfg);
06090
06091 if (!res) {
06092 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06093 vms->heard[vms->curmsg] = 1;
06094 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
06095 ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn);
06096 res = 0;
06097 }
06098 }
06099 DISPOSE(vms->curdir, vms->curmsg);
06100 return res;
06101 }
06102
06103 #ifdef IMAP_STORAGE
06104 static int imap_remove_file(char *dir, int msgnum)
06105 {
06106 char fn[PATH_MAX];
06107 char full_fn[PATH_MAX];
06108
06109 if (msgnum > -1) {
06110 make_file(fn, sizeof(fn), dir, msgnum);
06111 } else
06112 ast_copy_string(fn, dir, sizeof(fn));
06113
06114 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
06115 ast_filedelete(fn, NULL);
06116 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
06117 unlink(full_fn);
06118 }
06119 return 0;
06120 }
06121
06122 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
06123 {
06124 char *file, *filename;
06125 char *attachment;
06126 char arg[10];
06127 int i;
06128 BODY* body;
06129
06130
06131 file = strrchr(ast_strdupa(dir), '/');
06132 if (file)
06133 *file++ = '\0';
06134 else {
06135 ast_log(LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
06136 return -1;
06137 }
06138
06139 ast_mutex_lock(&vms->lock);
06140 for (i = 0; i < vms->mailstream->nmsgs; i++) {
06141 mail_fetchstructure(vms->mailstream, i + 1, &body);
06142
06143 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
06144 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
06145 } else {
06146 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
06147 ast_mutex_unlock(&vms->lock);
06148 return -1;
06149 }
06150 filename = strsep(&attachment, ".");
06151 if (!strcmp(filename, file)) {
06152 sprintf (arg, "%d", i + 1);
06153 mail_setflag(vms->mailstream, arg, "\\DELETED");
06154 }
06155 }
06156 mail_expunge(vms->mailstream);
06157 ast_mutex_unlock(&vms->lock);
06158 return 0;
06159 }
06160
06161 #else
06162 #ifndef IMAP_STORAGE
06163 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
06164 {
06165 int res = 0;
06166 int count_msg, last_msg;
06167
06168 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
06169
06170
06171
06172
06173 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
06174
06175
06176 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
06177
06178 count_msg = count_messages(vmu, vms->curdir);
06179 if (count_msg < 0)
06180 return count_msg;
06181 else
06182 vms->lastmsg = count_msg - 1;
06183
06184
06185
06186
06187
06188
06189
06190
06191 if (vm_lock_path(vms->curdir)) {
06192 ast_log(LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
06193 return -1;
06194 }
06195
06196 last_msg = last_message_index(vmu, vms->curdir);
06197 ast_unlock_path(vms->curdir);
06198
06199 if (last_msg < 0)
06200 return last_msg;
06201 else if (vms->lastmsg != last_msg) {
06202 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s\n", vms->curdir);
06203 res = resequence_mailbox(vmu, vms->curdir);
06204 if (res)
06205 return res;
06206 }
06207
06208 return 0;
06209 }
06210 #endif
06211 #endif
06212
06213 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
06214 {
06215 int x = 0;
06216 #ifndef IMAP_STORAGE
06217 int res = 0, nummsg;
06218 #endif
06219
06220 if (vms->lastmsg <= -1)
06221 goto done;
06222
06223 vms->curmsg = -1;
06224 #ifndef IMAP_STORAGE
06225
06226 if (vm_lock_path(vms->curdir))
06227 return ERROR_LOCK_PATH;
06228
06229 for (x = 0; x < vmu->maxmsg; x++) {
06230 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
06231
06232 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06233 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
06234 break;
06235 vms->curmsg++;
06236 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
06237 if (strcmp(vms->fn, vms->fn2)) {
06238 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
06239 }
06240 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
06241
06242 res = save_to_folder(vmu, vms, x, 1);
06243 if (res == ERROR_LOCK_PATH || res == ERROR_MAILBOX_FULL) {
06244
06245 ast_log(LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
06246 vms->deleted[x] = 0;
06247 vms->heard[x] = 0;
06248 --x;
06249 }
06250 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
06251
06252 res = save_to_folder(vmu, vms, x, 10);
06253 if (res == ERROR_LOCK_PATH) {
06254
06255 vms->deleted[x] = 0;
06256 vms->heard[x] = 0;
06257 --x;
06258 }
06259 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
06260
06261
06262 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06263 if (EXISTS(vms->curdir, x, vms->fn, NULL))
06264 DELETE(vms->curdir, x, vms->fn, vmu);
06265 }
06266 }
06267
06268
06269 nummsg = x - 1;
06270 for (x = vms->curmsg + 1; x <= nummsg; x++) {
06271 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
06272 if (EXISTS(vms->curdir, x, vms->fn, NULL))
06273 DELETE(vms->curdir, x, vms->fn, vmu);
06274 }
06275 ast_unlock_path(vms->curdir);
06276 #else
06277 if (vms->deleted) {
06278 for (x = 0; x < vmu->maxmsg; x++) {
06279 if (vms->deleted[x]) {
06280 ast_debug(3, "IMAP delete of %d\n", x);
06281 DELETE(vms->curdir, x, vms->fn, vmu);
06282 }
06283 }
06284 }
06285 #endif
06286
06287 done:
06288 if (vms->deleted)
06289 memset(vms->deleted, 0, vmu->maxmsg * sizeof(int));
06290 if (vms->heard)
06291 memset(vms->heard, 0, vmu->maxmsg * sizeof(int));
06292
06293 return 0;
06294 }
06295
06296
06297
06298
06299
06300
06301
06302 static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
06303 {
06304 int cmd;
06305 char *buf;
06306
06307 buf = alloca(strlen(mbox) + 2);
06308 strcpy(buf, mbox);
06309 strcat(buf, "s");
06310
06311 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
06312 cmd = ast_play_and_wait(chan, buf);
06313 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06314 } else {
06315 cmd = ast_play_and_wait(chan, "vm-messages");
06316 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06317 }
06318 }
06319
06320 static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
06321 {
06322 int cmd;
06323
06324 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
06325 if (!strcasecmp(mbox, "vm-INBOX"))
06326 cmd = ast_play_and_wait(chan, "vm-new-e");
06327 else
06328 cmd = ast_play_and_wait(chan, "vm-old-e");
06329 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06330 } else {
06331 cmd = ast_play_and_wait(chan, "vm-messages");
06332 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06333 }
06334 }
06335
06336 static int vm_play_folder_name_ua(struct ast_channel *chan, char *mbox)
06337 {
06338 int cmd;
06339
06340 if (!strcasecmp(mbox, "vm-Family") || !strcasecmp(mbox, "vm-Friends") || !strcasecmp(mbox, "vm-Work")) {
06341 cmd = ast_play_and_wait(chan, "vm-messages");
06342 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06343 } else {
06344 cmd = ast_play_and_wait(chan, mbox);
06345 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06346 }
06347 }
06348
06349 static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
06350 {
06351 int cmd;
06352
06353 if (!strcasecmp(chan->language, "it") || !strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) {
06354 cmd = ast_play_and_wait(chan, "vm-messages");
06355 return cmd ? cmd : ast_play_and_wait(chan, mbox);
06356 } else if (!strcasecmp(chan->language, "gr")) {
06357 return vm_play_folder_name_gr(chan, mbox);
06358 } else if (!strcasecmp(chan->language, "pl")) {
06359 return vm_play_folder_name_pl(chan, mbox);
06360 } else if (!strcasecmp(chan->language, "ua")) {
06361 return vm_play_folder_name_ua(chan, mbox);
06362 } else {
06363 cmd = ast_play_and_wait(chan, mbox);
06364 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
06365 }
06366 }
06367
06368
06369
06370
06371
06372
06373
06374
06375
06376
06377
06378
06379
06380 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
06381 {
06382 int res = 0;
06383
06384 if (vms->newmessages) {
06385 res = ast_play_and_wait(chan, "vm-youhave");
06386 if (!res)
06387 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
06388 if (!res) {
06389 if ((vms->newmessages == 1)) {
06390 res = ast_play_and_wait(chan, "vm-INBOX");
06391 if (!res)
06392 res = ast_play_and_wait(chan, "vm-message");
06393 } else {
06394 res = ast_play_and_wait(chan, "vm-INBOXs");
06395 if (!res)
06396 res = ast_play_and_wait(chan, "vm-messages");
06397 }
06398 }
06399 } else if (vms->oldmessages) {
06400 res = ast_play_and_wait(chan, "vm-youhave");
06401 if (!res)
06402 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
06403 if ((vms->oldmessages == 1)) {
06404 res = ast_play_and_wait(chan, "vm-Old");
06405 if (!res)
06406 res = ast_play_and_wait(chan, "vm-message");
06407 } else {
06408 res = ast_play_and_wait(chan, "vm-Olds");
06409 if (!res)
06410 res = ast_play_and_wait(chan, "vm-messages");
06411 }
06412 } else if (!vms->oldmessages && !vms->newmessages)
06413 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
06414 return res;
06415 }
06416
06417
06418
06419
06420
06421
06422
06423
06424
06425
06426
06427
06428
06429
06430
06431
06432
06433
06434
06435
06436
06437
06438
06439
06440
06441
06442
06443
06444
06445
06446
06447
06448
06449
06450
06451
06452
06453
06454
06455
06456
06457
06458
06459
06460
06461
06462
06463
06464
06465
06466
06467
06468
06469
06470
06471
06472
06473
06474 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
06475 {
06476 int res;
06477 int lastnum = 0;
06478
06479 res = ast_play_and_wait(chan, "vm-youhave");
06480
06481 if (!res && vms->newmessages) {
06482 lastnum = vms->newmessages;
06483
06484 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06485 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
06486 }
06487
06488 if (!res && vms->oldmessages) {
06489 res = ast_play_and_wait(chan, "vm-and");
06490 }
06491 }
06492
06493 if (!res && vms->oldmessages) {
06494 lastnum = vms->oldmessages;
06495
06496 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
06497 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
06498 }
06499 }
06500
06501 if (!res) {
06502 if (lastnum == 0) {
06503 res = ast_play_and_wait(chan, "vm-no");
06504 }
06505 if (!res) {
06506 res = ast_say_counted_noun(chan, lastnum, "vm-message");
06507 }
06508 }
06509
06510 return res;
06511 }
06512
06513
06514 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
06515 {
06516 int res;
06517
06518
06519 res = ast_play_and_wait(chan, "vm-youhave");
06520 if (!res) {
06521 if (vms->newmessages) {
06522 res = say_and_wait(chan, vms->newmessages, chan->language);
06523 if (!res)
06524 res = ast_play_and_wait(chan, "vm-INBOX");
06525 if (vms->oldmessages && !res)
06526 res = ast_play_and_wait(chan, "vm-and");
06527 else if (!res) {
06528 if ((vms->newmessages == 1))
06529 res = ast_play_and_wait(chan, "vm-message");
06530 else
06531 res = ast_play_and_wait(chan, "vm-messages");
06532 }
06533
06534 }
06535 if (!res && vms->oldmessages) {
06536 res = say_and_wait(chan, vms->oldmessages, chan->language);
06537 if (!res)
06538 res = ast_play_and_wait(chan, "vm-Old");
06539 if (!res) {
06540 if (vms->oldmessages == 1)
06541 res = ast_play_and_wait(chan, "vm-message");
06542 else
06543 res = ast_play_and_wait(chan, "vm-messages");
06544 }
06545 }
06546 if (!res) {
06547 if (!vms->oldmessages && !vms->newmessages) {
06548 res = ast_play_and_wait(chan, "vm-no");
06549 if (!res)
06550 res = ast_play_and_wait(chan, "vm-messages");
06551 }
06552 }
06553 }
06554 return res;
06555 }
06556
06557
06558 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
06559 {
06560
06561 int res;
06562 if (!vms->oldmessages && !vms->newmessages)
06563 res = ast_play_and_wait(chan, "vm-no") ||
06564 ast_play_and_wait(chan, "vm-message");
06565 else
06566 res = ast_play_and_wait(chan, "vm-youhave");
06567 if (!res && vms->newmessages) {
06568 res = (vms->newmessages == 1) ?
06569 ast_play_and_wait(chan, "digits/un") ||
06570 ast_play_and_wait(chan, "vm-nuovo") ||
06571 ast_play_and_wait(chan, "vm-message") :
06572
06573 say_and_wait(chan, vms->newmessages, chan->language) ||
06574 ast_play_and_wait(chan, "vm-nuovi") ||
06575 ast_play_and_wait(chan, "vm-messages");
06576 if (!res && vms->oldmessages)
06577 res = ast_play_and_wait(chan, "vm-and");
06578 }
06579 if (!res && vms->oldmessages) {
06580 res = (vms->oldmessages == 1) ?
06581 ast_play_and_wait(chan, "digits/un") ||
06582 ast_play_and_wait(chan, "vm-vecchio") ||
06583 ast_play_and_wait(chan, "vm-message") :
06584
06585 say_and_wait(chan, vms->oldmessages, chan->language) ||
06586 ast_play_and_wait(chan, "vm-vecchi") ||
06587 ast_play_and_wait(chan, "vm-messages");
06588 }
06589 return res;
06590 }
06591
06592
06593 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
06594 {
06595
06596 int res;
06597 div_t num;
06598
06599 if (!vms->oldmessages && !vms->newmessages) {
06600 res = ast_play_and_wait(chan, "vm-no");
06601 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06602 return res;
06603 } else {
06604 res = ast_play_and_wait(chan, "vm-youhave");
06605 }
06606
06607 if (vms->newmessages) {
06608 num = div(vms->newmessages, 10);
06609 if (vms->newmessages == 1) {
06610 res = ast_play_and_wait(chan, "digits/1-a");
06611 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
06612 res = res ? res : ast_play_and_wait(chan, "vm-message");
06613 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06614 if (num.rem == 2) {
06615 if (!num.quot) {
06616 res = ast_play_and_wait(chan, "digits/2-ie");
06617 } else {
06618 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
06619 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06620 }
06621 } else {
06622 res = say_and_wait(chan, vms->newmessages, chan->language);
06623 }
06624 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
06625 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06626 } else {
06627 res = say_and_wait(chan, vms->newmessages, chan->language);
06628 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
06629 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06630 }
06631 if (!res && vms->oldmessages)
06632 res = ast_play_and_wait(chan, "vm-and");
06633 }
06634 if (!res && vms->oldmessages) {
06635 num = div(vms->oldmessages, 10);
06636 if (vms->oldmessages == 1) {
06637 res = ast_play_and_wait(chan, "digits/1-a");
06638 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
06639 res = res ? res : ast_play_and_wait(chan, "vm-message");
06640 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06641 if (num.rem == 2) {
06642 if (!num.quot) {
06643 res = ast_play_and_wait(chan, "digits/2-ie");
06644 } else {
06645 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
06646 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06647 }
06648 } else {
06649 res = say_and_wait(chan, vms->oldmessages, chan->language);
06650 }
06651 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
06652 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06653 } else {
06654 res = say_and_wait(chan, vms->oldmessages, chan->language);
06655 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
06656 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06657 }
06658 }
06659
06660 return res;
06661 }
06662
06663
06664 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
06665 {
06666
06667 int res;
06668
06669 res = ast_play_and_wait(chan, "vm-youhave");
06670 if (res)
06671 return res;
06672
06673 if (!vms->oldmessages && !vms->newmessages) {
06674 res = ast_play_and_wait(chan, "vm-no");
06675 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06676 return res;
06677 }
06678
06679 if (vms->newmessages) {
06680 if ((vms->newmessages == 1)) {
06681 res = ast_play_and_wait(chan, "digits/ett");
06682 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
06683 res = res ? res : ast_play_and_wait(chan, "vm-message");
06684 } else {
06685 res = say_and_wait(chan, vms->newmessages, chan->language);
06686 res = res ? res : ast_play_and_wait(chan, "vm-nya");
06687 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06688 }
06689 if (!res && vms->oldmessages)
06690 res = ast_play_and_wait(chan, "vm-and");
06691 }
06692 if (!res && vms->oldmessages) {
06693 if (vms->oldmessages == 1) {
06694 res = ast_play_and_wait(chan, "digits/ett");
06695 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
06696 res = res ? res : ast_play_and_wait(chan, "vm-message");
06697 } else {
06698 res = say_and_wait(chan, vms->oldmessages, chan->language);
06699 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
06700 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06701 }
06702 }
06703
06704 return res;
06705 }
06706
06707
06708 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
06709 {
06710
06711 int res;
06712
06713 res = ast_play_and_wait(chan, "vm-youhave");
06714 if (res)
06715 return res;
06716
06717 if (!vms->oldmessages && !vms->newmessages) {
06718 res = ast_play_and_wait(chan, "vm-no");
06719 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06720 return res;
06721 }
06722
06723 if (vms->newmessages) {
06724 if ((vms->newmessages == 1)) {
06725 res = ast_play_and_wait(chan, "digits/1");
06726 res = res ? res : ast_play_and_wait(chan, "vm-ny");
06727 res = res ? res : ast_play_and_wait(chan, "vm-message");
06728 } else {
06729 res = say_and_wait(chan, vms->newmessages, chan->language);
06730 res = res ? res : ast_play_and_wait(chan, "vm-nye");
06731 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06732 }
06733 if (!res && vms->oldmessages)
06734 res = ast_play_and_wait(chan, "vm-and");
06735 }
06736 if (!res && vms->oldmessages) {
06737 if (vms->oldmessages == 1) {
06738 res = ast_play_and_wait(chan, "digits/1");
06739 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
06740 res = res ? res : ast_play_and_wait(chan, "vm-message");
06741 } else {
06742 res = say_and_wait(chan, vms->oldmessages, chan->language);
06743 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
06744 res = res ? res : ast_play_and_wait(chan, "vm-messages");
06745 }
06746 }
06747
06748 return res;
06749 }
06750
06751
06752 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
06753 {
06754
06755 int res;
06756 res = ast_play_and_wait(chan, "vm-youhave");
06757 if (!res) {
06758 if (vms->newmessages) {
06759 if ((vms->newmessages == 1))
06760 res = ast_play_and_wait(chan, "digits/1F");
06761 else
06762 res = say_and_wait(chan, vms->newmessages, chan->language);
06763 if (!res)
06764 res = ast_play_and_wait(chan, "vm-INBOX");
06765 if (vms->oldmessages && !res)
06766 res = ast_play_and_wait(chan, "vm-and");
06767 else if (!res) {
06768 if ((vms->newmessages == 1))
06769 res = ast_play_and_wait(chan, "vm-message");
06770 else
06771 res = ast_play_and_wait(chan, "vm-messages");
06772 }
06773
06774 }
06775 if (!res && vms->oldmessages) {
06776 if (vms->oldmessages == 1)
06777 res = ast_play_and_wait(chan, "digits/1F");
06778 else
06779 res = say_and_wait(chan, vms->oldmessages, chan->language);
06780 if (!res)
06781 res = ast_play_and_wait(chan, "vm-Old");
06782 if (!res) {
06783 if (vms->oldmessages == 1)
06784 res = ast_play_and_wait(chan, "vm-message");
06785 else
06786 res = ast_play_and_wait(chan, "vm-messages");
06787 }
06788 }
06789 if (!res) {
06790 if (!vms->oldmessages && !vms->newmessages) {
06791 res = ast_play_and_wait(chan, "vm-no");
06792 if (!res)
06793 res = ast_play_and_wait(chan, "vm-messages");
06794 }
06795 }
06796 }
06797 return res;
06798 }
06799
06800
06801 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
06802 {
06803
06804 int res;
06805 if (!vms->oldmessages && !vms->newmessages) {
06806 res = ast_play_and_wait(chan, "vm-youhaveno");
06807 if (!res)
06808 res = ast_play_and_wait(chan, "vm-messages");
06809 } else {
06810 res = ast_play_and_wait(chan, "vm-youhave");
06811 }
06812 if (!res) {
06813 if (vms->newmessages) {
06814 if (!res) {
06815 if ((vms->newmessages == 1)) {
06816 res = ast_play_and_wait(chan, "digits/1M");
06817 if (!res)
06818 res = ast_play_and_wait(chan, "vm-message");
06819 if (!res)
06820 res = ast_play_and_wait(chan, "vm-INBOXs");
06821 } else {
06822 res = say_and_wait(chan, vms->newmessages, chan->language);
06823 if (!res)
06824 res = ast_play_and_wait(chan, "vm-messages");
06825 if (!res)
06826 res = ast_play_and_wait(chan, "vm-INBOX");
06827 }
06828 }
06829 if (vms->oldmessages && !res)
06830 res = ast_play_and_wait(chan, "vm-and");
06831 }
06832 if (vms->oldmessages) {
06833 if (!res) {
06834 if (vms->oldmessages == 1) {
06835 res = ast_play_and_wait(chan, "digits/1M");
06836 if (!res)
06837 res = ast_play_and_wait(chan, "vm-message");
06838 if (!res)
06839 res = ast_play_and_wait(chan, "vm-Olds");
06840 } else {
06841 res = say_and_wait(chan, vms->oldmessages, chan->language);
06842 if (!res)
06843 res = ast_play_and_wait(chan, "vm-messages");
06844 if (!res)
06845 res = ast_play_and_wait(chan, "vm-Old");
06846 }
06847 }
06848 }
06849 }
06850 return res;
06851 }
06852
06853
06854 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
06855
06856 int res;
06857 if (!vms->oldmessages && !vms->newmessages) {
06858 res = ast_play_and_wait(chan, "vm-nomessages");
06859 return res;
06860 } else {
06861 res = ast_play_and_wait(chan, "vm-youhave");
06862 }
06863 if (vms->newmessages) {
06864 if (!res)
06865 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06866 if ((vms->newmessages == 1)) {
06867 if (!res)
06868 res = ast_play_and_wait(chan, "vm-message");
06869 if (!res)
06870 res = ast_play_and_wait(chan, "vm-INBOXs");
06871 } else {
06872 if (!res)
06873 res = ast_play_and_wait(chan, "vm-messages");
06874 if (!res)
06875 res = ast_play_and_wait(chan, "vm-INBOX");
06876 }
06877 if (vms->oldmessages && !res)
06878 res = ast_play_and_wait(chan, "vm-and");
06879 }
06880 if (vms->oldmessages) {
06881 if (!res)
06882 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06883 if (vms->oldmessages == 1) {
06884 if (!res)
06885 res = ast_play_and_wait(chan, "vm-message");
06886 if (!res)
06887 res = ast_play_and_wait(chan, "vm-Olds");
06888 } else {
06889 if (!res)
06890 res = ast_play_and_wait(chan, "vm-messages");
06891 if (!res)
06892 res = ast_play_and_wait(chan, "vm-Old");
06893 }
06894 }
06895 return res;
06896 }
06897
06898
06899 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
06900 {
06901
06902 int res;
06903 res = ast_play_and_wait(chan, "vm-youhave");
06904 if (!res) {
06905 if (vms->newmessages) {
06906 res = say_and_wait(chan, vms->newmessages, chan->language);
06907 if (!res)
06908 res = ast_play_and_wait(chan, "vm-INBOX");
06909 if (vms->oldmessages && !res)
06910 res = ast_play_and_wait(chan, "vm-and");
06911 else if (!res) {
06912 if ((vms->newmessages == 1))
06913 res = ast_play_and_wait(chan, "vm-message");
06914 else
06915 res = ast_play_and_wait(chan, "vm-messages");
06916 }
06917
06918 }
06919 if (!res && vms->oldmessages) {
06920 res = say_and_wait(chan, vms->oldmessages, chan->language);
06921 if (!res)
06922 res = ast_play_and_wait(chan, "vm-Old");
06923 if (!res) {
06924 if (vms->oldmessages == 1)
06925 res = ast_play_and_wait(chan, "vm-message");
06926 else
06927 res = ast_play_and_wait(chan, "vm-messages");
06928 }
06929 }
06930 if (!res) {
06931 if (!vms->oldmessages && !vms->newmessages) {
06932 res = ast_play_and_wait(chan, "vm-no");
06933 if (!res)
06934 res = ast_play_and_wait(chan, "vm-messages");
06935 }
06936 }
06937 }
06938 return res;
06939 }
06940
06941
06942 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
06943 {
06944
06945 int res;
06946 res = ast_play_and_wait(chan, "vm-youhave");
06947 if (!res) {
06948 if (vms->newmessages) {
06949 res = say_and_wait(chan, vms->newmessages, chan->language);
06950 if (!res) {
06951 if (vms->newmessages == 1)
06952 res = ast_play_and_wait(chan, "vm-INBOXs");
06953 else
06954 res = ast_play_and_wait(chan, "vm-INBOX");
06955 }
06956 if (vms->oldmessages && !res)
06957 res = ast_play_and_wait(chan, "vm-and");
06958 else if (!res) {
06959 if ((vms->newmessages == 1))
06960 res = ast_play_and_wait(chan, "vm-message");
06961 else
06962 res = ast_play_and_wait(chan, "vm-messages");
06963 }
06964
06965 }
06966 if (!res && vms->oldmessages) {
06967 res = say_and_wait(chan, vms->oldmessages, chan->language);
06968 if (!res) {
06969 if (vms->oldmessages == 1)
06970 res = ast_play_and_wait(chan, "vm-Olds");
06971 else
06972 res = ast_play_and_wait(chan, "vm-Old");
06973 }
06974 if (!res) {
06975 if (vms->oldmessages == 1)
06976 res = ast_play_and_wait(chan, "vm-message");
06977 else
06978 res = ast_play_and_wait(chan, "vm-messages");
06979 }
06980 }
06981 if (!res) {
06982 if (!vms->oldmessages && !vms->newmessages) {
06983 res = ast_play_and_wait(chan, "vm-no");
06984 if (!res)
06985 res = ast_play_and_wait(chan, "vm-messages");
06986 }
06987 }
06988 }
06989 return res;
06990 }
06991
06992
06993 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
06994 {
06995
06996 int res;
06997 res = ast_play_and_wait(chan, "vm-youhave");
06998 if (!res) {
06999 if (vms->newmessages) {
07000 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07001 if (!res) {
07002 if ((vms->newmessages == 1)) {
07003 res = ast_play_and_wait(chan, "vm-message");
07004 if (!res)
07005 res = ast_play_and_wait(chan, "vm-INBOXs");
07006 } else {
07007 res = ast_play_and_wait(chan, "vm-messages");
07008 if (!res)
07009 res = ast_play_and_wait(chan, "vm-INBOX");
07010 }
07011 }
07012 if (vms->oldmessages && !res)
07013 res = ast_play_and_wait(chan, "vm-and");
07014 }
07015 if (!res && vms->oldmessages) {
07016 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07017 if (!res) {
07018 if (vms->oldmessages == 1) {
07019 res = ast_play_and_wait(chan, "vm-message");
07020 if (!res)
07021 res = ast_play_and_wait(chan, "vm-Olds");
07022 } else {
07023 res = ast_play_and_wait(chan, "vm-messages");
07024 if (!res)
07025 res = ast_play_and_wait(chan, "vm-Old");
07026 }
07027 }
07028 }
07029 if (!res) {
07030 if (!vms->oldmessages && !vms->newmessages) {
07031 res = ast_play_and_wait(chan, "vm-no");
07032 if (!res)
07033 res = ast_play_and_wait(chan, "vm-messages");
07034 }
07035 }
07036 }
07037 return res;
07038 }
07039
07040
07041
07042
07043
07044
07045
07046
07047
07048
07049
07050
07051
07052
07053
07054
07055
07056 static int vm_intro_cz(struct ast_channel *chan, struct vm_state *vms)
07057 {
07058 int res;
07059 res = ast_play_and_wait(chan, "vm-youhave");
07060 if (!res) {
07061 if (vms->newmessages) {
07062 if (vms->newmessages == 1) {
07063 res = ast_play_and_wait(chan, "digits/jednu");
07064 } else {
07065 res = say_and_wait(chan, vms->newmessages, chan->language);
07066 }
07067 if (!res) {
07068 if ((vms->newmessages == 1))
07069 res = ast_play_and_wait(chan, "vm-novou");
07070 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07071 res = ast_play_and_wait(chan, "vm-nove");
07072 if (vms->newmessages > 4)
07073 res = ast_play_and_wait(chan, "vm-novych");
07074 }
07075 if (vms->oldmessages && !res)
07076 res = ast_play_and_wait(chan, "vm-and");
07077 else if (!res) {
07078 if ((vms->newmessages == 1))
07079 res = ast_play_and_wait(chan, "vm-zpravu");
07080 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
07081 res = ast_play_and_wait(chan, "vm-zpravy");
07082 if (vms->newmessages > 4)
07083 res = ast_play_and_wait(chan, "vm-zprav");
07084 }
07085 }
07086 if (!res && vms->oldmessages) {
07087 res = say_and_wait(chan, vms->oldmessages, chan->language);
07088 if (!res) {
07089 if ((vms->oldmessages == 1))
07090 res = ast_play_and_wait(chan, "vm-starou");
07091 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07092 res = ast_play_and_wait(chan, "vm-stare");
07093 if (vms->oldmessages > 4)
07094 res = ast_play_and_wait(chan, "vm-starych");
07095 }
07096 if (!res) {
07097 if ((vms->oldmessages == 1))
07098 res = ast_play_and_wait(chan, "vm-zpravu");
07099 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
07100 res = ast_play_and_wait(chan, "vm-zpravy");
07101 if (vms->oldmessages > 4)
07102 res = ast_play_and_wait(chan, "vm-zprav");
07103 }
07104 }
07105 if (!res) {
07106 if (!vms->oldmessages && !vms->newmessages) {
07107 res = ast_play_and_wait(chan, "vm-no");
07108 if (!res)
07109 res = ast_play_and_wait(chan, "vm-zpravy");
07110 }
07111 }
07112 }
07113 return res;
07114 }
07115
07116
07117 static int vm_intro_tw(struct ast_channel *chan, struct vm_state *vms)
07118 {
07119 int res;
07120
07121 res = ast_play_and_wait(chan, "vm-you");
07122
07123 if (!res && vms->newmessages) {
07124 res = ast_play_and_wait(chan, "vm-have");
07125 if (!res)
07126 res = say_and_wait(chan, vms->newmessages, chan->language);
07127 if (!res)
07128 res = ast_play_and_wait(chan, "vm-tong");
07129 if (!res)
07130 res = ast_play_and_wait(chan, "vm-INBOX");
07131 if (vms->oldmessages && !res)
07132 res = ast_play_and_wait(chan, "vm-and");
07133 else if (!res)
07134 res = ast_play_and_wait(chan, "vm-messages");
07135 }
07136 if (!res && vms->oldmessages) {
07137 res = ast_play_and_wait(chan, "vm-have");
07138 if (!res)
07139 res = say_and_wait(chan, vms->oldmessages, chan->language);
07140 if (!res)
07141 res = ast_play_and_wait(chan, "vm-tong");
07142 if (!res)
07143 res = ast_play_and_wait(chan, "vm-Old");
07144 if (!res)
07145 res = ast_play_and_wait(chan, "vm-messages");
07146 }
07147 if (!res && !vms->oldmessages && !vms->newmessages) {
07148 res = ast_play_and_wait(chan, "vm-haveno");
07149 if (!res)
07150 res = ast_play_and_wait(chan, "vm-messages");
07151 }
07152 return res;
07153 }
07154
07155 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07156 {
07157 char prefile[256];
07158
07159
07160 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07161 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
07162 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
07163 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07164 ast_play_and_wait(chan, "vm-tempgreetactive");
07165 }
07166 DISPOSE(prefile, -1);
07167 }
07168
07169
07170 if (!strcasecmp(chan->language, "de")) {
07171 return vm_intro_de(chan, vms);
07172 } else if (!strcasecmp(chan->language, "es")) {
07173 return vm_intro_es(chan, vms);
07174 } else if (!strcasecmp(chan->language, "it")) {
07175 return vm_intro_it(chan, vms);
07176 } else if (!strcasecmp(chan->language, "fr")) {
07177 return vm_intro_fr(chan, vms);
07178 } else if (!strcasecmp(chan->language, "nl")) {
07179 return vm_intro_nl(chan, vms);
07180 } else if (!strcasecmp(chan->language, "pt")) {
07181 return vm_intro_pt(chan, vms);
07182 } else if (!strcasecmp(chan->language, "pt_BR")) {
07183 return vm_intro_pt_BR(chan, vms);
07184 } else if (!strcasecmp(chan->language, "cz")) {
07185 return vm_intro_cz(chan, vms);
07186 } else if (!strcasecmp(chan->language, "gr")) {
07187 return vm_intro_gr(chan, vms);
07188 } else if (!strcasecmp(chan->language, "pl")) {
07189 return vm_intro_pl(chan, vms);
07190 } else if (!strcasecmp(chan->language, "se")) {
07191 return vm_intro_se(chan, vms);
07192 } else if (!strcasecmp(chan->language, "no")) {
07193 return vm_intro_no(chan, vms);
07194 } else if (!strcasecmp(chan->language, "ru")) {
07195 return vm_intro_multilang(chan, vms, "n");
07196 } else if (!strcasecmp(chan->language, "tw")) {
07197 return vm_intro_tw(chan, vms);
07198 } else if (!strcasecmp(chan->language, "ua")) {
07199 return vm_intro_multilang(chan, vms, "n");
07200 } else {
07201 return vm_intro_en(chan, vms);
07202 }
07203 }
07204
07205 static int vm_instructions_en(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
07206 {
07207 int res = 0;
07208
07209 while (!res) {
07210 if (vms->starting) {
07211 if (vms->lastmsg > -1) {
07212 res = ast_play_and_wait(chan, "vm-onefor");
07213 if (!res)
07214 res = vm_play_folder_name(chan, vms->vmbox);
07215 }
07216 if (!res)
07217 res = ast_play_and_wait(chan, "vm-opts");
07218 } else {
07219 if (vms->curmsg)
07220 res = ast_play_and_wait(chan, "vm-prev");
07221 if (!res && !skipadvanced)
07222 res = ast_play_and_wait(chan, "vm-advopts");
07223 if (!res)
07224 res = ast_play_and_wait(chan, "vm-repeat");
07225 if (!res && (vms->curmsg != vms->lastmsg))
07226 res = ast_play_and_wait(chan, "vm-next");
07227 if (!res) {
07228 if (!vms->deleted[vms->curmsg])
07229 res = ast_play_and_wait(chan, "vm-delete");
07230 else
07231 res = ast_play_and_wait(chan, "vm-undelete");
07232 if (!res)
07233 res = ast_play_and_wait(chan, "vm-toforward");
07234 if (!res)
07235 res = ast_play_and_wait(chan, "vm-savemessage");
07236 }
07237 }
07238 if (!res)
07239 res = ast_play_and_wait(chan, "vm-helpexit");
07240 if (!res)
07241 res = ast_waitfordigit(chan, 6000);
07242 if (!res) {
07243 vms->repeats++;
07244 if (vms->repeats > 2) {
07245 res = 't';
07246 }
07247 }
07248 }
07249 return res;
07250 }
07251
07252 static int vm_instructions_tw(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
07253 {
07254 int res = 0;
07255
07256 while (!res) {
07257 if (vms->lastmsg > -1) {
07258 res = ast_play_and_wait(chan, "vm-listen");
07259 if (!res)
07260 res = vm_play_folder_name(chan, vms->vmbox);
07261 if (!res)
07262 res = ast_play_and_wait(chan, "press");
07263 if (!res)
07264 res = ast_play_and_wait(chan, "digits/1");
07265 }
07266 if (!res)
07267 res = ast_play_and_wait(chan, "vm-opts");
07268 if (!res) {
07269 vms->starting = 0;
07270 return vm_instructions_en(chan, vms, skipadvanced);
07271 }
07272 }
07273 return res;
07274 }
07275
07276 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
07277 {
07278 if (vms->starting && !strcasecmp(chan->language, "tw")) {
07279 return vm_instructions_tw(chan, vms, skipadvanced);
07280 } else {
07281 return vm_instructions_en(chan, vms, skipadvanced);
07282 }
07283 }
07284
07285
07286 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07287 {
07288 int cmd = 0;
07289 int duration = 0;
07290 int tries = 0;
07291 char newpassword[80] = "";
07292 char newpassword2[80] = "";
07293 char prefile[PATH_MAX] = "";
07294 unsigned char buf[256];
07295 int bytes = 0;
07296
07297 if (ast_adsi_available(chan)) {
07298 bytes += adsi_logo(buf + bytes);
07299 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
07300 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07301 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07302 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07303 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07304 }
07305
07306
07307
07308 for (;;) {
07309 newpassword[1] = '\0';
07310 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
07311 if (cmd == '#')
07312 newpassword[0] = '\0';
07313 if (cmd < 0 || cmd == 't' || cmd == '#')
07314 return cmd;
07315 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
07316 if (cmd < 0 || cmd == 't' || cmd == '#')
07317 return cmd;
07318 newpassword2[1] = '\0';
07319 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
07320 if (cmd == '#')
07321 newpassword2[0] = '\0';
07322 if (cmd < 0 || cmd == 't' || cmd == '#')
07323 return cmd;
07324 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
07325 if (cmd < 0 || cmd == 't' || cmd == '#')
07326 return cmd;
07327 if (!strcmp(newpassword, newpassword2))
07328 break;
07329 ast_log(LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07330 cmd = ast_play_and_wait(chan, vm_mismatch);
07331 if (++tries == 3)
07332 return -1;
07333 }
07334 if (pwdchange & PWDCHANGE_INTERNAL)
07335 vm_change_password(vmu, newpassword);
07336 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
07337 vm_change_password_shell(vmu, newpassword);
07338
07339 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int)strlen(newpassword));
07340 cmd = ast_play_and_wait(chan, vm_passchanged);
07341
07342
07343 if (ast_test_flag(vmu, VM_FORCENAME)) {
07344 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07345 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07346 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07347 if (cmd < 0 || cmd == 't' || cmd == '#')
07348 return cmd;
07349 }
07350 }
07351
07352
07353 if (ast_test_flag(vmu, VM_FORCEGREET)) {
07354 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07355 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07356 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07357 if (cmd < 0 || cmd == 't' || cmd == '#')
07358 return cmd;
07359 }
07360
07361 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07362 if (ast_fileexists(prefile, NULL, NULL) < 1) {
07363 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07364 if (cmd < 0 || cmd == 't' || cmd == '#')
07365 return cmd;
07366 }
07367 }
07368
07369 return cmd;
07370 }
07371
07372 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07373 {
07374 int cmd = 0;
07375 int retries = 0;
07376 int duration = 0;
07377 char newpassword[80] = "";
07378 char newpassword2[80] = "";
07379 char prefile[PATH_MAX] = "";
07380 unsigned char buf[256];
07381 int bytes = 0;
07382
07383 if (ast_adsi_available(chan)) {
07384 bytes += adsi_logo(buf + bytes);
07385 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
07386 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07387 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07388 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07389 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07390 }
07391 while ((cmd >= 0) && (cmd != 't')) {
07392 if (cmd)
07393 retries = 0;
07394 switch (cmd) {
07395 case '1':
07396 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
07397 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07398 break;
07399 case '2':
07400 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
07401 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07402 break;
07403 case '3':
07404 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
07405 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07406 break;
07407 case '4':
07408 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
07409 break;
07410 case '5':
07411 if (vmu->password[0] == '-') {
07412 cmd = ast_play_and_wait(chan, "vm-no");
07413 break;
07414 }
07415 newpassword[1] = '\0';
07416 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
07417 if (cmd == '#')
07418 newpassword[0] = '\0';
07419 else {
07420 if (cmd < 0)
07421 break;
07422 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
07423 break;
07424 }
07425 }
07426 newpassword2[1] = '\0';
07427 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
07428 if (cmd == '#')
07429 newpassword2[0] = '\0';
07430 else {
07431 if (cmd < 0)
07432 break;
07433
07434 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
07435 break;
07436 }
07437 }
07438 if (strcmp(newpassword, newpassword2)) {
07439 ast_log(LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
07440 cmd = ast_play_and_wait(chan, vm_mismatch);
07441 break;
07442 }
07443 if (pwdchange & PWDCHANGE_INTERNAL)
07444 vm_change_password(vmu, newpassword);
07445 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
07446 vm_change_password_shell(vmu, newpassword);
07447
07448 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int)strlen(newpassword));
07449 cmd = ast_play_and_wait(chan, vm_passchanged);
07450 break;
07451 case '*':
07452 cmd = 't';
07453 break;
07454 default:
07455 cmd = 0;
07456 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07457 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
07458 if (ast_fileexists(prefile, NULL, NULL)) {
07459 cmd = ast_play_and_wait(chan, "vm-tmpexists");
07460 }
07461 DISPOSE(prefile, -1);
07462 if (!cmd) {
07463 cmd = ast_play_and_wait(chan, "vm-options");
07464 }
07465 if (!cmd) {
07466 cmd = ast_waitfordigit(chan, 6000);
07467 }
07468 if (!cmd) {
07469 retries++;
07470 }
07471 if (retries > 3) {
07472 cmd = 't';
07473 }
07474 }
07475 }
07476 if (cmd == 't')
07477 cmd = 0;
07478 return cmd;
07479 }
07480
07481 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
07482 {
07483 int cmd = 0;
07484 int retries = 0;
07485 int duration = 0;
07486 char prefile[PATH_MAX] = "";
07487 unsigned char buf[256];
07488 int bytes = 0;
07489
07490 if (ast_adsi_available(chan)) {
07491 bytes += adsi_logo(buf + bytes);
07492 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
07493 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
07494 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07495 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07496 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07497 }
07498
07499 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
07500 while ((cmd >= 0) && (cmd != 't')) {
07501 if (cmd)
07502 retries = 0;
07503 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
07504 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
07505 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07506 cmd = 't';
07507 } else {
07508 switch (cmd) {
07509 case '1':
07510 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
07511 break;
07512 case '2':
07513 DELETE(prefile, -1, prefile, vmu);
07514 ast_play_and_wait(chan, "vm-tempremoved");
07515 cmd = 't';
07516 break;
07517 case '*':
07518 cmd = 't';
07519 break;
07520 default:
07521 cmd = ast_play_and_wait(chan,
07522 ast_fileexists(prefile, NULL, NULL) > 0 ?
07523 "vm-tempgreeting2" : "vm-tempgreeting");
07524 if (!cmd)
07525 cmd = ast_waitfordigit(chan, 6000);
07526 if (!cmd)
07527 retries++;
07528 if (retries > 3)
07529 cmd = 't';
07530 }
07531 }
07532 DISPOSE(prefile, -1);
07533 }
07534 if (cmd == 't')
07535 cmd = 0;
07536 return cmd;
07537 }
07538
07539
07540
07541 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07542 {
07543 int cmd = 0;
07544
07545 if (vms->lastmsg > -1) {
07546 cmd = play_message(chan, vmu, vms);
07547 } else {
07548 cmd = ast_play_and_wait(chan, "vm-youhaveno");
07549 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")) {
07550 if (!cmd) {
07551 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
07552 cmd = ast_play_and_wait(chan, vms->fn);
07553 }
07554 if (!cmd)
07555 cmd = ast_play_and_wait(chan, "vm-messages");
07556 } else {
07557 if (!cmd)
07558 cmd = ast_play_and_wait(chan, "vm-messages");
07559 if (!cmd) {
07560 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07561 cmd = ast_play_and_wait(chan, vms->fn);
07562 }
07563 }
07564 }
07565 return cmd;
07566 }
07567
07568
07569 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07570 {
07571 int cmd = 0;
07572
07573 if (vms->lastmsg > -1) {
07574 cmd = play_message(chan, vmu, vms);
07575 } else {
07576 cmd = ast_play_and_wait(chan, "vm-youhave");
07577 if (!cmd)
07578 cmd = ast_play_and_wait(chan, "vm-no");
07579 if (!cmd) {
07580 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07581 cmd = ast_play_and_wait(chan, vms->fn);
07582 }
07583 if (!cmd)
07584 cmd = ast_play_and_wait(chan, "vm-messages");
07585 }
07586 return cmd;
07587 }
07588
07589
07590 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07591 {
07592 int cmd = 0;
07593
07594 if (vms->lastmsg > -1) {
07595 cmd = play_message(chan, vmu, vms);
07596 } else {
07597 cmd = ast_play_and_wait(chan, "vm-no");
07598 if (!cmd)
07599 cmd = ast_play_and_wait(chan, "vm-message");
07600 if (!cmd) {
07601 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07602 cmd = ast_play_and_wait(chan, vms->fn);
07603 }
07604 }
07605 return cmd;
07606 }
07607
07608
07609 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07610 {
07611 int cmd = 0;
07612
07613 if (vms->lastmsg > -1) {
07614 cmd = play_message(chan, vmu, vms);
07615 } else {
07616 cmd = ast_play_and_wait(chan, "vm-youhaveno");
07617 if (!cmd)
07618 cmd = ast_play_and_wait(chan, "vm-messages");
07619 if (!cmd) {
07620 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07621 cmd = ast_play_and_wait(chan, vms->fn);
07622 }
07623 }
07624 return cmd;
07625 }
07626
07627
07628 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07629 {
07630 int cmd = 0;
07631
07632 if (vms->lastmsg > -1) {
07633 cmd = play_message(chan, vmu, vms);
07634 } else {
07635 cmd = ast_play_and_wait(chan, "vm-no");
07636 if (!cmd) {
07637 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07638 cmd = ast_play_and_wait(chan, vms->fn);
07639 }
07640 if (!cmd)
07641 cmd = ast_play_and_wait(chan, "vm-messages");
07642 }
07643 return cmd;
07644 }
07645
07646
07647 static int vm_browse_messages_tw(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07648 {
07649 int cmd = 0;
07650
07651 if (vms->lastmsg > -1) {
07652 cmd = play_message(chan, vmu, vms);
07653 } else {
07654 cmd = ast_play_and_wait(chan, "vm-you");
07655 if (!cmd)
07656 cmd = ast_play_and_wait(chan, "vm-haveno");
07657 if (!cmd)
07658 cmd = ast_play_and_wait(chan, "vm-messages");
07659 if (!cmd) {
07660 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
07661 cmd = ast_play_and_wait(chan, vms->fn);
07662 }
07663 }
07664 return cmd;
07665 }
07666
07667 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
07668 {
07669 if (!strcasecmp(chan->language, "es")) {
07670 return vm_browse_messages_es(chan, vms, vmu);
07671 } else if (!strcasecmp(chan->language, "it")) {
07672 return vm_browse_messages_it(chan, vms, vmu);
07673 } else if (!strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) {
07674 return vm_browse_messages_pt(chan, vms, vmu);
07675 } else if (!strcasecmp(chan->language, "gr")) {
07676 return vm_browse_messages_gr(chan, vms, vmu);
07677 } else if (!strcasecmp(chan->language, "tw")) {
07678 return vm_browse_messages_tw(chan, vms, vmu);
07679 } else {
07680 return vm_browse_messages_en(chan, vms, vmu);
07681 }
07682 }
07683
07684 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
07685 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
07686 int skipuser, int maxlogins, int silent)
07687 {
07688 int useadsi = 0, valid = 0, logretries = 0;
07689 char password[AST_MAX_EXTENSION] = "", *passptr;
07690 struct ast_vm_user vmus, *vmu = NULL;
07691
07692
07693 adsi_begin(chan, &useadsi);
07694 if (!skipuser && useadsi)
07695 adsi_login(chan);
07696 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
07697 ast_log(LOG_WARNING, "Couldn't stream login file\n");
07698 return -1;
07699 }
07700
07701
07702
07703 while (!valid && (logretries < maxlogins)) {
07704
07705 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
07706 ast_log(LOG_WARNING, "Couldn't read username\n");
07707 return -1;
07708 }
07709 if (ast_strlen_zero(mailbox)) {
07710 if (chan->cid.cid_num) {
07711 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
07712 } else {
07713 ast_verb(3, "Username not entered\n");
07714 return -1;
07715 }
07716 }
07717 if (useadsi)
07718 adsi_password(chan);
07719
07720 if (!ast_strlen_zero(prefix)) {
07721 char fullusername[80] = "";
07722 ast_copy_string(fullusername, prefix, sizeof(fullusername));
07723 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
07724 ast_copy_string(mailbox, fullusername, mailbox_size);
07725 }
07726
07727 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
07728 vmu = find_user(&vmus, context, mailbox);
07729 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
07730
07731 password[0] = '\0';
07732 } else {
07733 if (ast_streamfile(chan, vm_password, chan->language)) {
07734 ast_log(LOG_WARNING, "Unable to stream password file\n");
07735 return -1;
07736 }
07737 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
07738 ast_log(LOG_WARNING, "Unable to read password\n");
07739 return -1;
07740 }
07741 }
07742
07743 if (vmu) {
07744 passptr = vmu->password;
07745 if (passptr[0] == '-') passptr++;
07746 }
07747 if (vmu && !strcmp(passptr, password))
07748 valid++;
07749 else {
07750 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
07751 if (!ast_strlen_zero(prefix))
07752 mailbox[0] = '\0';
07753 }
07754 logretries++;
07755 if (!valid) {
07756 if (skipuser || logretries >= maxlogins) {
07757 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
07758 ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
07759 return -1;
07760 }
07761 } else {
07762 if (useadsi)
07763 adsi_login(chan);
07764 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
07765 ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
07766 return -1;
07767 }
07768 }
07769 if (ast_waitstream(chan, ""))
07770 return -1;
07771 }
07772 }
07773 if (!valid && (logretries >= maxlogins)) {
07774 ast_stopstream(chan);
07775 ast_play_and_wait(chan, "vm-goodbye");
07776 return -1;
07777 }
07778 if (vmu && !skipuser) {
07779 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
07780 }
07781 return 0;
07782 }
07783
07784 static int vm_execmain(struct ast_channel *chan, void *data)
07785 {
07786
07787
07788
07789 int res = -1;
07790 int cmd = 0;
07791 int valid = 0;
07792 char prefixstr[80] = "";
07793 char ext_context[256] = "";
07794 int box;
07795 int useadsi = 0;
07796 int skipuser = 0;
07797 struct vm_state vms;
07798 struct ast_vm_user *vmu = NULL, vmus;
07799 char *context = NULL;
07800 int silentexit = 0;
07801 struct ast_flags flags = { 0 };
07802 signed char record_gain = 0;
07803 int play_auto = 0;
07804 int play_folder = 0;
07805 #ifdef IMAP_STORAGE
07806 int deleted = 0;
07807 #endif
07808
07809
07810 memset(&vms, 0, sizeof(vms));
07811 vms.lastmsg = -1;
07812
07813 memset(&vmus, 0, sizeof(vmus));
07814
07815 if (chan->_state != AST_STATE_UP) {
07816 ast_debug(1, "Before ast_answer\n");
07817 ast_answer(chan);
07818 }
07819
07820 if (!ast_strlen_zero(data)) {
07821 char *opts[OPT_ARG_ARRAY_SIZE];
07822 char *parse;
07823 AST_DECLARE_APP_ARGS(args,
07824 AST_APP_ARG(argv0);
07825 AST_APP_ARG(argv1);
07826 );
07827
07828 parse = ast_strdupa(data);
07829
07830 AST_STANDARD_APP_ARGS(args, parse);
07831
07832 if (args.argc == 2) {
07833 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
07834 return -1;
07835 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
07836 int gain;
07837 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
07838 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
07839 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
07840 return -1;
07841 } else {
07842 record_gain = (signed char) gain;
07843 }
07844 } else {
07845 ast_log(LOG_WARNING, "Invalid Gain level set with option g\n");
07846 }
07847 }
07848 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
07849 play_auto = 1;
07850 if (opts[OPT_ARG_PLAYFOLDER]) {
07851 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%d", &play_folder) != 1) {
07852 ast_log(LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
07853 }
07854 } else {
07855 ast_log(LOG_WARNING, "Invalid folder set with option a\n");
07856 }
07857 if (play_folder > 9 || play_folder < 0) {
07858 ast_log(LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
07859 play_folder = 0;
07860 }
07861 }
07862 } else {
07863
07864 while (*(args.argv0)) {
07865 if (*(args.argv0) == 's')
07866 ast_set_flag(&flags, OPT_SILENT);
07867 else if (*(args.argv0) == 'p')
07868 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
07869 else
07870 break;
07871 (args.argv0)++;
07872 }
07873
07874 }
07875
07876 valid = ast_test_flag(&flags, OPT_SILENT);
07877
07878 if ((context = strchr(args.argv0, '@')))
07879 *context++ = '\0';
07880
07881 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
07882 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
07883 else
07884 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
07885
07886 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context, vms.username)))
07887 skipuser++;
07888 else
07889 valid = 0;
07890 }
07891
07892 if (!valid)
07893 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
07894
07895 ast_debug(1, "After vm_authenticate\n");
07896 if (!res) {
07897 valid = 1;
07898 if (!skipuser)
07899 vmu = &vmus;
07900 } else {
07901 res = 0;
07902 }
07903
07904
07905 adsi_begin(chan, &useadsi);
07906
07907 if (!valid) {
07908 goto out;
07909 }
07910
07911 #ifdef IMAP_STORAGE
07912 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
07913 pthread_setspecific(ts_vmstate.key, &vms);
07914
07915 vms.interactive = 1;
07916 vms.updated = 1;
07917 vmstate_insert(&vms);
07918 init_vm_state(&vms);
07919 #endif
07920 if (!(vms.deleted = ast_calloc(vmu->maxmsg, sizeof(int)))) {
07921 ast_log(LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
07922 cmd = ast_play_and_wait(chan, "an-error-has-occured");
07923 return -1;
07924 }
07925 if (!(vms.heard = ast_calloc(vmu->maxmsg, sizeof(int)))) {
07926 ast_log(LOG_ERROR, "Could not allocate memory for heard message storage!\n");
07927 cmd = ast_play_and_wait(chan, "an-error-has-occured");
07928 return -1;
07929 }
07930
07931
07932 if (!ast_strlen_zero(vmu->language))
07933 ast_string_field_set(chan, language, vmu->language);
07934
07935 ast_debug(1, "Before open_mailbox\n");
07936 res = open_mailbox(&vms, vmu, OLD_FOLDER);
07937 if (res == ERROR_LOCK_PATH)
07938 goto out;
07939 vms.oldmessages = vms.lastmsg + 1;
07940 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
07941
07942 res = open_mailbox(&vms, vmu, NEW_FOLDER);
07943 if (res == ERROR_LOCK_PATH)
07944 goto out;
07945 vms.newmessages = vms.lastmsg + 1;
07946 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
07947
07948
07949 if (play_auto) {
07950 res = open_mailbox(&vms, vmu, play_folder);
07951 if (res == ERROR_LOCK_PATH)
07952 goto out;
07953
07954
07955 if (vms.lastmsg == -1) {
07956 cmd = vm_browse_messages(chan, &vms, vmu);
07957 res = 0;
07958 goto out;
07959 }
07960 } else {
07961 if (!vms.newmessages && vms.oldmessages) {
07962
07963 res = open_mailbox(&vms, vmu, OLD_FOLDER);
07964 play_folder = 1;
07965 if (res == ERROR_LOCK_PATH)
07966 goto out;
07967 }
07968 }
07969
07970 if (useadsi)
07971 adsi_status(chan, &vms);
07972 res = 0;
07973
07974
07975 if (!strcasecmp(vmu->mailbox, vmu->password) &&
07976 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
07977 if (ast_play_and_wait(chan, "vm-newuser") == -1)
07978 ast_log(LOG_WARNING, "Couldn't stream new user file\n");
07979 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
07980 if ((cmd == 't') || (cmd == '#')) {
07981
07982 res = 0;
07983 goto out;
07984 } else if (cmd < 0) {
07985
07986 res = -1;
07987 goto out;
07988 }
07989 }
07990 #ifdef IMAP_STORAGE
07991 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
07992 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
07993 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
07994 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07995 }
07996 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
07997 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
07998 ast_log(LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
07999 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
08000 }
08001 #endif
08002 if (play_auto) {
08003 cmd = '1';
08004 } else {
08005 cmd = vm_intro(chan, vmu, &vms);
08006 }
08007
08008 vms.repeats = 0;
08009 vms.starting = 1;
08010 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
08011
08012 switch (cmd) {
08013 case '1':
08014 vms.curmsg = 0;
08015
08016 case '5':
08017 cmd = vm_browse_messages(chan, &vms, vmu);
08018 break;
08019 case '2':
08020 if (useadsi)
08021 adsi_folders(chan, 0, "Change to folder...");
08022 cmd = get_folder2(chan, "vm-changeto", 0);
08023 if (cmd == '#') {
08024 cmd = 0;
08025 } else if (cmd > 0) {
08026 cmd = cmd - '0';
08027 res = close_mailbox(&vms, vmu);
08028 if (res == ERROR_LOCK_PATH)
08029 goto out;
08030 res = open_mailbox(&vms, vmu, cmd);
08031 if (res == ERROR_LOCK_PATH)
08032 goto out;
08033 play_folder = cmd;
08034 cmd = 0;
08035 }
08036 if (useadsi)
08037 adsi_status2(chan, &vms);
08038
08039 if (!cmd)
08040 cmd = vm_play_folder_name(chan, vms.vmbox);
08041
08042 vms.starting = 1;
08043 break;
08044 case '3':
08045 cmd = 0;
08046 vms.repeats = 0;
08047 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
08048 switch (cmd) {
08049 case '1':
08050 if (vms.lastmsg > -1 && !vms.starting) {
08051 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
08052 if (cmd == ERROR_LOCK_PATH) {
08053 res = cmd;
08054 goto out;
08055 }
08056 } else
08057 cmd = ast_play_and_wait(chan, "vm-sorry");
08058 cmd = 't';
08059 break;
08060 case '2':
08061 if (!vms.starting)
08062 ast_verb(3, "Callback Requested\n");
08063 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
08064 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
08065 if (cmd == 9) {
08066 silentexit = 1;
08067 goto out;
08068 } else if (cmd == ERROR_LOCK_PATH) {
08069 res = cmd;
08070 goto out;
08071 }
08072 } else
08073 cmd = ast_play_and_wait(chan, "vm-sorry");
08074 cmd = 't';
08075 break;
08076 case '3':
08077 if (vms.lastmsg > -1 && !vms.starting) {
08078 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
08079 if (cmd == ERROR_LOCK_PATH) {
08080 res = cmd;
08081 goto out;
08082 }
08083 } else
08084 cmd = ast_play_and_wait(chan, "vm-sorry");
08085 cmd = 't';
08086 break;
08087 case '4':
08088 if (!ast_strlen_zero(vmu->dialout)) {
08089 cmd = dialout(chan, vmu, NULL, vmu->dialout);
08090 if (cmd == 9) {
08091 silentexit = 1;
08092 goto out;
08093 }
08094 } else
08095 cmd = ast_play_and_wait(chan, "vm-sorry");
08096 cmd = 't';
08097 break;
08098
08099 case '5':
08100 if (ast_test_flag(vmu, VM_SVMAIL)) {
08101 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain);
08102 if (cmd == ERROR_LOCK_PATH) {
08103 res = cmd;
08104 ast_log(LOG_WARNING, "forward_message failed to lock path.\n");
08105 goto out;
08106 }
08107 } else
08108 cmd = ast_play_and_wait(chan, "vm-sorry");
08109 cmd = 't';
08110 break;
08111
08112 case '*':
08113 cmd = 't';
08114 break;
08115
08116 default:
08117 cmd = 0;
08118 if (!vms.starting) {
08119 cmd = ast_play_and_wait(chan, "vm-toreply");
08120 }
08121 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
08122 cmd = ast_play_and_wait(chan, "vm-tocallback");
08123 }
08124 if (!cmd && !vms.starting) {
08125 cmd = ast_play_and_wait(chan, "vm-tohearenv");
08126 }
08127 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
08128 cmd = ast_play_and_wait(chan, "vm-tomakecall");
08129 }
08130 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
08131 cmd = ast_play_and_wait(chan, "vm-leavemsg");
08132 if (!cmd)
08133 cmd = ast_play_and_wait(chan, "vm-starmain");
08134 if (!cmd)
08135 cmd = ast_waitfordigit(chan, 6000);
08136 if (!cmd)
08137 vms.repeats++;
08138 if (vms.repeats > 3)
08139 cmd = 't';
08140 }
08141 }
08142 if (cmd == 't') {
08143 cmd = 0;
08144 vms.repeats = 0;
08145 }
08146 break;
08147 case '4':
08148 if (vms.curmsg > 0) {
08149 vms.curmsg--;
08150 cmd = play_message(chan, vmu, &vms);
08151 } else {
08152 cmd = ast_play_and_wait(chan, "vm-nomore");
08153 }
08154 break;
08155 case '6':
08156 if (vms.curmsg < vms.lastmsg) {
08157 vms.curmsg++;
08158 cmd = play_message(chan, vmu, &vms);
08159 } else {
08160 cmd = ast_play_and_wait(chan, "vm-nomore");
08161 }
08162 break;
08163 case '7':
08164 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
08165 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
08166 if (useadsi)
08167 adsi_delete(chan, &vms);
08168 if (vms.deleted[vms.curmsg]) {
08169 if (play_folder == 0)
08170 vms.newmessages--;
08171 else if (play_folder == 1)
08172 vms.oldmessages--;
08173 cmd = ast_play_and_wait(chan, "vm-deleted");
08174 } else {
08175 if (play_folder == 0)
08176 vms.newmessages++;
08177 else if (play_folder == 1)
08178 vms.oldmessages++;
08179 cmd = ast_play_and_wait(chan, "vm-undeleted");
08180 }
08181 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
08182 if (vms.curmsg < vms.lastmsg) {
08183 vms.curmsg++;
08184 cmd = play_message(chan, vmu, &vms);
08185 } else {
08186 cmd = ast_play_and_wait(chan, "vm-nomore");
08187 }
08188 }
08189 } else
08190 cmd = 0;
08191 #ifdef IMAP_STORAGE
08192 deleted = 1;
08193 #endif
08194 break;
08195
08196 case '8':
08197 if (vms.lastmsg > -1) {
08198 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain);
08199 if (cmd == ERROR_LOCK_PATH) {
08200 res = cmd;
08201 goto out;
08202 }
08203 } else
08204 cmd = ast_play_and_wait(chan, "vm-nomore");
08205 break;
08206 case '9':
08207 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
08208
08209 cmd = 0;
08210 break;
08211 }
08212 if (useadsi)
08213 adsi_folders(chan, 1, "Save to folder...");
08214 cmd = get_folder2(chan, "vm-savefolder", 1);
08215 box = 0;
08216 if (cmd == '#') {
08217 cmd = 0;
08218 break;
08219 } else if (cmd > 0) {
08220 box = cmd = cmd - '0';
08221 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
08222 if (cmd == ERROR_LOCK_PATH) {
08223 res = cmd;
08224 goto out;
08225 #ifndef IMAP_STORAGE
08226 } else if (!cmd) {
08227 vms.deleted[vms.curmsg] = 1;
08228 #endif
08229 } else {
08230 vms.deleted[vms.curmsg] = 0;
08231 vms.heard[vms.curmsg] = 0;
08232 }
08233 }
08234 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
08235 if (useadsi)
08236 adsi_message(chan, &vms);
08237 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
08238 if (!cmd) {
08239 cmd = ast_play_and_wait(chan, "vm-message");
08240 if (!cmd)
08241 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
08242 if (!cmd)
08243 cmd = ast_play_and_wait(chan, "vm-savedto");
08244 if (!cmd)
08245 cmd = vm_play_folder_name(chan, vms.fn);
08246 } else {
08247 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
08248 }
08249 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
08250 if (vms.curmsg < vms.lastmsg) {
08251 vms.curmsg++;
08252 cmd = play_message(chan, vmu, &vms);
08253 } else {
08254 cmd = ast_play_and_wait(chan, "vm-nomore");
08255 }
08256 }
08257 break;
08258 case '*':
08259 if (!vms.starting) {
08260 cmd = ast_play_and_wait(chan, "vm-onefor");
08261 if (!cmd)
08262 cmd = vm_play_folder_name(chan, vms.vmbox);
08263 if (!cmd)
08264 cmd = ast_play_and_wait(chan, "vm-opts");
08265 if (!cmd)
08266 cmd = vm_instructions(chan, &vms, 1);
08267 } else
08268 cmd = 0;
08269 break;
08270 case '0':
08271 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
08272 if (useadsi)
08273 adsi_status(chan, &vms);
08274 break;
08275 default:
08276 cmd = vm_instructions(chan, &vms, 0);
08277 break;
08278 }
08279 }
08280 if ((cmd == 't') || (cmd == '#')) {
08281
08282 res = 0;
08283 } else {
08284
08285 res = -1;
08286 }
08287
08288 out:
08289 if (res > -1) {
08290 ast_stopstream(chan);
08291 adsi_goodbye(chan);
08292 if (valid) {
08293 if (silentexit)
08294 res = ast_play_and_wait(chan, "vm-dialout");
08295 else
08296 res = ast_play_and_wait(chan, "vm-goodbye");
08297 if (res > 0)
08298 res = 0;
08299 }
08300 if (useadsi)
08301 ast_adsi_unload_session(chan);
08302 }
08303 if (vmu)
08304 close_mailbox(&vms, vmu);
08305 if (valid) {
08306 int new = 0, old = 0;
08307 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
08308 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
08309 run_externnotify(vmu->context, vmu->mailbox);
08310 ast_app_inboxcount(ext_context, &new, &old);
08311 queue_mwi_event(ext_context, new, old);
08312 }
08313 #ifdef IMAP_STORAGE
08314
08315 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
08316 if (vmu && deleted == 1 && expungeonhangup == 1) {
08317 ast_mutex_lock(&vms.lock);
08318 #ifdef HAVE_IMAP_TK2006
08319 if (LEVELUIDPLUS (vms.mailstream)) {
08320 mail_expunge_full(vms.mailstream, NIL, EX_UID);
08321 } else
08322 #endif
08323 mail_expunge(vms.mailstream);
08324 ast_mutex_unlock(&vms.lock);
08325 }
08326
08327
08328 if (vmu) {
08329 vmstate_delete(&vms);
08330 }
08331 #endif
08332 if (vmu)
08333 free_user(vmu);
08334 if (vms.deleted)
08335 ast_free(vms.deleted);
08336 if (vms.heard)
08337 ast_free(vms.heard);
08338
08339 #ifdef IMAP_STORAGE
08340 pthread_setspecific(ts_vmstate.key, NULL);
08341 #endif
08342 return res;
08343 }
08344
08345 static int vm_exec(struct ast_channel *chan, void *data)
08346 {
08347 int res = 0;
08348 char *tmp;
08349 struct leave_vm_options leave_options;
08350 struct ast_flags flags = { 0 };
08351 char *opts[OPT_ARG_ARRAY_SIZE];
08352 AST_DECLARE_APP_ARGS(args,
08353 AST_APP_ARG(argv0);
08354 AST_APP_ARG(argv1);
08355 );
08356
08357 memset(&leave_options, 0, sizeof(leave_options));
08358
08359 if (chan->_state != AST_STATE_UP)
08360 ast_answer(chan);
08361
08362 if (!ast_strlen_zero(data)) {
08363 tmp = ast_strdupa(data);
08364 AST_STANDARD_APP_ARGS(args, tmp);
08365 if (args.argc == 2) {
08366 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
08367 return -1;
08368 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_DTMFEXIT);
08369 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
08370 int gain;
08371
08372 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
08373 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
08374 return -1;
08375 } else {
08376 leave_options.record_gain = (signed char) gain;
08377 }
08378 }
08379 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
08380 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
08381 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
08382 }
08383 }
08384 } else {
08385 char tmp[256];
08386 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
08387 if (res < 0)
08388 return res;
08389 if (ast_strlen_zero(tmp))
08390 return 0;
08391 args.argv0 = ast_strdupa(tmp);
08392 }
08393
08394 res = leave_voicemail(chan, args.argv0, &leave_options);
08395
08396 if (res == ERROR_LOCK_PATH) {
08397 ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
08398 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
08399 res = 0;
08400 }
08401
08402 return res;
08403 }
08404
08405 static struct ast_vm_user *find_or_create(const char *context, const char *mbox)
08406 {
08407 struct ast_vm_user *vmu;
08408
08409 AST_LIST_TRAVERSE(&users, vmu, list) {
08410 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox)) {
08411 if (strcasecmp(vmu->context, context)) {
08412 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
08413 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
08414 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
08415 \n\tamend your voicemail.conf file to avoid this situation.\n", mbox);
08416 }
08417 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", mbox);
08418 return NULL;
08419 }
08420 if (!strcasecmp(context, vmu->context) && !strcasecmp(mbox, vmu->mailbox)) {
08421 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", mbox, context);
08422 return NULL;
08423 }
08424 }
08425
08426 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
08427 return NULL;
08428
08429 ast_copy_string(vmu->context, context, sizeof(vmu->context));
08430 ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
08431
08432 AST_LIST_INSERT_TAIL(&users, vmu, list);
08433
08434 return vmu;
08435 }
08436
08437 static int append_mailbox(const char *context, const char *mbox, const char *data)
08438 {
08439
08440 char *tmp;
08441 char *stringp;
08442 char *s;
08443 struct ast_vm_user *vmu;
08444 char *mailbox_full;
08445 int new = 0, old = 0;
08446
08447 tmp = ast_strdupa(data);
08448
08449 if (!(vmu = find_or_create(context, mbox)))
08450 return -1;
08451
08452 populate_defaults(vmu);
08453
08454 stringp = tmp;
08455 if ((s = strsep(&stringp, ",")))
08456 ast_copy_string(vmu->password, s, sizeof(vmu->password));
08457 if (stringp && (s = strsep(&stringp, ",")))
08458 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
08459 if (stringp && (s = strsep(&stringp, ",")))
08460 ast_copy_string(vmu->email, s, sizeof(vmu->email));
08461 if (stringp && (s = strsep(&stringp, ",")))
08462 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
08463 if (stringp && (s = strsep(&stringp, ",")))
08464 apply_options(vmu, s);
08465
08466 mailbox_full = alloca(strlen(mbox) + strlen(context) + 1);
08467 strcpy(mailbox_full, mbox);
08468 strcat(mailbox_full, "@");
08469 strcat(mailbox_full, context);
08470
08471 inboxcount(mailbox_full, &new, &old);
08472 queue_mwi_event(mailbox_full, new, old);
08473
08474 return 0;
08475 }
08476
08477 static int vm_box_exists(struct ast_channel *chan, void *data)
08478 {
08479 struct ast_vm_user svm;
08480 char *context, *box;
08481 AST_DECLARE_APP_ARGS(args,
08482 AST_APP_ARG(mbox);
08483 AST_APP_ARG(options);
08484 );
08485 static int dep_warning = 0;
08486
08487 if (ast_strlen_zero(data)) {
08488 ast_log(LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
08489 return -1;
08490 }
08491
08492 if (!dep_warning) {
08493 dep_warning = 1;
08494 ast_log(LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *)data);
08495 }
08496
08497 box = ast_strdupa(data);
08498
08499 AST_STANDARD_APP_ARGS(args, box);
08500
08501 if (args.options) {
08502 }
08503
08504 if ((context = strchr(args.mbox, '@'))) {
08505 *context = '\0';
08506 context++;
08507 }
08508
08509 if (find_user(&svm, context, args.mbox)) {
08510 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
08511 } else
08512 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
08513
08514 return 0;
08515 }
08516
08517 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
08518 {
08519 struct ast_vm_user svm;
08520 AST_DECLARE_APP_ARGS(arg,
08521 AST_APP_ARG(mbox);
08522 AST_APP_ARG(context);
08523 );
08524
08525 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
08526
08527 if (ast_strlen_zero(arg.mbox)) {
08528 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
08529 return -1;
08530 }
08531
08532 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
08533 return 0;
08534 }
08535
08536 static struct ast_custom_function mailbox_exists_acf = {
08537 .name = "MAILBOX_EXISTS",
08538 .synopsis = "Tell if a mailbox is configured",
08539 .desc =
08540 "Returns a boolean of whether the corresponding mailbox exists. If context\n"
08541 "is not specified, defaults to the \"default\" context.\n",
08542 .syntax = "MAILBOX_EXISTS(<vmbox>[@<context>])",
08543 .read = acf_mailbox_exists,
08544 };
08545
08546 static int vmauthenticate(struct ast_channel *chan, void *data)
08547 {
08548 char *s = data, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
08549 struct ast_vm_user vmus;
08550 char *options = NULL;
08551 int silent = 0, skipuser = 0;
08552 int res = -1;
08553
08554 if (s) {
08555 s = ast_strdupa(s);
08556 user = strsep(&s, ",");
08557 options = strsep(&s, ",");
08558 if (user) {
08559 s = user;
08560 user = strsep(&s, "@");
08561 context = strsep(&s, "");
08562 if (!ast_strlen_zero(user))
08563 skipuser++;
08564 ast_copy_string(mailbox, user, sizeof(mailbox));
08565 }
08566 }
08567
08568 if (options) {
08569 silent = (strchr(options, 's')) != NULL;
08570 }
08571
08572 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
08573 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
08574 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
08575 ast_play_and_wait(chan, "auth-thankyou");
08576 res = 0;
08577 }
08578
08579 return res;
08580 }
08581
08582 static char *show_users_realtime(int fd, const char *context)
08583 {
08584 struct ast_config *cfg;
08585 const char *cat = NULL;
08586
08587 if (!(cfg = ast_load_realtime_multientry("voicemail",
08588 "context", context, NULL))) {
08589 return CLI_FAILURE;
08590 }
08591
08592 ast_cli(fd,
08593 "\n"
08594 "=============================================================\n"
08595 "=== Configured Voicemail Users ==============================\n"
08596 "=============================================================\n"
08597 "===\n");
08598
08599 while ((cat = ast_category_browse(cfg, cat))) {
08600 struct ast_variable *var = NULL;
08601 ast_cli(fd,
08602 "=== Mailbox ...\n"
08603 "===\n");
08604 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
08605 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
08606 ast_cli(fd,
08607 "===\n"
08608 "=== ---------------------------------------------------------\n"
08609 "===\n");
08610 }
08611
08612 ast_cli(fd,
08613 "=============================================================\n"
08614 "\n");
08615
08616 ast_config_destroy(cfg);
08617
08618 return CLI_SUCCESS;
08619 }
08620
08621 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
08622 {
08623 int which = 0;
08624 int wordlen;
08625 struct ast_vm_user *vmu;
08626 const char *context = "";
08627
08628
08629 if (pos > 4)
08630 return NULL;
08631 if (pos == 3)
08632 return (state == 0) ? ast_strdup("for") : NULL;
08633 wordlen = strlen(word);
08634 AST_LIST_TRAVERSE(&users, vmu, list) {
08635 if (!strncasecmp(word, vmu->context, wordlen)) {
08636 if (context && strcmp(context, vmu->context) && ++which > state)
08637 return ast_strdup(vmu->context);
08638
08639 context = vmu->context;
08640 }
08641 }
08642 return NULL;
08643 }
08644
08645
08646 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08647 {
08648 struct ast_vm_user *vmu;
08649 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
08650 const char *context = NULL;
08651 int users_counter = 0;
08652
08653 switch (cmd) {
08654 case CLI_INIT:
08655 e->command = "voicemail show users";
08656 e->usage =
08657 "Usage: voicemail show users [for <context>]\n"
08658 " Lists all mailboxes currently set up\n";
08659 return NULL;
08660 case CLI_GENERATE:
08661 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
08662 }
08663
08664 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
08665 return CLI_SHOWUSAGE;
08666 if (a->argc == 5) {
08667 if (strcmp(a->argv[3], "for"))
08668 return CLI_SHOWUSAGE;
08669 context = a->argv[4];
08670 }
08671
08672 if (ast_check_realtime("voicemail")) {
08673 if (!context) {
08674 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
08675 return CLI_SHOWUSAGE;
08676 }
08677 return show_users_realtime(a->fd, context);
08678 }
08679
08680 AST_LIST_LOCK(&users);
08681 if (AST_LIST_EMPTY(&users)) {
08682 ast_cli(a->fd, "There are no voicemail users currently defined\n");
08683 AST_LIST_UNLOCK(&users);
08684 return CLI_FAILURE;
08685 }
08686 if (a->argc == 3)
08687 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
08688 else {
08689 int count = 0;
08690 AST_LIST_TRAVERSE(&users, vmu, list) {
08691 if (!strcmp(context, vmu->context))
08692 count++;
08693 }
08694 if (count) {
08695 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
08696 } else {
08697 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
08698 AST_LIST_UNLOCK(&users);
08699 return CLI_FAILURE;
08700 }
08701 }
08702 AST_LIST_TRAVERSE(&users, vmu, list) {
08703 int newmsgs = 0, oldmsgs = 0;
08704 char count[12], tmp[256] = "";
08705
08706 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
08707 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
08708 inboxcount(tmp, &newmsgs, &oldmsgs);
08709 snprintf(count, sizeof(count), "%d", newmsgs);
08710 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
08711 users_counter++;
08712 }
08713 }
08714 AST_LIST_UNLOCK(&users);
08715 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
08716 return CLI_SUCCESS;
08717 }
08718
08719
08720 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08721 {
08722 struct vm_zone *zone;
08723 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
08724 char *res = CLI_SUCCESS;
08725
08726 switch (cmd) {
08727 case CLI_INIT:
08728 e->command = "voicemail show zones";
08729 e->usage =
08730 "Usage: voicemail show zones\n"
08731 " Lists zone message formats\n";
08732 return NULL;
08733 case CLI_GENERATE:
08734 return NULL;
08735 }
08736
08737 if (a->argc != e->args)
08738 return CLI_SHOWUSAGE;
08739
08740 AST_LIST_LOCK(&zones);
08741 if (!AST_LIST_EMPTY(&zones)) {
08742 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
08743 AST_LIST_TRAVERSE(&zones, zone, list) {
08744 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
08745 }
08746 } else {
08747 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
08748 res = CLI_FAILURE;
08749 }
08750 AST_LIST_UNLOCK(&zones);
08751
08752 return res;
08753 }
08754
08755
08756 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08757 {
08758 switch (cmd) {
08759 case CLI_INIT:
08760 e->command = "voicemail reload";
08761 e->usage =
08762 "Usage: voicemail reload\n"
08763 " Reload voicemail configuration\n";
08764 return NULL;
08765 case CLI_GENERATE:
08766 return NULL;
08767 }
08768
08769 if (a->argc != e->args)
08770 return CLI_SHOWUSAGE;
08771
08772 ast_cli(a->fd, "Reloading voicemail configuration...\n");
08773 load_config(1);
08774
08775 return CLI_SUCCESS;
08776 }
08777
08778 static struct ast_cli_entry cli_voicemail[] = {
08779 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
08780 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
08781 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
08782 };
08783
08784 static void poll_subscribed_mailboxes(void)
08785 {
08786 struct mwi_sub *mwi_sub;
08787
08788 AST_RWLIST_RDLOCK(&mwi_subs);
08789 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
08790 int new = 0, old = 0;
08791
08792 if (ast_strlen_zero(mwi_sub->mailbox))
08793 continue;
08794
08795 inboxcount(mwi_sub->mailbox, &new, &old);
08796
08797 if (new != mwi_sub->old_new || old != mwi_sub->old_old) {
08798 mwi_sub->old_new = new;
08799 mwi_sub->old_old = old;
08800 queue_mwi_event(mwi_sub->mailbox, new, old);
08801 }
08802 }
08803 AST_RWLIST_UNLOCK(&mwi_subs);
08804 }
08805
08806 static void *mb_poll_thread(void *data)
08807 {
08808 while (poll_thread_run) {
08809 struct timespec ts = { 0, };
08810 struct timeval tv;
08811
08812 tv = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
08813 ts.tv_sec = tv.tv_sec;
08814 ts.tv_nsec = tv.tv_usec * 1000;
08815
08816 ast_mutex_lock(&poll_lock);
08817 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
08818 ast_mutex_unlock(&poll_lock);
08819
08820 if (!poll_thread_run)
08821 break;
08822
08823 poll_subscribed_mailboxes();
08824 }
08825
08826 return NULL;
08827 }
08828
08829 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
08830 {
08831 ast_free(mwi_sub);
08832 }
08833
08834 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
08835 {
08836 uint32_t uniqueid;
08837 struct mwi_sub *mwi_sub;
08838
08839 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
08840 return;
08841
08842 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
08843 return;
08844
08845 uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
08846
08847 AST_RWLIST_WRLOCK(&mwi_subs);
08848 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
08849 if (mwi_sub->uniqueid == uniqueid) {
08850 AST_LIST_REMOVE_CURRENT(entry);
08851 break;
08852 }
08853 }
08854 AST_RWLIST_TRAVERSE_SAFE_END
08855 AST_RWLIST_UNLOCK(&mwi_subs);
08856
08857 if (mwi_sub)
08858 mwi_sub_destroy(mwi_sub);
08859 }
08860
08861 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
08862 {
08863 const char *mailbox;
08864 const char *context;
08865 uint32_t uniqueid;
08866 unsigned int len;
08867 struct mwi_sub *mwi_sub;
08868
08869 if (ast_event_get_type(event) != AST_EVENT_SUB)
08870 return;
08871
08872 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
08873 return;
08874
08875 mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
08876 context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
08877 uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
08878
08879 len = sizeof(*mwi_sub);
08880 if (!ast_strlen_zero(mailbox))
08881 len += strlen(mailbox);
08882
08883 if (!ast_strlen_zero(context))
08884 len += strlen(context) + 1;
08885
08886 if (!(mwi_sub = ast_calloc(1, len)))
08887 return;
08888
08889 mwi_sub->uniqueid = uniqueid;
08890 if (!ast_strlen_zero(mailbox))
08891 strcpy(mwi_sub->mailbox, mailbox);
08892
08893 if (!ast_strlen_zero(context)) {
08894 strcat(mwi_sub->mailbox, "@");
08895 strcat(mwi_sub->mailbox, context);
08896 }
08897
08898 AST_RWLIST_WRLOCK(&mwi_subs);
08899 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
08900 AST_RWLIST_UNLOCK(&mwi_subs);
08901 }
08902
08903 static void start_poll_thread(void)
08904 {
08905 pthread_attr_t attr;
08906
08907 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, NULL,
08908 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
08909 AST_EVENT_IE_END);
08910
08911 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, NULL,
08912 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
08913 AST_EVENT_IE_END);
08914
08915 if (mwi_sub_sub)
08916 ast_event_report_subs(mwi_sub_sub);
08917
08918 poll_thread_run = 1;
08919
08920 pthread_attr_init(&attr);
08921 ast_pthread_create(&poll_thread, &attr, mb_poll_thread, NULL);
08922 pthread_attr_destroy(&attr);
08923 }
08924
08925 static void stop_poll_thread(void)
08926 {
08927 poll_thread_run = 0;
08928
08929 if (mwi_sub_sub) {
08930 ast_event_unsubscribe(mwi_sub_sub);
08931 mwi_sub_sub = NULL;
08932 }
08933
08934 if (mwi_unsub_sub) {
08935 ast_event_unsubscribe(mwi_unsub_sub);
08936 mwi_unsub_sub = NULL;
08937 }
08938
08939 ast_mutex_lock(&poll_lock);
08940 ast_cond_signal(&poll_cond);
08941 ast_mutex_unlock(&poll_lock);
08942
08943 pthread_join(poll_thread, NULL);
08944
08945 poll_thread = AST_PTHREADT_NULL;
08946 }
08947
08948
08949 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
08950 {
08951 struct ast_vm_user *vmu = NULL;
08952 const char *id = astman_get_header(m, "ActionID");
08953 char actionid[128] = "";
08954
08955 if (!ast_strlen_zero(id))
08956 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
08957
08958 AST_LIST_LOCK(&users);
08959
08960 if (AST_LIST_EMPTY(&users)) {
08961 astman_send_ack(s, m, "There are no voicemail users currently defined.");
08962 AST_LIST_UNLOCK(&users);
08963 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
08964 return RESULT_SUCCESS;
08965 }
08966
08967 astman_send_ack(s, m, "Voicemail user list will follow");
08968
08969 AST_LIST_TRAVERSE(&users, vmu, list) {
08970 char dirname[256];
08971
08972 #ifdef IMAP_STORAGE
08973 int new, old;
08974 inboxcount (vmu->mailbox, &new, &old);
08975 #endif
08976
08977 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
08978 astman_append(s,
08979 "%s"
08980 "Event: VoicemailUserEntry\r\n"
08981 "VMContext: %s\r\n"
08982 "VoiceMailbox: %s\r\n"
08983 "Fullname: %s\r\n"
08984 "Email: %s\r\n"
08985 "Pager: %s\r\n"
08986 "ServerEmail: %s\r\n"
08987 "MailCommand: %s\r\n"
08988 "Language: %s\r\n"
08989 "TimeZone: %s\r\n"
08990 "Callback: %s\r\n"
08991 "Dialout: %s\r\n"
08992 "UniqueID: %s\r\n"
08993 "ExitContext: %s\r\n"
08994 "SayDurationMinimum: %d\r\n"
08995 "SayEnvelope: %s\r\n"
08996 "SayCID: %s\r\n"
08997 "AttachMessage: %s\r\n"
08998 "AttachmentFormat: %s\r\n"
08999 "DeleteMessage: %s\r\n"
09000 "VolumeGain: %.2f\r\n"
09001 "CanReview: %s\r\n"
09002 "CallOperator: %s\r\n"
09003 "MaxMessageCount: %d\r\n"
09004 "MaxMessageLength: %d\r\n"
09005 "NewMessageCount: %d\r\n"
09006 #ifdef IMAP_STORAGE
09007 "OldMessageCount: %d\r\n"
09008 "IMAPUser: %s\r\n"
09009 #endif
09010 "\r\n",
09011 actionid,
09012 vmu->context,
09013 vmu->mailbox,
09014 vmu->fullname,
09015 vmu->email,
09016 vmu->pager,
09017 vmu->serveremail,
09018 vmu->mailcmd,
09019 vmu->language,
09020 vmu->zonetag,
09021 vmu->callback,
09022 vmu->dialout,
09023 vmu->uniqueid,
09024 vmu->exit,
09025 vmu->saydurationm,
09026 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
09027 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
09028 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
09029 vmu->attachfmt,
09030 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
09031 vmu->volgain,
09032 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
09033 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
09034 vmu->maxmsg,
09035 vmu->maxsecs,
09036 #ifdef IMAP_STORAGE
09037 new, old, vmu->imapuser
09038 #else
09039 count_messages(vmu, dirname)
09040 #endif
09041 );
09042 }
09043 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
09044
09045 AST_LIST_UNLOCK(&users);
09046
09047 return RESULT_SUCCESS;
09048 }
09049
09050
09051 static void free_vm_users(void)
09052 {
09053 struct ast_vm_user *cur;
09054 AST_LIST_LOCK(&users);
09055 while ((cur = AST_LIST_REMOVE_HEAD(&users, list))) {
09056 ast_set_flag(cur, VM_ALLOCED);
09057 free_user(cur);
09058 }
09059 AST_LIST_UNLOCK(&users);
09060 }
09061
09062
09063 static void free_vm_zones(void)
09064 {
09065 struct vm_zone *zcur;
09066 AST_LIST_LOCK(&zones);
09067 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
09068 free_zone(zcur);
09069 AST_LIST_UNLOCK(&zones);
09070 }
09071
09072 static char *substitute_escapes(const char *value)
09073 {
09074 char *current, *result;
09075
09076
09077 struct ast_str *str = ast_str_create(strlen(value) + 16);
09078
09079
09080 for (current = (char *) value; *current; current++) {
09081 if (*current == '\\') {
09082 current++;
09083 if (!*current) {
09084 ast_log(LOG_NOTICE, "Incomplete escape at end of value.\n");
09085 break;
09086 }
09087 switch (*current) {
09088 case 'r':
09089 ast_str_append(&str, 0, "\r");
09090 break;
09091 case 'n':
09092 #ifdef IMAP_STORAGE
09093 if (!str->used || str->str[str->used - 1] != '\r') {
09094 ast_str_append(&str, 0, "\r");
09095 }
09096 #endif
09097 ast_str_append(&str, 0, "\n");
09098 break;
09099 case 't':
09100 ast_str_append(&str, 0, "\t");
09101 break;
09102 default:
09103 ast_log(LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
09104 break;
09105 }
09106 } else {
09107 ast_str_append(&str, 0, "%c", *current);
09108 }
09109 }
09110
09111 result = ast_strdup(str->str);
09112 ast_free(str);
09113
09114 return result;
09115 }
09116
09117 static int load_config(int reload)
09118 {
09119 struct ast_vm_user *cur;
09120 struct ast_config *cfg, *ucfg;
09121 char *cat;
09122 struct ast_variable *var;
09123 const char *val;
09124 char *q, *stringp;
09125 int x;
09126 int tmpadsi[4];
09127 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
09128
09129 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
09130 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
09131 return 0;
09132 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
09133 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
09134 } else {
09135 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
09136 ucfg = ast_config_load("users.conf", config_flags);
09137 }
09138 #ifdef IMAP_STORAGE
09139 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
09140 #endif
09141
09142 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
09143 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
09144 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
09145 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
09146 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
09147
09148
09149 free_vm_users();
09150
09151
09152 free_vm_zones();
09153
09154 AST_LIST_LOCK(&users);
09155
09156 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
09157
09158 if (cfg) {
09159
09160
09161 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
09162 val = "default";
09163 ast_copy_string(userscontext, val, sizeof(userscontext));
09164
09165 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
09166 val = "yes";
09167 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
09168
09169 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
09170 val = "no";
09171 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
09172
09173 volgain = 0.0;
09174 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
09175 sscanf(val, "%lf", &volgain);
09176
09177 #ifdef ODBC_STORAGE
09178 strcpy(odbc_database, "asterisk");
09179 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
09180 ast_copy_string(odbc_database, val, sizeof(odbc_database));
09181 }
09182 strcpy(odbc_table, "voicemessages");
09183 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
09184 ast_copy_string(odbc_table, val, sizeof(odbc_table));
09185 }
09186 #endif
09187
09188 strcpy(mailcmd, SENDMAIL);
09189 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
09190 ast_copy_string(mailcmd, val, sizeof(mailcmd));
09191
09192 maxsilence = 0;
09193 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
09194 maxsilence = atoi(val);
09195 if (maxsilence > 0)
09196 maxsilence *= 1000;
09197 }
09198
09199 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
09200 maxmsg = MAXMSG;
09201 } else {
09202 maxmsg = atoi(val);
09203 if (maxmsg <= 0) {
09204 ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
09205 maxmsg = MAXMSG;
09206 } else if (maxmsg > MAXMSGLIMIT) {
09207 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
09208 maxmsg = MAXMSGLIMIT;
09209 }
09210 }
09211
09212 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
09213 maxdeletedmsg = 0;
09214 } else {
09215 if (sscanf(val, "%d", &x) == 1)
09216 maxdeletedmsg = x;
09217 else if (ast_true(val))
09218 maxdeletedmsg = MAXMSG;
09219 else
09220 maxdeletedmsg = 0;
09221
09222 if (maxdeletedmsg < 0) {
09223 ast_log(LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
09224 maxdeletedmsg = MAXMSG;
09225 } else if (maxdeletedmsg > MAXMSGLIMIT) {
09226 ast_log(LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
09227 maxdeletedmsg = MAXMSGLIMIT;
09228 }
09229 }
09230
09231
09232 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
09233 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
09234 }
09235
09236
09237 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
09238 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
09239 pwdchange = PWDCHANGE_EXTERNAL;
09240 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
09241 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
09242 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
09243 }
09244
09245 #ifdef IMAP_STORAGE
09246
09247 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
09248 ast_copy_string(imapserver, val, sizeof(imapserver));
09249 } else {
09250 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
09251 }
09252
09253 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
09254 ast_copy_string(imapport, val, sizeof(imapport));
09255 } else {
09256 ast_copy_string(imapport, "143", sizeof(imapport));
09257 }
09258
09259 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
09260 ast_copy_string(imapflags, val, sizeof(imapflags));
09261 }
09262
09263 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
09264 ast_copy_string(authuser, val, sizeof(authuser));
09265 }
09266
09267 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
09268 ast_copy_string(authpassword, val, sizeof(authpassword));
09269 }
09270
09271 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
09272 if (ast_false(val))
09273 expungeonhangup = 0;
09274 else
09275 expungeonhangup = 1;
09276 } else {
09277 expungeonhangup = 1;
09278 }
09279
09280 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
09281 ast_copy_string(imapfolder, val, sizeof(imapfolder));
09282 } else {
09283 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
09284 }
09285 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
09286 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
09287 }
09288 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
09289 imapgreetings = ast_true(val);
09290 } else {
09291 imapgreetings = 0;
09292 }
09293 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
09294 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
09295 } else {
09296 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
09297 }
09298
09299
09300
09301
09302
09303 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
09304 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
09305 } else {
09306 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
09307 }
09308
09309 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
09310 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
09311 } else {
09312 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
09313 }
09314
09315 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
09316 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
09317 } else {
09318 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
09319 }
09320
09321 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
09322 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
09323 } else {
09324 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
09325 }
09326
09327 #endif
09328
09329 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
09330 ast_copy_string(externnotify, val, sizeof(externnotify));
09331 ast_debug(1, "found externnotify: %s\n", externnotify);
09332 } else {
09333 externnotify[0] = '\0';
09334 }
09335
09336
09337 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
09338 ast_debug(1, "Enabled SMDI voicemail notification\n");
09339 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
09340 smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find(val) : NULL;
09341 } else {
09342 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
09343 smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find("/dev/ttyS0") : NULL;
09344 }
09345 if (!smdi_iface) {
09346 ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
09347 }
09348 }
09349
09350
09351 silencethreshold = 256;
09352 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
09353 silencethreshold = atoi(val);
09354
09355 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
09356 val = ASTERISK_USERNAME;
09357 ast_copy_string(serveremail, val, sizeof(serveremail));
09358
09359 vmmaxsecs = 0;
09360 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
09361 if (sscanf(val, "%d", &x) == 1) {
09362 vmmaxsecs = x;
09363 } else {
09364 ast_log(LOG_WARNING, "Invalid max message time length\n");
09365 }
09366 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
09367 static int maxmessage_deprecate = 0;
09368 if (maxmessage_deprecate == 0) {
09369 maxmessage_deprecate = 1;
09370 ast_log(LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
09371 }
09372 if (sscanf(val, "%d", &x) == 1) {
09373 vmmaxsecs = x;
09374 } else {
09375 ast_log(LOG_WARNING, "Invalid max message time length\n");
09376 }
09377 }
09378
09379 vmminsecs = 0;
09380 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
09381 if (sscanf(val, "%d", &x) == 1) {
09382 vmminsecs = x;
09383 if (maxsilence <= vmminsecs)
09384 ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
09385 } else {
09386 ast_log(LOG_WARNING, "Invalid min message time length\n");
09387 }
09388 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
09389 static int maxmessage_deprecate = 0;
09390 if (maxmessage_deprecate == 0) {
09391 maxmessage_deprecate = 1;
09392 ast_log(LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
09393 }
09394 if (sscanf(val, "%d", &x) == 1) {
09395 vmminsecs = x;
09396 if (maxsilence <= vmminsecs)
09397 ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
09398 } else {
09399 ast_log(LOG_WARNING, "Invalid min message time length\n");
09400 }
09401 }
09402
09403 val = ast_variable_retrieve(cfg, "general", "format");
09404 if (!val)
09405 val = "wav";
09406 ast_copy_string(vmfmts, val, sizeof(vmfmts));
09407
09408 skipms = 3000;
09409 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
09410 if (sscanf(val, "%d", &x) == 1) {
09411 maxgreet = x;
09412 } else {
09413 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
09414 }
09415 }
09416
09417 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
09418 if (sscanf(val, "%d", &x) == 1) {
09419 skipms = x;
09420 } else {
09421 ast_log(LOG_WARNING, "Invalid skipms value\n");
09422 }
09423 }
09424
09425 maxlogins = 3;
09426 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
09427 if (sscanf(val, "%d", &x) == 1) {
09428 maxlogins = x;
09429 } else {
09430 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
09431 }
09432 }
09433
09434
09435 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
09436 val = "no";
09437 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
09438
09439
09440 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
09441 val = "no";
09442 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
09443
09444 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
09445 ast_debug(1, "VM_CID Internal context string: %s\n", val);
09446 stringp = ast_strdupa(val);
09447 for (x = 0; x < MAX_NUM_CID_CONTEXTS; x++) {
09448 if (!ast_strlen_zero(stringp)) {
09449 q = strsep(&stringp, ",");
09450 while ((*q == ' ')||(*q == '\t'))
09451 q++;
09452 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
09453 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
09454 } else {
09455 cidinternalcontexts[x][0] = '\0';
09456 }
09457 }
09458 }
09459 if (!(val = ast_variable_retrieve(cfg, "general", "review"))) {
09460 ast_debug(1, "VM Review Option disabled globally\n");
09461 val = "no";
09462 }
09463 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
09464
09465
09466 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
09467 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
09468 val = "no";
09469 } else {
09470 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
09471 }
09472 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
09473
09474 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))) {
09475 ast_debug(1, "VM Operator break disabled globally\n");
09476 val = "no";
09477 }
09478 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
09479
09480 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
09481 ast_debug(1, "VM CID Info before msg disabled globally\n");
09482 val = "no";
09483 }
09484 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
09485
09486 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))) {
09487 ast_debug(1, "Send Voicemail msg disabled globally\n");
09488 val = "no";
09489 }
09490 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
09491
09492 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
09493 ast_debug(1, "ENVELOPE before msg enabled globally\n");
09494 val = "yes";
09495 }
09496 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
09497
09498 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
09499 ast_debug(1, "Move Heard enabled globally\n");
09500 val = "yes";
09501 }
09502 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
09503
09504 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
09505 ast_debug(1, "Duration info before msg enabled globally\n");
09506 val = "yes";
09507 }
09508 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
09509
09510 saydurationminfo = 2;
09511 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
09512 if (sscanf(val, "%d", &x) == 1) {
09513 saydurationminfo = x;
09514 } else {
09515 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
09516 }
09517 }
09518
09519 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
09520 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
09521 val = "no";
09522 }
09523 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
09524
09525 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
09526 ast_copy_string(dialcontext, val, sizeof(dialcontext));
09527 ast_debug(1, "found dialout context: %s\n", dialcontext);
09528 } else {
09529 dialcontext[0] = '\0';
09530 }
09531
09532 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
09533 ast_copy_string(callcontext, val, sizeof(callcontext));
09534 ast_debug(1, "found callback context: %s\n", callcontext);
09535 } else {
09536 callcontext[0] = '\0';
09537 }
09538
09539 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
09540 ast_copy_string(exitcontext, val, sizeof(exitcontext));
09541 ast_debug(1, "found operator context: %s\n", exitcontext);
09542 } else {
09543 exitcontext[0] = '\0';
09544 }
09545
09546
09547 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
09548 ast_copy_string(vm_password, val, sizeof(vm_password));
09549 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
09550 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
09551 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
09552 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
09553 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
09554 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
09555 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
09556 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
09557
09558 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
09559 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
09560 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
09561 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
09562 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
09563 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
09564 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
09565 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
09566 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
09567 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
09568
09569 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
09570 val = "no";
09571 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
09572
09573 poll_freq = DEFAULT_POLL_FREQ;
09574 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
09575 if (sscanf(val, "%u", &poll_freq) != 1) {
09576 poll_freq = DEFAULT_POLL_FREQ;
09577 ast_log(LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
09578 }
09579 }
09580
09581 poll_mailboxes = 0;
09582 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
09583 poll_mailboxes = ast_true(val);
09584
09585 if (ucfg) {
09586 for (cat = ast_category_browse(ucfg, NULL); cat; cat = ast_category_browse(ucfg, cat)) {
09587 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
09588 continue;
09589 if ((cur = find_or_create(userscontext, cat))) {
09590 populate_defaults(cur);
09591 apply_options_full(cur, ast_variable_browse(ucfg, cat));
09592 ast_copy_string(cur->context, userscontext, sizeof(cur->context));
09593 }
09594 }
09595 ast_config_destroy(ucfg);
09596 }
09597 cat = ast_category_browse(cfg, NULL);
09598 while (cat) {
09599 if (strcasecmp(cat, "general")) {
09600 var = ast_variable_browse(cfg, cat);
09601 if (strcasecmp(cat, "zonemessages")) {
09602
09603 while (var) {
09604 append_mailbox(cat, var->name, var->value);
09605 var = var->next;
09606 }
09607 } else {
09608
09609 while (var) {
09610 struct vm_zone *z;
09611 if ((z = ast_malloc(sizeof(*z)))) {
09612 char *msg_format, *timezone;
09613 msg_format = ast_strdupa(var->value);
09614 timezone = strsep(&msg_format, "|");
09615 if (msg_format) {
09616 ast_copy_string(z->name, var->name, sizeof(z->name));
09617 ast_copy_string(z->timezone, timezone, sizeof(z->timezone));
09618 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
09619 AST_LIST_LOCK(&zones);
09620 AST_LIST_INSERT_HEAD(&zones, z, list);
09621 AST_LIST_UNLOCK(&zones);
09622 } else {
09623 ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
09624 ast_free(z);
09625 }
09626 } else {
09627 AST_LIST_UNLOCK(&users);
09628 ast_config_destroy(cfg);
09629 return -1;
09630 }
09631 var = var->next;
09632 }
09633 }
09634 }
09635 cat = ast_category_browse(cfg, cat);
09636 }
09637 memset(fromstring, 0, sizeof(fromstring));
09638 memset(pagerfromstring, 0, sizeof(pagerfromstring));
09639 strcpy(charset, "ISO-8859-1");
09640 if (emailbody) {
09641 ast_free(emailbody);
09642 emailbody = NULL;
09643 }
09644 if (emailsubject) {
09645 ast_free(emailsubject);
09646 emailsubject = NULL;
09647 }
09648 if (pagerbody) {
09649 ast_free(pagerbody);
09650 pagerbody = NULL;
09651 }
09652 if (pagersubject) {
09653 ast_free(pagersubject);
09654 pagersubject = NULL;
09655 }
09656 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
09657 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
09658 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
09659 ast_copy_string(fromstring, val, sizeof(fromstring));
09660 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
09661 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
09662 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
09663 ast_copy_string(charset, val, sizeof(charset));
09664 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
09665 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
09666 for (x = 0; x < 4; x++) {
09667 memcpy(&adsifdn[x], &tmpadsi[x], 1);
09668 }
09669 }
09670 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
09671 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
09672 for (x = 0; x < 4; x++) {
09673 memcpy(&adsisec[x], &tmpadsi[x], 1);
09674 }
09675 }
09676 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
09677 if (atoi(val)) {
09678 adsiver = atoi(val);
09679 }
09680 }
09681 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
09682 ast_copy_string(zonetag, val, sizeof(zonetag));
09683 }
09684 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
09685 emailsubject = ast_strdup(val);
09686 }
09687 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
09688 emailbody = substitute_escapes(val);
09689 }
09690 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
09691 pagersubject = ast_strdup(val);
09692 }
09693 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
09694 pagerbody = substitute_escapes(val);
09695 }
09696 AST_LIST_UNLOCK(&users);
09697 ast_config_destroy(cfg);
09698
09699 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
09700 start_poll_thread();
09701 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
09702 stop_poll_thread();;
09703
09704 return 0;
09705 } else {
09706 AST_LIST_UNLOCK(&users);
09707 ast_log(LOG_WARNING, "Failed to load configuration file.\n");
09708 if (ucfg)
09709 ast_config_destroy(ucfg);
09710 return 0;
09711 }
09712 }
09713
09714 static int reload(void)
09715 {
09716 return load_config(1);
09717 }
09718
09719 static int unload_module(void)
09720 {
09721 int res;
09722
09723 res = ast_unregister_application(app);
09724 res |= ast_unregister_application(app2);
09725 res |= ast_unregister_application(app3);
09726 res |= ast_unregister_application(app4);
09727 res |= ast_custom_function_unregister(&mailbox_exists_acf);
09728 res |= ast_manager_unregister("VoicemailUsersList");
09729 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
09730 ast_uninstall_vm_functions();
09731
09732 if (poll_thread != AST_PTHREADT_NULL)
09733 stop_poll_thread();
09734
09735
09736 free_vm_users();
09737 free_vm_zones();
09738 return res;
09739 }
09740
09741 static int load_module(void)
09742 {
09743 int res;
09744 my_umask = umask(0);
09745 umask(my_umask);
09746
09747
09748 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
09749
09750 if ((res = load_config(0)))
09751 return res;
09752
09753 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
09754 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
09755 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
09756 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
09757 res |= ast_custom_function_register(&mailbox_exists_acf);
09758 res |= ast_manager_register("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users, "List All Voicemail User Information");
09759 if (res)
09760 return res;
09761
09762 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
09763
09764 ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
09765
09766 return res;
09767 }
09768
09769 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
09770 {
09771 int cmd = 0;
09772 char destination[80] = "";
09773 int retries = 0;
09774
09775 if (!num) {
09776 ast_verb(3, "Destination number will be entered manually\n");
09777 while (retries < 3 && cmd != 't') {
09778 destination[1] = '\0';
09779 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
09780 if (!cmd)
09781 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
09782 if (!cmd)
09783 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
09784 if (!cmd) {
09785 cmd = ast_waitfordigit(chan, 6000);
09786 if (cmd)
09787 destination[0] = cmd;
09788 }
09789 if (!cmd) {
09790 retries++;
09791 } else {
09792
09793 if (cmd < 0)
09794 return 0;
09795 if (cmd == '*') {
09796 ast_verb(3, "User hit '*' to cancel outgoing call\n");
09797 return 0;
09798 }
09799 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination)-1, 6000, 10000, "#")) < 0)
09800 retries++;
09801 else
09802 cmd = 't';
09803 }
09804 }
09805 if (retries >= 3) {
09806 return 0;
09807 }
09808
09809 } else {
09810 ast_verb(3, "Destination number is CID number '%s'\n", num);
09811 ast_copy_string(destination, num, sizeof(destination));
09812 }
09813
09814 if (!ast_strlen_zero(destination)) {
09815 if (destination[strlen(destination) -1 ] == '*')
09816 return 0;
09817 ast_verb(3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
09818 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
09819 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
09820 chan->priority = 0;
09821 return 9;
09822 }
09823 return 0;
09824 }
09825
09826 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)
09827 {
09828 int res = 0;
09829 char filename[PATH_MAX];
09830 struct ast_config *msg_cfg = NULL;
09831 const char *origtime, *context;
09832 char *name, *num;
09833 int retries = 0;
09834 char *cid;
09835 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
09836
09837 vms->starting = 0;
09838
09839 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
09840
09841
09842
09843 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
09844 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
09845 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
09846 msg_cfg = ast_config_load(filename, config_flags);
09847 DISPOSE(vms->curdir, vms->curmsg);
09848 if (!msg_cfg) {
09849 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
09850 return 0;
09851 }
09852
09853 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
09854 ast_config_destroy(msg_cfg);
09855 return 0;
09856 }
09857
09858 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
09859
09860 context = ast_variable_retrieve(msg_cfg, "message", "context");
09861 if (!strncasecmp("macro", context, 5))
09862 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
09863 switch (option) {
09864 case 3:
09865 if (!res)
09866 res = play_message_datetime(chan, vmu, origtime, filename);
09867 if (!res)
09868 res = play_message_callerid(chan, vms, cid, context, 0);
09869
09870 res = 't';
09871 break;
09872
09873 case 2:
09874
09875 if (ast_strlen_zero(cid))
09876 break;
09877
09878 ast_callerid_parse(cid, &name, &num);
09879 while ((res > -1) && (res != 't')) {
09880 switch (res) {
09881 case '1':
09882 if (num) {
09883
09884 res = dialout(chan, vmu, num, vmu->callback);
09885 if (res) {
09886 ast_config_destroy(msg_cfg);
09887 return 9;
09888 }
09889 } else {
09890 res = '2';
09891 }
09892 break;
09893
09894 case '2':
09895
09896 if (!ast_strlen_zero(vmu->dialout)) {
09897 res = dialout(chan, vmu, NULL, vmu->dialout);
09898 if (res) {
09899 ast_config_destroy(msg_cfg);
09900 return 9;
09901 }
09902 } else {
09903 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
09904 res = ast_play_and_wait(chan, "vm-sorry");
09905 }
09906 ast_config_destroy(msg_cfg);
09907 return res;
09908 case '*':
09909 res = 't';
09910 break;
09911 case '3':
09912 case '4':
09913 case '5':
09914 case '6':
09915 case '7':
09916 case '8':
09917 case '9':
09918 case '0':
09919
09920 res = ast_play_and_wait(chan, "vm-sorry");
09921 retries++;
09922 break;
09923 default:
09924 if (num) {
09925 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
09926 res = ast_play_and_wait(chan, "vm-num-i-have");
09927 if (!res)
09928 res = play_message_callerid(chan, vms, num, vmu->context, 1);
09929 if (!res)
09930 res = ast_play_and_wait(chan, "vm-tocallnum");
09931
09932 if (!ast_strlen_zero(vmu->dialout)) {
09933 if (!res)
09934 res = ast_play_and_wait(chan, "vm-calldiffnum");
09935 }
09936 } else {
09937 res = ast_play_and_wait(chan, "vm-nonumber");
09938 if (!ast_strlen_zero(vmu->dialout)) {
09939 if (!res)
09940 res = ast_play_and_wait(chan, "vm-toenternumber");
09941 }
09942 }
09943 if (!res)
09944 res = ast_play_and_wait(chan, "vm-star-cancel");
09945 if (!res)
09946 res = ast_waitfordigit(chan, 6000);
09947 if (!res) {
09948 retries++;
09949 if (retries > 3)
09950 res = 't';
09951 }
09952 break;
09953
09954 }
09955 if (res == 't')
09956 res = 0;
09957 else if (res == '*')
09958 res = -1;
09959 }
09960 break;
09961
09962 case 1:
09963
09964 if (ast_strlen_zero(cid))
09965 break;
09966
09967 ast_callerid_parse(cid, &name, &num);
09968 if (!num) {
09969 ast_verb(3, "No CID number available, no reply sent\n");
09970 if (!res)
09971 res = ast_play_and_wait(chan, "vm-nonumber");
09972 ast_config_destroy(msg_cfg);
09973 return res;
09974 } else {
09975 struct ast_vm_user vmu2;
09976 if (find_user(&vmu2, vmu->context, num)) {
09977 struct leave_vm_options leave_options;
09978 char mailbox[AST_MAX_EXTENSION * 2 + 2];
09979 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
09980
09981 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
09982
09983 memset(&leave_options, 0, sizeof(leave_options));
09984 leave_options.record_gain = record_gain;
09985 res = leave_voicemail(chan, mailbox, &leave_options);
09986 if (!res)
09987 res = 't';
09988 ast_config_destroy(msg_cfg);
09989 return res;
09990 } else {
09991
09992 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
09993 ast_play_and_wait(chan, "vm-nobox");
09994 res = 't';
09995 ast_config_destroy(msg_cfg);
09996 return res;
09997 }
09998 }
09999 res = 0;
10000
10001 break;
10002 }
10003
10004 #ifndef IMAP_STORAGE
10005 ast_config_destroy(msg_cfg);
10006
10007 if (!res) {
10008 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
10009 vms->heard[msg] = 1;
10010 res = wait_file(chan, vms, vms->fn);
10011 }
10012 #endif
10013 return res;
10014 }
10015
10016 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
10017 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
10018 signed char record_gain, struct vm_state *vms)
10019 {
10020
10021 int res = 0;
10022 int cmd = 0;
10023 int max_attempts = 3;
10024 int attempts = 0;
10025 int recorded = 0;
10026 int message_exists = 0;
10027 signed char zero_gain = 0;
10028 char tempfile[PATH_MAX];
10029 char *acceptdtmf = "#";
10030 char *canceldtmf = "";
10031
10032
10033
10034
10035 if (duration == NULL) {
10036 ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
10037 return -1;
10038 }
10039
10040 if (!outsidecaller)
10041 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
10042 else
10043 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
10044
10045 cmd = '3';
10046
10047 while ((cmd >= 0) && (cmd != 't')) {
10048 switch (cmd) {
10049 case '1':
10050 if (!message_exists) {
10051
10052 cmd = '3';
10053 break;
10054 } else {
10055
10056 ast_verb(3, "Saving message as is\n");
10057 if (!outsidecaller)
10058 ast_filerename(tempfile, recordfile, NULL);
10059 ast_stream_and_wait(chan, "vm-msgsaved", "");
10060 if (!outsidecaller) {
10061 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
10062 DISPOSE(recordfile, -1);
10063 }
10064 cmd = 't';
10065 return res;
10066 }
10067 case '2':
10068
10069 ast_verb(3, "Reviewing the message\n");
10070 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
10071 break;
10072 case '3':
10073 message_exists = 0;
10074
10075 if (recorded == 1)
10076 ast_verb(3, "Re-recording the message\n");
10077 else
10078 ast_verb(3, "Recording the message\n");
10079
10080 if (recorded && outsidecaller) {
10081 cmd = ast_play_and_wait(chan, INTRO);
10082 cmd = ast_play_and_wait(chan, "beep");
10083 }
10084 recorded = 1;
10085
10086 if (record_gain)
10087 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
10088 if (ast_test_flag(vmu, VM_OPERATOR))
10089 canceldtmf = "0";
10090 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
10091 if (record_gain)
10092 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
10093 if (cmd == -1) {
10094
10095 if (!outsidecaller) {
10096
10097 ast_filedelete(tempfile, NULL);
10098 }
10099 return cmd;
10100 }
10101 if (cmd == '0') {
10102 break;
10103 } else if (cmd == '*') {
10104 break;
10105 #if 0
10106 } else if (vmu->review && (*duration < 5)) {
10107
10108 ast_verb(3, "Message too short\n");
10109 cmd = ast_play_and_wait(chan, "vm-tooshort");
10110 cmd = ast_filedelete(tempfile, NULL);
10111 break;
10112 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
10113
10114 ast_verb(3, "Nothing recorded\n");
10115 cmd = ast_filedelete(tempfile, NULL);
10116 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
10117 if (!cmd)
10118 cmd = ast_play_and_wait(chan, "vm-speakup");
10119 break;
10120 #endif
10121 } else {
10122
10123 message_exists = 1;
10124 cmd = 0;
10125 }
10126 break;
10127 case '4':
10128 case '5':
10129 case '6':
10130 case '7':
10131 case '8':
10132 case '9':
10133 case '*':
10134 case '#':
10135 cmd = ast_play_and_wait(chan, "vm-sorry");
10136 break;
10137 #if 0
10138
10139
10140 case '*':
10141
10142 cmd = ast_play_and_wait(chan, "vm-deleted");
10143 cmd = ast_filedelete(tempfile, NULL);
10144 if (outsidecaller) {
10145 res = vm_exec(chan, NULL);
10146 return res;
10147 }
10148 else
10149 return 1;
10150 #endif
10151 case '0':
10152 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10153 cmd = ast_play_and_wait(chan, "vm-sorry");
10154 break;
10155 }
10156 if (message_exists || recorded) {
10157 cmd = ast_play_and_wait(chan, "vm-saveoper");
10158 if (!cmd)
10159 cmd = ast_waitfordigit(chan, 3000);
10160 if (cmd == '1') {
10161 ast_play_and_wait(chan, "vm-msgsaved");
10162 cmd = '0';
10163 } else {
10164 ast_play_and_wait(chan, "vm-deleted");
10165 DELETE(recordfile, -1, recordfile, vmu);
10166 cmd = '0';
10167 }
10168 }
10169 return cmd;
10170 default:
10171
10172
10173
10174 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
10175 return cmd;
10176 if (message_exists) {
10177 cmd = ast_play_and_wait(chan, "vm-review");
10178 } else {
10179 cmd = ast_play_and_wait(chan, "vm-torerecord");
10180 if (!cmd)
10181 cmd = ast_waitfordigit(chan, 600);
10182 }
10183
10184 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
10185 cmd = ast_play_and_wait(chan, "vm-reachoper");
10186 if (!cmd)
10187 cmd = ast_waitfordigit(chan, 600);
10188 }
10189 #if 0
10190 if (!cmd)
10191 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
10192 #endif
10193 if (!cmd)
10194 cmd = ast_waitfordigit(chan, 6000);
10195 if (!cmd) {
10196 attempts++;
10197 }
10198 if (attempts > max_attempts) {
10199 cmd = 't';
10200 }
10201 }
10202 }
10203 if (outsidecaller)
10204 ast_play_and_wait(chan, "vm-goodbye");
10205 if (cmd == 't')
10206 cmd = 0;
10207 return cmd;
10208 }
10209
10210
10211
10212
10213
10214 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
10215 .load = load_module,
10216 .unload = unload_module,
10217 .reload = reload,
10218 );