Skip to content
Snippets Groups Projects
app_voicemail.c 258 KiB
Newer Older
  • Learn to ignore specific revisions
  • 				AST_LIST_REMOVE_CURRENT(&extensions, list);
    				free_user(vmtmp);
    				if (res)
    					break;
    
    			AST_LIST_TRAVERSE_SAFE_END;
    
    			if (saved_messages > 0) {
    				/* give confirmation that the message was saved */
    				/* commented out since we can't forward batches yet
    				if (saved_messages == 1)
    
    					res = ast_play_and_wait(chan, "vm-message");
    
    					res = ast_play_and_wait(chan, "vm-messages");
    
    					res = ast_play_and_wait(chan, "vm-saved"); */
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				res = ast_play_and_wait(chan, "vm-msgsaved");
    
    static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
    
    	if ((res = ast_stream_and_wait(chan, file, chan->language, AST_DIGIT_ANY)) < 0) 
    
    		ast_log(LOG_WARNING, "Unable to play message %s\n", file); 
    	return res;
    }
    
    static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) 
    {
    
    	return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
    
    static int play_message_category(struct ast_channel *chan, const char *category)
    
    	if (!ast_strlen_zero(category))
    
    		res = ast_play_and_wait(chan, category);
    
    
    	if (res) {
    		ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
    		res = 0;
    	}
    
    
    static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
    
    {
    	int res = 0;
    	struct vm_zone *the_zone = NULL;
    	time_t t;
    
    
    	if (ast_get_time_t(origtime, &t, 0, NULL)) {
    
    		ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
    		return 0;
    	}
    
    	/* Does this user have a timezone specified? */
    
    	if (!ast_strlen_zero(vmu->zonetag)) {
    
    		/* Find the zone in the list */
    		struct vm_zone *z;
    
    		AST_LIST_LOCK(&zones);
    		AST_LIST_TRAVERSE(&zones, z, list) {
    
    			if (!strcmp(z->name, vmu->zonetag)) {
    				the_zone = z;
    				break;
    
    /* No internal variable parsing for now, so we'll comment it out for the time being */
    #if 0
    	/* Set the DIFF_* variables */
    	localtime_r(&t, &time_now);
    
    	tnow = tv_now.tv_sec;
    	localtime_r(&tnow,&time_then);
    
    	/* Day difference */
    	if (time_now.tm_year == time_then.tm_year)
    
    		snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
    
    		snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
    
    	pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
    
    	/* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
    #endif
    	if (the_zone)
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	else if (!strcasecmp(chan->language,"pl"))       /* POLISH syntax */
    
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	else if (!strcasecmp(chan->language,"se"))       /* SWEDISH syntax */
    
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	else if (!strcasecmp(chan->language,"no"))       /* NORWEGIAN syntax */
    
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	else if (!strcasecmp(chan->language,"de"))       /* GERMAN syntax */
    
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	else if (!strcasecmp(chan->language,"nl"))      /* DUTCH syntax */
    
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	else if (!strcasecmp(chan->language,"it"))      /* ITALIAN syntax */
    
    		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);
    
    	else if (!strcasecmp(chan->language,"gr"))
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q  H 'digits/kai' M ", NULL);
    
    	else
    		res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
    #if 0
    	pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
    #endif
    	return res;
    }
    
    static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
    
    {
    	int res = 0;
    	int i;
    	char *callerid, *name;
    
    	
    
    	/* If voicemail cid is not enabled, or we didn't get cid or context from the attribute file, leave now. */
    	/* BB: Still need to change this so that if this function is called by the message envelope (and someone is explicitly requesting to hear the CID), it does not check to see if CID is enabled in the config file */
    
    	if ((cid == NULL)||(context == NULL))
    
    		return res;
    
    	/* Strip off caller ID number from name */
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
    
    	ast_callerid_parse(cid, &name, &callerid);
    
    	if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
    
    		/* Check for internal contexts and only */
    		/* say extension when the call didn't come from an internal context in the list */
    
    		for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
    
    			if (option_debug)
    				ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
    
    			if ((strcmp(cidinternalcontexts[i], context) == 0))
    
    		if (i != MAX_NUM_CID_CONTEXTS){ /* internal context? */
    			if (!res) {
    
    				snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
    
    				if (!ast_strlen_zero(prefile)) {
    
    				/* See if we can find a recorded name for this person instead of their extension number */
    					if (ast_fileexists(prefile, NULL, NULL) > 0) {
    
    						if (option_verbose > 2)
    							ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
    
    						if (!callback)
    							res = wait_file2(chan, vms, "vm-from");
    
    						res = ast_stream_and_wait(chan, prefile, chan->language, "");
    
    						if (option_verbose > 2)
    							ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
    
    						/* BB: Say "from extension" as one saying to sound smoother */
    						if (!callback)
    							res = wait_file2(chan, vms, "vm-from-extension");
    						res = ast_say_digit_str(chan, callerid, "", chan->language);
    					}
    				}
    			}
    		}
    
    		else if (!res){
    
    			if (option_debug)
    				ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
    
    			/* BB: Since this is all nicely figured out, why not say "from phone number" in this case" */
    			if (!callback)
    				res = wait_file2(chan, vms, "vm-from-phonenumber");
    			res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
    		}
    
    		/* Number unknown */
    
    		if (option_debug)
    			ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
    
    		/* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
    		res = wait_file2(chan, vms, "vm-unknown-caller");
    
    static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
    
    {
    	int res = 0;
    	int durationm;
    	int durations;
    	/* Verify that we have a duration for the message */
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	if (duration == NULL)
    
    		return res;
    
    	/* Convert from seconds to minutes */
    	durations=atoi(duration);
    	durationm=(durations / 60);
    
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
    
    	if ((!res) && (durationm >= minduration)) {
    		res = wait_file2(chan, vms, "vm-duration");
    
    		/* POLISH syntax */
    		if (!strcasecmp(chan->language, "pl")) {
    			div_t num = div(durationm, 10);
    
    			if (durationm == 1) {
    				res = ast_play_and_wait(chan, "digits/1z");
    				res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
    			} else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
    				if (num.rem == 2) {
    					if (!num.quot) {
    						res = ast_play_and_wait(chan, "digits/2-ie");
    					} else {
    						res = say_and_wait(chan, durationm - 2 , chan->language);
    						res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
    					}
    				} else {
    					res = say_and_wait(chan, durationm, chan->language);
    				}
    				res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
    			} else {
    				res = say_and_wait(chan, durationm, chan->language);
    				res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
    			}
    		/* DEFAULT syntax */
    		} else {
    			res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
    			res = wait_file2(chan, vms, "vm-minutes");
    		}
    
    #ifdef IMAP_STORAGE
    static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
    {
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	BODY *body;
    
    	char *header_content;
    	char cid[256];
    	char context[256];
    	char origtime[32];
    	char duration[16];
    	char category[32];
    
    	int res = 0;
    	char *temp;
    
    	vms->starting = 0; 
    
    	if(option_debug > 2)
    		ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]);
    
    	if (vms->msgArray[vms->curmsg] == 0) {
    		ast_log (LOG_WARNING,"Trying to access unknown message\n");
    		return -1;
    	}
    
    	/* This will only work for new messages... */
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	header_content = mail_fetchheader (vms->mailstream, vms->msgArray[vms->curmsg]);
    
    	/* empty string means no valid header */
    
    	if (ast_strlen(header_content)) {
    
    		ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[vms->curmsg]);
    		return -1;
    	}
    
    	snprintf(todir, sizeof(todir), "%s/imap", VM_SPOOL_DIR);
    	make_gsm_file(vms->fn, vms->imapuser, todir, vms->curmsg);
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	mail_fetchstructure (vms->mailstream,vms->msgArray[vms->curmsg],&body);
    	save_body(body,vms,"3","gsm");
    
    
    	adsi_message(chan, vms);
    	if (!vms->curmsg)
    		res = wait_file2(chan, vms, "vm-first");	/* "First" */
    	else if (vms->curmsg == vms->lastmsg)
    		res = wait_file2(chan, vms, "vm-last");		/* "last" */
    	if (!res) {
    		res = wait_file2(chan, vms, "vm-message");	/* "message" */
    		if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
    			if (!res)
    				res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
    		}
    	}
    
    	/* Get info from headers!!  */
    	temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    		strcpy(cid,temp); 
    	else 
    		cid[0] = '\0';
    
    
    	temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    		strcpy(context,temp); 
    	else
    		context[0] = '\0';
    
    
    	temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    		strcpy(origtime,temp);
    	else
    		origtime[0] = '\0';
    
    
    	temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    		strcpy(duration,temp);
    	else
    		duration[0] = '\0';
    	
    
    	temp = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    		strcpy(category,temp);
    	else
    		category[0] = '\0';
    
    
    	/*if (!strncasecmp("macro",context,5))  Macro names in contexts are useless for our needs */
    	/*	context = ast_variable_retrieve(msg_cfg, "message","macrocontext"); */
    	if (res == '1')
    		res = 0;
    
    
    	if ((!res) && !ast_strlen_zero(category)) {
    
    		res = play_message_category(chan, category);
    	}
    
    	if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)) && origtime[0] != '\0')
    		res = play_message_datetime(chan, vmu, origtime, "IMAP_STORAGE");
    	if ((!res) && (ast_test_flag(vmu, VM_SAYCID)) && cid[0] !='\0' && context[0] !='\0')
    		res = play_message_callerid(chan, vms, cid, context, 0);
    
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)) && duration[0] != '\0')
    		res = play_message_duration(chan, vms, duration, vmu->saydurationm);
    
    
    	/* Allow pressing '1' to skip envelope / callerid */
    	/* if (res == '1')
    		res = 0;
    	*/
    	/*ast_config_destroy(msg_cfg);*/
    	res = 0;
    
    	if (!res) {
    		vms->heard[vms->curmsg] = 1;
    		res = wait_file(chan, vms, vms->fn);
    	}
    	DISPOSE(vms->curdir, vms->curmsg);
    	return res;
    }
    #else
    
    static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
    
    	char filename[256], *cid;
    	const char *origtime, *context, *category, *duration;
    
    	struct ast_config *msg_cfg;
    
    
    	make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
    	adsi_message(chan, vms);
    	if (!vms->curmsg)
    
    		res = wait_file2(chan, vms, "vm-first");	/* "First" */
    
    	else if (vms->curmsg == vms->lastmsg)
    
    		res = wait_file2(chan, vms, "vm-last");		/* "last" */
    
    		/* POLISH syntax */
    		if (!strcasecmp(chan->language, "pl")) { 
    			if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
    				int ten, one;
    				char nextmsg[256];
    				ten = (vms->curmsg + 1) / 10;
    				one = (vms->curmsg + 1) % 10;
    				
    				if (vms->curmsg < 20) {
    					snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
    					res = wait_file2(chan, vms, nextmsg);
    				} else {
    					snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
    					res = wait_file2(chan, vms, nextmsg);
    					if (one > 0) {
    						if (!res) {
    							snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
    							res = wait_file2(chan, vms, nextmsg);
    						}
    					}
    				}
    			}
    
    				res = wait_file2(chan, vms, "vm-message");
    		} else {
    			if (!strcasecmp(chan->language, "se")) /* SWEDISH syntax */
    				res = wait_file2(chan, vms, "vm-meddelandet");  /* "message" */
    			else /* DEFAULT syntax */
    				res = wait_file2(chan, vms, "vm-message");
    			if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
    				if (!res)
    					res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
    			}
    
    	/* Retrieve info from VM attribute file */
    
    	make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
    
    	snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
    
    	RETRIEVE(vms->curdir, vms->curmsg);
    
    	msg_cfg = ast_config_load(filename);
    
    	if (!msg_cfg) {
    		ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
    		return 0;
    	}
    
    	if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
    		ast_log(LOG_WARNING, "No origtime?!\n");
    		DISPOSE(vms->curdir, vms->curmsg);
    
    	cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
    
    	duration = ast_variable_retrieve(msg_cfg, "message", "duration");
    
    	category = ast_variable_retrieve(msg_cfg, "message", "category");
    
    	context = ast_variable_retrieve(msg_cfg, "message", "context");
    
    	if (!strncasecmp("macro",context,5)) /* Macro names in contexts are useless for our needs */
    
    		context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
    
    	if (!res)
    		res = play_message_category(chan, category);
    
    	if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
    
    		res = play_message_datetime(chan, vmu, origtime, filename);
    
    	if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
    
    		res = play_message_callerid(chan, vms, cid, context, 0);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
    		res = play_message_duration(chan, vms, duration, vmu->saydurationm);
    
    	/* Allow pressing '1' to skip envelope / callerid */
    	if (res == '1')
    		res = 0;
    
    	ast_config_destroy(msg_cfg);
    
    		make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
    		vms->heard[vms->curmsg] = 1;
    
    		res = wait_file(chan, vms, vms->fn);
    	}
    
    	DISPOSE(vms->curdir, vms->curmsg);
    
    static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	SEARCHPGM *pgm;
    	SEARCHHEADER *hdr;
    
    	int ret;
    
    	strcpy(vms->imapuser,vmu->imapuser);
    	if (box == 1) {
    
    		ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
    
    		sprintf(vms->vmbox, "vm-%s", mbox(1));
    	} else {
    
    		ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
    
    		snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
    	}
    
    	if(option_debug > 2)
    		ast_log(LOG_DEBUG,"Before init_mailstream, user is %s\n",vmu->imapuser);
    
    	ret = init_mailstream(vms);
    	if (ret != 0) {
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    		ast_log (LOG_ERROR,"Could not initialize mailstream\n");
    
    		return -1;
    	}
    
    	/* Check Quota (here for now to test) */
    	mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
    	imap_getquotaroot(vms->mailstream,"INBOX");
    
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	pgm = mail_newsearchpgm();
    
    
    	/* Check IMAP folder for Asterisk messages only... */
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox);
    	pgm->header = hdr;
    
    	pgm->deleted = 0;
    	pgm->undeleted = 1;
    
    	/* if box = 0, check for new, if box = 1, check for read */
    	if (box == 0) {
    		pgm->unseen = 1;
    		pgm->seen = 0;
    	} else if (box == 1) {
    		pgm->seen = 1;
    		pgm->unseen = 0;
    	}
    
    	vms->vmArrayIndex = 0;
    
    	if(option_debug > 2)
    		ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    	mail_search_full (vms->mailstream, NULL, pgm, NIL);
    
    
    
    	vms->lastmsg = vms->vmArrayIndex - 1;
    
    	return 0;
    }
    #else
    static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
    {
    	int res = 0;
    	int count_msg, last_msg;
    
    	ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
    	
    	/* Rename the member vmbox HERE so that we don't try to return before
    	 * we know what's going on.
    
    	 */
    	snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
    	
    
    	/* Faster to make the directory than to check if it exists. */
    	create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
    
    
    	count_msg = count_messages(vmu, vms->curdir);
    
    	if (count_msg < 0)
    		return count_msg;
    	else
    		vms->lastmsg = count_msg - 1;
    
    
    	/*
    	The following test is needed in case sequencing gets messed up.
    	There appears to be more than one way to mess up sequence, so
    	we will not try to find all of the root causes--just fix it when
    	detected.
    	*/
    
    
    Joshua Colp's avatar
    Joshua Colp committed
    	if (vm_lock_path(vms->curdir)) {
    		ast_log(LOG_ERROR, "Could not open mailbox %s:  mailbox is locked\n", vms->curdir);
    		return -1;
    	}
    
    
    	last_msg = last_message_index(vmu, vms->curdir);
    
    Joshua Colp's avatar
    Joshua Colp committed
    	ast_unlock_path(vms->curdir);
    
    	if (last_msg < 0) 
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	else if (vms->lastmsg != last_msg)
    
    	{
    		ast_log(LOG_NOTICE, "Resequencing Mailbox: %s\n", vms->curdir);
    
    		res = resequence_mailbox(vmu, vms->curdir);
    
    static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
    
    #ifndef IMAP_STORAGE
    	int res = 0, nummsg;
    #endif
    
    
    	if (vms->lastmsg <= -1)
    		goto done;
    
    
    	vms->curmsg = -1; 
    #ifndef IMAP_STORAGE
    
    	/* Get the deleted messages fixed */ 
    	if (vm_lock_path(vms->curdir))
    		return ERROR_LOCK_PATH;
    
    	for (x = 0; x < vmu->maxmsg; x++) { 
    
    		if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) { 
    			/* Save this message.  It's not in INBOX or hasn't been heard */ 
    			make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); 
    			if (!EXISTS(vms->curdir, x, vms->fn, NULL)) 
    				break;
    			vms->curmsg++; 
    			make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg); 
    			if (strcmp(vms->fn, vms->fn2)) { 
    
    				RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
    
    		} else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) { 
    			/* Move to old folder before deleting */ 
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    			res = save_to_folder(vmu, vms, x, 1);
    
    			if (res == ERROR_LOCK_PATH) {
    				/* If save failed do not delete the message */
    				vms->deleted[x] = 0;
    				vms->heard[x] = 0;
    				--x;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    
    	/* Delete ALL remaining messages */
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	nummsg = x - 1;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	for (x = vms->curmsg + 1; x <= nummsg; x++) {
    		make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
    		if (EXISTS(vms->curdir, x, vms->fn, NULL))
    			DELETE(vms->curdir, x, vms->fn);
    	}
    
    	ast_unlock_path(vms->curdir);
    
    #else
    	for (x=0;x < vmu->maxmsg;x++) { 
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    		if (vms->deleted[x]) { 
    
    			if(option_debug > 2)
    				ast_log(LOG_DEBUG,"IMAP delete of %d\n",x);
    
    Matt O'Gorman's avatar
    Matt O'Gorman committed
    			IMAP_DELETE(vms->curdir, x, vms->fn, vms);
    		}
    
    	if (vms->deleted)
    
    		memset(vms->deleted, 0, vmu->maxmsg * sizeof(int)); 
    
    	if (vms->heard)
    
    		memset(vms->heard, 0, vmu->maxmsg * sizeof(int)); 
    
    /* In Greek even though we CAN use a syntax like "friends messages"
     * ("filika mynhmata") it is not elegant. This also goes for "work/family messages"
     * ("ergasiaka/oikogeniaka mynhmata"). Therefore it is better to use a reversed 
     * syntax for the above three categories which is more elegant. 
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
     */
    
    
    static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
    {
    	int cmd;
    
    	buf = alloca(strlen(mbox)+2); 
    
    	strcpy(buf, mbox);
    	strcat(buf,"s");
    
    	if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")){
    		cmd = ast_play_and_wait(chan, buf); /* "NEA / PALIA" */
    
    		return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
    
    	} else {
    		cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages" -> "MYNHMATA" */
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		return cmd ? cmd : ast_play_and_wait(chan, mbox); /* friends/family/work... -> "FILWN"/"OIKOGENIAS"/"DOULEIAS"*/
    
    	}
    }
    
    static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
    {
    	int cmd;
    
    	if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
    		if (!strcasecmp(mbox, "vm-INBOX"))
    			cmd = ast_play_and_wait(chan, "vm-new-e");
    		else
    			cmd = ast_play_and_wait(chan, "vm-old-e");
    		return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
    	} else {
    		cmd = ast_play_and_wait(chan, "vm-messages");
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		return cmd ? cmd : ast_play_and_wait(chan, mbox);
    
    static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
    {
    	int cmd;
    
    	if (!strcasecmp(chan->language, "it") || !strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /* Italian, Spanish, French or Portuguese syntax */
    		cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
    
    		return cmd ? cmd : ast_play_and_wait(chan, mbox);
    
    	} else if (!strcasecmp(chan->language, "gr")){
    		return vm_play_folder_name_gr(chan, mbox);
    
    	} else if (!strcasecmp(chan->language, "pl")){
    		return vm_play_folder_name_pl(chan, mbox);
    
    	} else {  /* Default English */
    		cmd = ast_play_and_wait(chan, mbox);
    
    		return cmd ? cmd : ast_play_and_wait(chan, "vm-messages"); /* "messages */
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    /* GREEK SYNTAX 
    
    	In greek the plural for old/new is
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	different so we need the following files
    
    	We also need vm-denExeteMynhmata because 
    	this syntax is different.
    	
    	-> vm-Olds.wav	: "Palia"
    	-> vm-INBOXs.wav : "Nea"
    	-> vm-denExeteMynhmata : "den exete mynhmata"
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    */
    
    					
    	
    static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
    {
    
    	if (vms->newmessages) {
    
    		res = ast_play_and_wait(chan, "vm-youhave");
    
    		if (!res) 
    			res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
    		if (!res) {
    			if ((vms->newmessages == 1)) {
    				res = ast_play_and_wait(chan, "vm-INBOX");
    				if (!res)
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    					res = ast_play_and_wait(chan, "vm-message");
    			} else {
    
    				res = ast_play_and_wait(chan, "vm-INBOXs");
    				if (!res)
    					res = ast_play_and_wait(chan, "vm-messages");
    
    	} else if (vms->oldmessages){
    
    		res = ast_play_and_wait(chan, "vm-youhave");
    		if (!res)
    			res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
    		if ((vms->oldmessages == 1)){
    			res = ast_play_and_wait(chan, "vm-Old");
    			if (!res)
    				res = ast_play_and_wait(chan, "vm-message");
    		} else {
    			res = ast_play_and_wait(chan, "vm-Olds");
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if (!res)
    
    				res = ast_play_and_wait(chan, "vm-messages");
    		}
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	} else if (!vms->oldmessages && !vms->newmessages) 
    		res = ast_play_and_wait(chan, "vm-denExeteMynhmata"); 
    	return res;
    
    /* Default English syntax */
    
    static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
    {
    
    	res = ast_play_and_wait(chan, "vm-youhave");
    
    			res = say_and_wait(chan, vms->newmessages, chan->language);
    
    				res = ast_play_and_wait(chan, "vm-INBOX");
    
    				res = ast_play_and_wait(chan, "vm-and");
    
    			else if (!res) {
    				if ((vms->newmessages == 1))
    
    					res = ast_play_and_wait(chan, "vm-message");
    
    					res = ast_play_and_wait(chan, "vm-messages");
    
    			res = say_and_wait(chan, vms->oldmessages, chan->language);
    
    				res = ast_play_and_wait(chan, "vm-Old");
    
    			if (!res) {
    				if (vms->oldmessages == 1)
    
    					res = ast_play_and_wait(chan, "vm-message");
    
    					res = ast_play_and_wait(chan, "vm-messages");
    
    			}
    		}
    		if (!res) {
    			if (!vms->oldmessages && !vms->newmessages) {
    
    				res = ast_play_and_wait(chan, "vm-no");
    
    					res = ast_play_and_wait(chan, "vm-messages");
    
    /* ITALIAN syntax */
    
    static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
    
    	/* Introduce messages they have */
    	int res;
    	if (!vms->oldmessages && !vms->newmessages)
    		res =	ast_play_and_wait(chan, "vm-no") ||
    			ast_play_and_wait(chan, "vm-message");
    	else
    		res =	ast_play_and_wait(chan, "vm-youhave");
    	if (!res && vms->newmessages) {
    		res = (vms->newmessages == 1) ?
    			ast_play_and_wait(chan, "digits/un") ||
    			ast_play_and_wait(chan, "vm-nuovo") ||
    			ast_play_and_wait(chan, "vm-message") :
    			/* 2 or more new messages */
    			say_and_wait(chan, vms->newmessages, chan->language) ||
    			ast_play_and_wait(chan, "vm-nuovi") ||
    			ast_play_and_wait(chan, "vm-messages");
    		if (!res && vms->oldmessages)
    			res =	ast_play_and_wait(chan, "vm-and");
    	}
    	if (!res && vms->oldmessages) {
    		res = (vms->oldmessages == 1) ?
    			ast_play_and_wait(chan, "digits/un") ||
    			ast_play_and_wait(chan, "vm-vecchio") ||
    			ast_play_and_wait(chan, "vm-message") :
    			/* 2 or more old messages */
    			say_and_wait(chan, vms->oldmessages, chan->language) ||
    			ast_play_and_wait(chan, "vm-vecchi") ||
    			ast_play_and_wait(chan, "vm-messages");
    	}
    
    /* POLISH syntax */
    static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
    {
    	/* Introduce messages they have */
    	int res;
    	div_t num;
    
    	if (!vms->oldmessages && !vms->newmessages) {
    		res = ast_play_and_wait(chan, "vm-no");
    		res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		return res;
    	} else {
    		res = ast_play_and_wait(chan, "vm-youhave");
    	}
    
    	if (vms->newmessages) {
    		num = div(vms->newmessages, 10);
    		if (vms->newmessages == 1) {
    			res = ast_play_and_wait(chan, "digits/1-a");
    			res = res ? res : ast_play_and_wait(chan, "vm-new-a");
    			res = res ? res : ast_play_and_wait(chan, "vm-message");
    		} else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
    			if (num.rem == 2) {
    				if (!num.quot) {
    					res = ast_play_and_wait(chan, "digits/2-ie");
    				} else {
    					res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
    					res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
    				}
    			} else {
    				res = say_and_wait(chan, vms->newmessages, chan->language);
    			}
    			res = res ? res : ast_play_and_wait(chan, "vm-new-e");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		} else {
    			res = say_and_wait(chan, vms->newmessages, chan->language);
    			res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		}
    		if (!res && vms->oldmessages)
    			res = ast_play_and_wait(chan, "vm-and");
    	}
    	if (!res && vms->oldmessages) {
    		num = div(vms->oldmessages, 10);
    		if (vms->oldmessages == 1) {
    			res = ast_play_and_wait(chan, "digits/1-a");
    			res = res ? res : ast_play_and_wait(chan, "vm-old-a");
    			res = res ? res : ast_play_and_wait(chan, "vm-message");
    		} else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
    			if (num.rem == 2) {
    				if (!num.quot) {
    					res = ast_play_and_wait(chan, "digits/2-ie");
    				} else {
    					res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
    					res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
    				}
    			} else {
    				res = say_and_wait(chan, vms->oldmessages, chan->language);
    			}
    			res = res ? res : ast_play_and_wait(chan, "vm-old-e");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		} else {
    			res = say_and_wait(chan, vms->oldmessages, chan->language);
    			res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		}
    	}
    
    	return res;
    }
    
    
    /* SWEDISH syntax */
    static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
    {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	/* Introduce messages they have */
    	int res;
    
    
    	res = ast_play_and_wait(chan, "vm-youhave");
    	if (res)
    		return res;
    
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	if (!vms->oldmessages && !vms->newmessages) {
    
    		res = ast_play_and_wait(chan, "vm-no");
    		res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		return res;
    
    
    	if (vms->newmessages) {
    		if ((vms->newmessages == 1)) {
    			res = ast_play_and_wait(chan, "digits/ett");
    			res = res ? res : ast_play_and_wait(chan, "vm-nytt");
    			res = res ? res : ast_play_and_wait(chan, "vm-message");
    		} else {
    			res = say_and_wait(chan, vms->newmessages, chan->language);
    			res = res ? res : ast_play_and_wait(chan, "vm-nya");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		}
    		if (!res && vms->oldmessages)
    			res = ast_play_and_wait(chan, "vm-and");
    	}
    	if (!res && vms->oldmessages) {
    		if (vms->oldmessages == 1) {
    			res = ast_play_and_wait(chan, "digits/ett");
    			res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
    			res = res ? res : ast_play_and_wait(chan, "vm-message");
    		} else {
    			res = say_and_wait(chan, vms->oldmessages, chan->language);
    			res = res ? res : ast_play_and_wait(chan, "vm-gamla");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		}
    	}
    
    	return res;
    }
    
    /* NORWEGIAN syntax */
    static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
    {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	/* Introduce messages they have */
    	int res;
    
    
    	res = ast_play_and_wait(chan, "vm-youhave");
    	if (res)
    		return res;
    
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	if (!vms->oldmessages && !vms->newmessages) {
    
    		res = ast_play_and_wait(chan, "vm-no");
    		res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		return res;
    
    
    	if (vms->newmessages) {
    		if ((vms->newmessages == 1)) {
    			res = ast_play_and_wait(chan, "digits/1");
    			res = res ? res : ast_play_and_wait(chan, "vm-ny");
    			res = res ? res : ast_play_and_wait(chan, "vm-message");
    		} else {
    			res = say_and_wait(chan, vms->newmessages, chan->language);
    			res = res ? res : ast_play_and_wait(chan, "vm-nye");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		}
    		if (!res && vms->oldmessages)
    			res = ast_play_and_wait(chan, "vm-and");
    	}
    	if (!res && vms->oldmessages) {
    		if (vms->oldmessages == 1) {
    			res = ast_play_and_wait(chan, "digits/1");
    			res = res ? res : ast_play_and_wait(chan, "vm-gamel");
    			res = res ? res : ast_play_and_wait(chan, "vm-message");
    		} else {
    			res = say_and_wait(chan, vms->oldmessages, chan->language);
    			res = res ? res : ast_play_and_wait(chan, "vm-gamle");
    			res = res ? res : ast_play_and_wait(chan, "vm-messages");
    		}
    	}
    
    	return res;
    }
    
    /* GERMAN syntax */
    static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
    {
    	/* Introduce messages they have */
    	int res;
    
    	res = ast_play_and_wait(chan, "vm-youhave");
    
    	if (!res) {
    		if (vms->newmessages) {
    			if ((vms->newmessages == 1))
    
    				res = ast_play_and_wait(chan, "digits/1F");
    
    			else
    				res = say_and_wait(chan, vms->newmessages, chan->language);
    			if (!res)
    
    				res = ast_play_and_wait(chan, "vm-INBOX");
    
    			if (vms->oldmessages && !res)
    
    				res = ast_play_and_wait(chan, "vm-and");
    
    			else if (!res) {
    				if ((vms->newmessages == 1))
    
    					res = ast_play_and_wait(chan, "vm-message");
    
    					res = ast_play_and_wait(chan, "vm-messages");
    
    			}
    				
    		}
    		if (!res && vms->oldmessages) {
    			if (vms->oldmessages == 1)
    
    				res = ast_play_and_wait(chan, "digits/1F");
    
    			else
    				res = say_and_wait(chan, vms->oldmessages, chan->language);
    			if (!res)
    
    				res = ast_play_and_wait(chan, "vm-Old");