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