Review Board 1.7.16


Voicemail send email to multiple email addresses

Review Request #3829 - Created July 18, 2014 and submitted

Jacob Barber
12
ASTERISK-24045
Reviewers
asterisk-dev
Asterisk
Currently voicemail to email only works with a single email. This patch allows a user to use a space separated list of emails (up to 512 characters long), where the user would like for the emails to be sent. This is useful for people who don't want to go through setting up mailing groups, or for people who host provide VoIP services with asterisk as a backend, where their customers don't know how to set up mailing groups.
Tested calling and sending voicemails using the mysql realtime database and using the standard voicemail.conf implementation.

Diff revision 3 (Latest)

1 2 3
1 2 3

  1. /branches/12/apps/app_voicemail.c: Loading...
/branches/12/apps/app_voicemail.c
Revision 418713 New Change
1
/*
1
/*
2
 * Asterisk -- An open source telephony toolkit.
2
 * Asterisk -- An open source telephony toolkit.
3
 *
3
 *
4
 * Copyright (C) 1999 - 2006, Digium, Inc.
4
 * Copyright (C) 1999 - 2006, Digium, Inc.
5
 *
5
 *
6
 * Mark Spencer <markster@digium.com>
6
 * Mark Spencer <markster@digium.com>
7
 *
7
 *
8
 * See http://www.asterisk.org for more information about
8
 * See http://www.asterisk.org for more information about
9
 * the Asterisk project. Please do not directly contact
9
 * the Asterisk project. Please do not directly contact
10
 * any of the maintainers of this project for assistance;
10
 * any of the maintainers of this project for assistance;
11
 * the project provides a web site, mailing lists and IRC
11
 * the project provides a web site, mailing lists and IRC
12
 * channels for your use.
12
 * channels for your use.
13
 *
13
 *
14
 * This program is free software, distributed under the terms of
14
 * This program is free software, distributed under the terms of
15
 * the GNU General Public License Version 2. See the LICENSE file
15
 * the GNU General Public License Version 2. See the LICENSE file
16
 * at the top of the source tree.
16
 * at the top of the source tree.
17
 */
17
 */
18

    
   
18

   
19
/*!
19
/*!
20
 * \file
20
 * \file
21
 * \author Mark Spencer <markster@digium.com>
21
 * \author Mark Spencer <markster@digium.com>
22
 * \brief Comedian Mail - Voicemail System
22
 * \brief Comedian Mail - Voicemail System
23
 *
23
 *
24
 * unixODBC (http://www.unixodbc.org/)
24
 * unixODBC (http://www.unixodbc.org/)
25
 * A source distribution of University of Washington's IMAP c-client
25
 * A source distribution of University of Washington's IMAP c-client
26
 *         (http://www.washington.edu/imap/)
26
 *         (http://www.washington.edu/imap/)
27
 *
27
 *
28
 * \par See also
28
 * \par See also
29
 * \arg \ref Config_vm
29
 * \arg \ref Config_vm
30
 * \note For information about voicemail IMAP storage, https://wiki.asterisk.org/wiki/display/AST/IMAP+Voicemail+Storage
30
 * \note For information about voicemail IMAP storage, https://wiki.asterisk.org/wiki/display/AST/IMAP+Voicemail+Storage
31
 * \ingroup applications
31
 * \ingroup applications
32
 * \todo This module requires res_adsi to load. This needs to be optional
32
 * \todo This module requires res_adsi to load. This needs to be optional
33
 * during compilation.
33
 * during compilation.
34
 *
34
 *
35
 * \todo This file is now almost impossible to work with, due to all \#ifdefs.
35
 * \todo This file is now almost impossible to work with, due to all \#ifdefs.
36
 *       Feels like the database code before realtime. Someone - please come up
36
 *       Feels like the database code before realtime. Someone - please come up
37
 *       with a plan to clean this up.
37
 *       with a plan to clean this up.
38
 */
38
 */
39

    
   
39

   
40
/*! \li \ref app_voicemail.c uses configuration file \ref voicemail.conf
40
/*! \li \ref app_voicemail.c uses configuration file \ref voicemail.conf
41
 * \addtogroup configuration_file Configuration Files
41
 * \addtogroup configuration_file Configuration Files
42
 */
42
 */
43

    
   
43

   
44
/*! 
44
/*! 
45
 * \page voicemail.conf voicemail.conf
45
 * \page voicemail.conf voicemail.conf
46
 * \verbinclude voicemail.conf.sample
46
 * \verbinclude voicemail.conf.sample
47
 */
47
 */
48

    
   
48

   
49
/*** MODULEINFO
49
/*** MODULEINFO
50
	<defaultenabled>yes</defaultenabled>
50
	<defaultenabled>yes</defaultenabled>
51
	<conflict>res_mwi_external</conflict>
51
	<conflict>res_mwi_external</conflict>
52
	<use type="module">res_adsi</use>
52
	<use type="module">res_adsi</use>
53
	<use type="module">res_smdi</use>
53
	<use type="module">res_smdi</use>
54
	<support_level>core</support_level>
54
	<support_level>core</support_level>
55
 ***/
55
 ***/
56

    
   
56

   
57
/*** MAKEOPTS
57
/*** MAKEOPTS
58
<category name="MENUSELECT_OPTS_app_voicemail" displayname="Voicemail Build Options" positive_output="yes" touch_on_change="apps/app_voicemail.c apps/app_directory.c">
58
<category name="MENUSELECT_OPTS_app_voicemail" displayname="Voicemail Build Options" positive_output="yes" touch_on_change="apps/app_voicemail.c apps/app_directory.c">
59
	<member name="FILE_STORAGE" displayname="Storage of Voicemail using filesystem">
59
	<member name="FILE_STORAGE" displayname="Storage of Voicemail using filesystem">
60
		<conflict>ODBC_STORAGE</conflict>
60
		<conflict>ODBC_STORAGE</conflict>
61
		<conflict>IMAP_STORAGE</conflict>
61
		<conflict>IMAP_STORAGE</conflict>
62
		<defaultenabled>yes</defaultenabled>
62
		<defaultenabled>yes</defaultenabled>
63
		<support_level>core</support_level>
63
		<support_level>core</support_level>
64
	</member>
64
	</member>
65
	<member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
65
	<member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
66
		<depend>generic_odbc</depend>
66
		<depend>generic_odbc</depend>
67
		<depend>ltdl</depend>
67
		<depend>ltdl</depend>
68
		<conflict>IMAP_STORAGE</conflict>
68
		<conflict>IMAP_STORAGE</conflict>
69
		<conflict>FILE_STORAGE</conflict>
69
		<conflict>FILE_STORAGE</conflict>
70
		<defaultenabled>no</defaultenabled>
70
		<defaultenabled>no</defaultenabled>
71
		<support_level>core</support_level>
71
		<support_level>core</support_level>
72
	</member>
72
	</member>
73
	<member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
73
	<member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
74
		<depend>imap_tk</depend>
74
		<depend>imap_tk</depend>
75
		<conflict>ODBC_STORAGE</conflict>
75
		<conflict>ODBC_STORAGE</conflict>
76
		<conflict>FILE_STORAGE</conflict>
76
		<conflict>FILE_STORAGE</conflict>
77
		<use type="external">openssl</use>
77
		<use type="external">openssl</use>
78
		<defaultenabled>no</defaultenabled>
78
		<defaultenabled>no</defaultenabled>
79
		<support_level>core</support_level>
79
		<support_level>core</support_level>
80
	</member>
80
	</member>
81
</category>
81
</category>
82
***/
82
***/
83

    
   
83

   
84
#include "asterisk.h"
84
#include "asterisk.h"
85

    
   
85

   
86
#ifdef IMAP_STORAGE
86
#ifdef IMAP_STORAGE
87
#include <ctype.h>
87
#include <ctype.h>
88
#include <signal.h>
88
#include <signal.h>
89
#include <pwd.h>
89
#include <pwd.h>
90
#ifdef USE_SYSTEM_IMAP
90
#ifdef USE_SYSTEM_IMAP
91
#include <imap/c-client.h>
91
#include <imap/c-client.h>
92
#include <imap/imap4r1.h>
92
#include <imap/imap4r1.h>
93
#include <imap/linkage.h>
93
#include <imap/linkage.h>
94
#elif defined (USE_SYSTEM_CCLIENT)
94
#elif defined (USE_SYSTEM_CCLIENT)
95
#include <c-client/c-client.h>
95
#include <c-client/c-client.h>
96
#include <c-client/imap4r1.h>
96
#include <c-client/imap4r1.h>
97
#include <c-client/linkage.h>
97
#include <c-client/linkage.h>
98
#else
98
#else
99
#include "c-client.h"
99
#include "c-client.h"
100
#include "imap4r1.h"
100
#include "imap4r1.h"
101
#include "linkage.h"
101
#include "linkage.h"
102
#endif
102
#endif
103
#endif
103
#endif
104

    
   
104

   
105
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
105
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
106

    
   
106

   
107
#include "asterisk/paths.h"	/* use ast_config_AST_SPOOL_DIR */
107
#include "asterisk/paths.h"	/* use ast_config_AST_SPOOL_DIR */
108
#include <sys/time.h>
108
#include <sys/time.h>
109
#include <sys/stat.h>
109
#include <sys/stat.h>
110
#include <sys/mman.h>
110
#include <sys/mman.h>
111
#include <time.h>
111
#include <time.h>
112
#include <dirent.h>
112
#include <dirent.h>
113
#if defined(__FreeBSD__) || defined(__OpenBSD__)
113
#if defined(__FreeBSD__) || defined(__OpenBSD__)
114
#include <sys/wait.h>
114
#include <sys/wait.h>
115
#endif
115
#endif
116

    
   
116

   
117
#include "asterisk/logger.h"
117
#include "asterisk/logger.h"
118
#include "asterisk/lock.h"
118
#include "asterisk/lock.h"
119
#include "asterisk/file.h"
119
#include "asterisk/file.h"
120
#include "asterisk/channel.h"
120
#include "asterisk/channel.h"
121
#include "asterisk/pbx.h"
121
#include "asterisk/pbx.h"
122
#include "asterisk/config.h"
122
#include "asterisk/config.h"
123
#include "asterisk/say.h"
123
#include "asterisk/say.h"
124
#include "asterisk/module.h"
124
#include "asterisk/module.h"
125
#include "asterisk/adsi.h"
125
#include "asterisk/adsi.h"
126
#include "asterisk/app.h"
126
#include "asterisk/app.h"
127
#include "asterisk/manager.h"
127
#include "asterisk/manager.h"
128
#include "asterisk/dsp.h"
128
#include "asterisk/dsp.h"
129
#include "asterisk/localtime.h"
129
#include "asterisk/localtime.h"
130
#include "asterisk/cli.h"
130
#include "asterisk/cli.h"
131
#include "asterisk/utils.h"
131
#include "asterisk/utils.h"
132
#include "asterisk/stringfields.h"
132
#include "asterisk/stringfields.h"
133
#include "asterisk/strings.h"
133
#include "asterisk/strings.h"
134
#include "asterisk/smdi.h"
134
#include "asterisk/smdi.h"
135
#include "asterisk/astobj2.h"
135
#include "asterisk/astobj2.h"
136
#include "asterisk/taskprocessor.h"
136
#include "asterisk/taskprocessor.h"
137
#include "asterisk/test.h"
137
#include "asterisk/test.h"
138

    
   
138

   
139
#ifdef ODBC_STORAGE
139
#ifdef ODBC_STORAGE
140
#include "asterisk/res_odbc.h"
140
#include "asterisk/res_odbc.h"
141
#endif
141
#endif
142

    
   
142

   
143
#ifdef IMAP_STORAGE
143
#ifdef IMAP_STORAGE
144
#include "asterisk/threadstorage.h"
144
#include "asterisk/threadstorage.h"
145
#endif
145
#endif
146

    
   
146

   
147
/*** DOCUMENTATION
147
/*** DOCUMENTATION
148
	<application name="VoiceMail" language="en_US">
148
	<application name="VoiceMail" language="en_US">
149
		<synopsis>
149
		<synopsis>
150
			Leave a Voicemail message.
150
			Leave a Voicemail message.
151
		</synopsis>
151
		</synopsis>
152
		<syntax>
152
		<syntax>
153
			<parameter name="mailboxs" argsep="&amp;" required="true">
153
			<parameter name="mailboxs" argsep="&amp;" required="true">
154
				<argument name="mailbox1" argsep="@" required="true">
154
				<argument name="mailbox1" argsep="@" required="true">
155
					<argument name="mailbox" required="true" />
155
					<argument name="mailbox" required="true" />
156
					<argument name="context" />
156
					<argument name="context" />
157
				</argument>
157
				</argument>
158
				<argument name="mailbox2" argsep="@" multiple="true">
158
				<argument name="mailbox2" argsep="@" multiple="true">
159
					<argument name="mailbox" required="true" />
159
					<argument name="mailbox" required="true" />
160
					<argument name="context" />
160
					<argument name="context" />
161
				</argument>
161
				</argument>
162
			</parameter>
162
			</parameter>
163
			<parameter name="options">
163
			<parameter name="options">
164
				<optionlist>
164
				<optionlist>
165
					<option name="b">
165
					<option name="b">
166
						<para>Play the <literal>busy</literal> greeting to the calling party.</para>
166
						<para>Play the <literal>busy</literal> greeting to the calling party.</para>
167
					</option>
167
					</option>
168
					<option name="d">
168
					<option name="d">
169
						<argument name="c" />
169
						<argument name="c" />
170
						<para>Accept digits for a new extension in context <replaceable>c</replaceable>,
170
						<para>Accept digits for a new extension in context <replaceable>c</replaceable>,
171
						if played during the greeting. Context defaults to the current context.</para>
171
						if played during the greeting. Context defaults to the current context.</para>
172
					</option>
172
					</option>
173
					<option name="g">
173
					<option name="g">
174
						<argument name="#" required="true" />
174
						<argument name="#" required="true" />
175
						<para>Use the specified amount of gain when recording the voicemail
175
						<para>Use the specified amount of gain when recording the voicemail
176
						message. The units are whole-number decibels (dB). Only works on supported
176
						message. The units are whole-number decibels (dB). Only works on supported
177
						technologies, which is DAHDI only.</para>
177
						technologies, which is DAHDI only.</para>
178
					</option>
178
					</option>
179
					<option name="s">
179
					<option name="s">
180
						<para>Skip the playback of instructions for leaving a message to the
180
						<para>Skip the playback of instructions for leaving a message to the
181
						calling party.</para>
181
						calling party.</para>
182
					</option>
182
					</option>
183
					<option name="u">
183
					<option name="u">
184
						<para>Play the <literal>unavailable</literal> greeting.</para>
184
						<para>Play the <literal>unavailable</literal> greeting.</para>
185
					</option>
185
					</option>
186
					<option name="U">
186
					<option name="U">
187
						<para>Mark message as <literal>URGENT</literal>.</para>
187
						<para>Mark message as <literal>URGENT</literal>.</para>
188
					</option>
188
					</option>
189
					<option name="P">
189
					<option name="P">
190
						<para>Mark message as <literal>PRIORITY</literal>.</para>
190
						<para>Mark message as <literal>PRIORITY</literal>.</para>
191
					</option>
191
					</option>
192
				</optionlist>
192
				</optionlist>
193
			</parameter>
193
			</parameter>
194
		</syntax>
194
		</syntax>
195
		<description>
195
		<description>
196
			<para>This application allows the calling party to leave a message for the specified
196
			<para>This application allows the calling party to leave a message for the specified
197
			list of mailboxes. When multiple mailboxes are specified, the greeting will be taken from
197
			list of mailboxes. When multiple mailboxes are specified, the greeting will be taken from
198
			the first mailbox specified. Dialplan execution will stop if the specified mailbox does not
198
			the first mailbox specified. Dialplan execution will stop if the specified mailbox does not
199
			exist.</para>
199
			exist.</para>
200
			<para>The Voicemail application will exit if any of the following DTMF digits are received:</para>
200
			<para>The Voicemail application will exit if any of the following DTMF digits are received:</para>
201
			<enumlist>
201
			<enumlist>
202
				<enum name="0">
202
				<enum name="0">
203
					<para>Jump to the <literal>o</literal> extension in the current dialplan context.</para>
203
					<para>Jump to the <literal>o</literal> extension in the current dialplan context.</para>
204
				</enum>
204
				</enum>
205
				<enum name="*">
205
				<enum name="*">
206
					<para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
206
					<para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
207
				</enum>
207
				</enum>
208
			</enumlist>
208
			</enumlist>
209
			<para>This application will set the following channel variable upon completion:</para>
209
			<para>This application will set the following channel variable upon completion:</para>
210
			<variablelist>
210
			<variablelist>
211
				<variable name="VMSTATUS">
211
				<variable name="VMSTATUS">
212
					<para>This indicates the status of the execution of the VoiceMail application.</para>
212
					<para>This indicates the status of the execution of the VoiceMail application.</para>
213
					<value name="SUCCESS" />
213
					<value name="SUCCESS" />
214
					<value name="USEREXIT" />
214
					<value name="USEREXIT" />
215
					<value name="FAILED" />
215
					<value name="FAILED" />
216
				</variable>
216
				</variable>
217
			</variablelist>
217
			</variablelist>
218
		</description>
218
		</description>
219
		<see-also>
219
		<see-also>
220
			<ref type="application">VoiceMailMain</ref>
220
			<ref type="application">VoiceMailMain</ref>
221
		</see-also>
221
		</see-also>
222
	</application>
222
	</application>
223
	<application name="VoiceMailMain" language="en_US">
223
	<application name="VoiceMailMain" language="en_US">
224
		<synopsis>
224
		<synopsis>
225
			Check Voicemail messages.
225
			Check Voicemail messages.
226
		</synopsis>
226
		</synopsis>
227
		<syntax>
227
		<syntax>
228
			<parameter name="mailbox" required="true" argsep="@">
228
			<parameter name="mailbox" required="true" argsep="@">
229
				<argument name="mailbox" />
229
				<argument name="mailbox" />
230
				<argument name="context" />
230
				<argument name="context" />
231
			</parameter>
231
			</parameter>
232
			<parameter name="options">
232
			<parameter name="options">
233
				<optionlist>
233
				<optionlist>
234
					<option name="p">
234
					<option name="p">
235
						<para>Consider the <replaceable>mailbox</replaceable> parameter as a prefix to
235
						<para>Consider the <replaceable>mailbox</replaceable> parameter as a prefix to
236
						the mailbox that is entered by the caller.</para>
236
						the mailbox that is entered by the caller.</para>
237
					</option>
237
					</option>
238
					<option name="g">
238
					<option name="g">
239
						<argument name="#" required="true" />
239
						<argument name="#" required="true" />
240
						<para>Use the specified amount of gain when recording a voicemail message.
240
						<para>Use the specified amount of gain when recording a voicemail message.
241
						The units are whole-number decibels (dB).</para>
241
						The units are whole-number decibels (dB).</para>
242
					</option>
242
					</option>
243
					<option name="s">
243
					<option name="s">
244
						<para>Skip checking the passcode for the mailbox.</para>
244
						<para>Skip checking the passcode for the mailbox.</para>
245
					</option>
245
					</option>
246
					<option name="a">
246
					<option name="a">
247
						<argument name="folder" required="true" />
247
						<argument name="folder" required="true" />
248
						<para>Skip folder prompt and go directly to <replaceable>folder</replaceable> specified.
248
						<para>Skip folder prompt and go directly to <replaceable>folder</replaceable> specified.
249
						Defaults to <literal>INBOX</literal> (or <literal>0</literal>).</para>
249
						Defaults to <literal>INBOX</literal> (or <literal>0</literal>).</para>
250
						<enumlist>
250
						<enumlist>
251
							<enum name="0"><para>INBOX</para></enum>
251
							<enum name="0"><para>INBOX</para></enum>
252
							<enum name="1"><para>Old</para></enum>
252
							<enum name="1"><para>Old</para></enum>
253
							<enum name="2"><para>Work</para></enum>
253
							<enum name="2"><para>Work</para></enum>
254
							<enum name="3"><para>Family</para></enum>
254
							<enum name="3"><para>Family</para></enum>
255
							<enum name="4"><para>Friends</para></enum>
255
							<enum name="4"><para>Friends</para></enum>
256
							<enum name="5"><para>Cust1</para></enum>
256
							<enum name="5"><para>Cust1</para></enum>
257
							<enum name="6"><para>Cust2</para></enum>
257
							<enum name="6"><para>Cust2</para></enum>
258
							<enum name="7"><para>Cust3</para></enum>
258
							<enum name="7"><para>Cust3</para></enum>
259
							<enum name="8"><para>Cust4</para></enum>
259
							<enum name="8"><para>Cust4</para></enum>
260
							<enum name="9"><para>Cust5</para></enum>
260
							<enum name="9"><para>Cust5</para></enum>
261
						</enumlist>
261
						</enumlist>
262
					</option>
262
					</option>
263
				</optionlist>
263
				</optionlist>
264
			</parameter>
264
			</parameter>
265
		</syntax>
265
		</syntax>
266
		<description>
266
		<description>
267
			<para>This application allows the calling party to check voicemail messages. A specific
267
			<para>This application allows the calling party to check voicemail messages. A specific
268
			<replaceable>mailbox</replaceable>, and optional corresponding <replaceable>context</replaceable>,
268
			<replaceable>mailbox</replaceable>, and optional corresponding <replaceable>context</replaceable>,
269
			may be specified. If a <replaceable>mailbox</replaceable> is not provided, the calling party will
269
			may be specified. If a <replaceable>mailbox</replaceable> is not provided, the calling party will
270
			be prompted to enter one. If a <replaceable>context</replaceable> is not specified, the
270
			be prompted to enter one. If a <replaceable>context</replaceable> is not specified, the
271
			<literal>default</literal> context will be used.</para>
271
			<literal>default</literal> context will be used.</para>
272
			<para>The VoiceMailMain application will exit if the following DTMF digit is entered as Mailbox
272
			<para>The VoiceMailMain application will exit if the following DTMF digit is entered as Mailbox
273
			or Password, and the extension exists:</para>
273
			or Password, and the extension exists:</para>
274
			<enumlist>
274
			<enumlist>
275
				<enum name="*">
275
				<enum name="*">
276
					<para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
276
					<para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
277
				</enum>
277
				</enum>
278
			</enumlist>
278
			</enumlist>
279
		</description>
279
		</description>
280
		<see-also>
280
		<see-also>
281
			<ref type="application">VoiceMail</ref>
281
			<ref type="application">VoiceMail</ref>
282
		</see-also>
282
		</see-also>
283
	</application>
283
	</application>
284
	<application name="MailboxExists" language="en_US">
284
	<application name="MailboxExists" language="en_US">
285
		<synopsis>
285
		<synopsis>
286
			Check to see if Voicemail mailbox exists.
286
			Check to see if Voicemail mailbox exists.
287
		</synopsis>
287
		</synopsis>
288
		<syntax>
288
		<syntax>
289
			<parameter name="mailbox" required="true" argsep="@">
289
			<parameter name="mailbox" required="true" argsep="@">
290
				<argument name="mailbox" required="true" />
290
				<argument name="mailbox" required="true" />
291
				<argument name="context" />
291
				<argument name="context" />
292
			</parameter>
292
			</parameter>
293
			<parameter name="options">
293
			<parameter name="options">
294
				<para>None options.</para>
294
				<para>None options.</para>
295
			</parameter>
295
			</parameter>
296
		</syntax>
296
		</syntax>
297
		<description>
297
		<description>
298
			<note><para>DEPRECATED. Use VM_INFO(mailbox[@context],exists) instead.</para></note>
298
			<note><para>DEPRECATED. Use VM_INFO(mailbox[@context],exists) instead.</para></note>
299
			<para>Check to see if the specified <replaceable>mailbox</replaceable> exists. If no voicemail
299
			<para>Check to see if the specified <replaceable>mailbox</replaceable> exists. If no voicemail
300
			<replaceable>context</replaceable> is specified, the <literal>default</literal> context
300
			<replaceable>context</replaceable> is specified, the <literal>default</literal> context
301
			will be used.</para>
301
			will be used.</para>
302
			<para>This application will set the following channel variable upon completion:</para>
302
			<para>This application will set the following channel variable upon completion:</para>
303
			<variablelist>
303
			<variablelist>
304
				<variable name="VMBOXEXISTSSTATUS">
304
				<variable name="VMBOXEXISTSSTATUS">
305
					<para>This will contain the status of the execution of the MailboxExists application.
305
					<para>This will contain the status of the execution of the MailboxExists application.
306
					Possible values include:</para>
306
					Possible values include:</para>
307
					<value name="SUCCESS" />
307
					<value name="SUCCESS" />
308
					<value name="FAILED" />
308
					<value name="FAILED" />
309
				</variable>
309
				</variable>
310
			</variablelist>
310
			</variablelist>
311
		</description>
311
		</description>
312
		<see-also>
312
		<see-also>
313
			<ref type="function">VM_INFO</ref>
313
			<ref type="function">VM_INFO</ref>
314
		</see-also>
314
		</see-also>
315
	</application>
315
	</application>
316
	<application name="VMAuthenticate" language="en_US">
316
	<application name="VMAuthenticate" language="en_US">
317
		<synopsis>
317
		<synopsis>
318
			Authenticate with Voicemail passwords.
318
			Authenticate with Voicemail passwords.
319
		</synopsis>
319
		</synopsis>
320
		<syntax>
320
		<syntax>
321
			<parameter name="mailbox" required="true" argsep="@">
321
			<parameter name="mailbox" required="true" argsep="@">
322
				<argument name="mailbox" />
322
				<argument name="mailbox" />
323
				<argument name="context" />
323
				<argument name="context" />
324
			</parameter>
324
			</parameter>
325
			<parameter name="options">
325
			<parameter name="options">
326
				<optionlist>
326
				<optionlist>
327
					<option name="s">
327
					<option name="s">
328
						<para>Skip playing the initial prompts.</para>
328
						<para>Skip playing the initial prompts.</para>
329
					</option>
329
					</option>
330
				</optionlist>
330
				</optionlist>
331
			</parameter>
331
			</parameter>
332
		</syntax>
332
		</syntax>
333
		<description>
333
		<description>
334
			<para>This application behaves the same way as the Authenticate application, but the passwords
334
			<para>This application behaves the same way as the Authenticate application, but the passwords
335
			are taken from <filename>voicemail.conf</filename>. If the <replaceable>mailbox</replaceable> is
335
			are taken from <filename>voicemail.conf</filename>. If the <replaceable>mailbox</replaceable> is
336
			specified, only that mailbox's password will be considered valid. If the <replaceable>mailbox</replaceable>
336
			specified, only that mailbox's password will be considered valid. If the <replaceable>mailbox</replaceable>
337
			is not specified, the channel variable <variable>AUTH_MAILBOX</variable> will be set with the authenticated
337
			is not specified, the channel variable <variable>AUTH_MAILBOX</variable> will be set with the authenticated
338
			mailbox.</para>
338
			mailbox.</para>
339
			<para>The VMAuthenticate application will exit if the following DTMF digit is entered as Mailbox
339
			<para>The VMAuthenticate application will exit if the following DTMF digit is entered as Mailbox
340
			or Password, and the extension exists:</para>
340
			or Password, and the extension exists:</para>
341
			<enumlist>
341
			<enumlist>
342
				<enum name="*">
342
				<enum name="*">
343
					<para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
343
					<para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
344
				</enum>
344
				</enum>
345
			</enumlist>
345
			</enumlist>
346
		</description>
346
		</description>
347
	</application>
347
	</application>
348
	<application name="VoiceMailPlayMsg" language="en_US">
348
	<application name="VoiceMailPlayMsg" language="en_US">
349
		<synopsis>
349
		<synopsis>
350
			Play a single voice mail msg from a mailbox by msg id.
350
			Play a single voice mail msg from a mailbox by msg id.
351
		</synopsis>
351
		</synopsis>
352
		<syntax>
352
		<syntax>
353
			<parameter name="mailbox" required="true" argsep="@">
353
			<parameter name="mailbox" required="true" argsep="@">
354
				<argument name="mailbox" />
354
				<argument name="mailbox" />
355
				<argument name="context" />
355
				<argument name="context" />
356
			</parameter>
356
			</parameter>
357
			<parameter name="msg_id" required="true">
357
			<parameter name="msg_id" required="true">
358
				<para>The msg id of the msg to play back. </para>
358
				<para>The msg id of the msg to play back. </para>
359
			</parameter>
359
			</parameter>
360
		</syntax>
360
		</syntax>
361
		<description>
361
		<description>
362
			<para>This application sets the following channel variable upon completion:</para>
362
			<para>This application sets the following channel variable upon completion:</para>
363
			<variablelist>
363
			<variablelist>
364
				<variable name="VOICEMAIL_PLAYBACKSTATUS">
364
				<variable name="VOICEMAIL_PLAYBACKSTATUS">
365
					<para>The status of the playback attempt as a text string.</para>
365
					<para>The status of the playback attempt as a text string.</para>
366
					<value name="SUCCESS"/>
366
					<value name="SUCCESS"/>
367
					<value name="FAILED"/>
367
					<value name="FAILED"/>
368
				</variable>
368
				</variable>
369
			</variablelist>
369
			</variablelist>
370
		</description>
370
		</description>
371
	</application>
371
	</application>
372
	<application name="VMSayName" language="en_US">
372
	<application name="VMSayName" language="en_US">
373
		<synopsis>
373
		<synopsis>
374
			Play the name of a voicemail user
374
			Play the name of a voicemail user
375
		</synopsis>
375
		</synopsis>
376
		<syntax>
376
		<syntax>
377
			<parameter name="mailbox" required="true" argsep="@">
377
			<parameter name="mailbox" required="true" argsep="@">
378
				<argument name="mailbox" />
378
				<argument name="mailbox" />
379
				<argument name="context" />
379
				<argument name="context" />
380
			</parameter>
380
			</parameter>
381
		</syntax>
381
		</syntax>
382
		<description>
382
		<description>
383
			<para>This application will say the recorded name of the voicemail user specified as the
383
			<para>This application will say the recorded name of the voicemail user specified as the
384
			argument to this application. If no context is provided, <literal>default</literal> is assumed.</para>
384
			argument to this application. If no context is provided, <literal>default</literal> is assumed.</para>
385
		</description>
385
		</description>
386
	</application>
386
	</application>
387
	<function name="MAILBOX_EXISTS" language="en_US">
387
	<function name="MAILBOX_EXISTS" language="en_US">
388
		<synopsis>
388
		<synopsis>
389
			Tell if a mailbox is configured.
389
			Tell if a mailbox is configured.
390
		</synopsis>
390
		</synopsis>
391
		<syntax argsep="@">
391
		<syntax argsep="@">
392
			<parameter name="mailbox" required="true" />
392
			<parameter name="mailbox" required="true" />
393
			<parameter name="context" />
393
			<parameter name="context" />
394
		</syntax>
394
		</syntax>
395
		<description>
395
		<description>
396
			<note><para>DEPRECATED. Use VM_INFO(mailbox[@context],exists) instead.</para></note>
396
			<note><para>DEPRECATED. Use VM_INFO(mailbox[@context],exists) instead.</para></note>
397
			<para>Returns a boolean of whether the corresponding <replaceable>mailbox</replaceable> exists.
397
			<para>Returns a boolean of whether the corresponding <replaceable>mailbox</replaceable> exists.
398
			If <replaceable>context</replaceable> is not specified, defaults to the <literal>default</literal>
398
			If <replaceable>context</replaceable> is not specified, defaults to the <literal>default</literal>
399
			context.</para>
399
			context.</para>
400
		</description>
400
		</description>
401
		<see-also>
401
		<see-also>
402
			<ref type="function">VM_INFO</ref>
402
			<ref type="function">VM_INFO</ref>
403
		</see-also>
403
		</see-also>
404
	</function>
404
	</function>
405
	<function name="VM_INFO" language="en_US">
405
	<function name="VM_INFO" language="en_US">
406
		<synopsis>
406
		<synopsis>
407
			Returns the selected attribute from a mailbox.
407
			Returns the selected attribute from a mailbox.
408
		</synopsis>
408
		</synopsis>
409
		<syntax argsep=",">
409
		<syntax argsep=",">
410
			<parameter name="mailbox" argsep="@" required="true">
410
			<parameter name="mailbox" argsep="@" required="true">
411
				<argument name="mailbox" required="true" />
411
				<argument name="mailbox" required="true" />
412
				<argument name="context" />
412
				<argument name="context" />
413
			</parameter>
413
			</parameter>
414
			<parameter name="attribute" required="true">
414
			<parameter name="attribute" required="true">
415
				<optionlist>
415
				<optionlist>
416
					<option name="count">
416
					<option name="count">
417
						<para>Count of messages in specified <replaceable>folder</replaceable>.
417
						<para>Count of messages in specified <replaceable>folder</replaceable>.
418
						If <replaceable>folder</replaceable> is not specified, defaults to <literal>INBOX</literal>.</para>
418
						If <replaceable>folder</replaceable> is not specified, defaults to <literal>INBOX</literal>.</para>
419
					</option>
419
					</option>
420
					<option name="email">
420
					<option name="email">
421
						<para>E-mail address associated with the mailbox.</para>
421
						<para>E-mail address associated with the mailbox.</para>
422
					</option>
422
					</option>
423
					<option name="exists">
423
					<option name="exists">
424
						<para>Returns a boolean of whether the corresponding <replaceable>mailbox</replaceable> exists.</para>
424
						<para>Returns a boolean of whether the corresponding <replaceable>mailbox</replaceable> exists.</para>
425
					</option>
425
					</option>
426
					<option name="fullname">
426
					<option name="fullname">
427
						<para>Full name associated with the mailbox.</para>
427
						<para>Full name associated with the mailbox.</para>
428
					</option>
428
					</option>
429
					<option name="language">
429
					<option name="language">
430
						<para>Mailbox language if overridden, otherwise the language of the channel.</para>
430
						<para>Mailbox language if overridden, otherwise the language of the channel.</para>
431
					</option>
431
					</option>
432
					<option name="locale">
432
					<option name="locale">
433
						<para>Mailbox locale if overridden, otherwise global locale.</para>
433
						<para>Mailbox locale if overridden, otherwise global locale.</para>
434
					</option>
434
					</option>
435
					<option name="pager">
435
					<option name="pager">
436
						<para>Pager e-mail address associated with the mailbox.</para>
436
						<para>Pager e-mail address associated with the mailbox.</para>
437
					</option>
437
					</option>
438
					<option name="password">
438
					<option name="password">
439
						<para>Mailbox access password.</para>
439
						<para>Mailbox access password.</para>
440
					</option>
440
					</option>
441
					<option name="tz">
441
					<option name="tz">
442
						<para>Mailbox timezone if overridden, otherwise global timezone</para>
442
						<para>Mailbox timezone if overridden, otherwise global timezone</para>
443
					</option>
443
					</option>
444
				</optionlist>
444
				</optionlist>
445
			</parameter>
445
			</parameter>
446
			<parameter name="folder" required="false">
446
			<parameter name="folder" required="false">
447
				<para>If not specified, <literal>INBOX</literal> is assumed.</para>
447
				<para>If not specified, <literal>INBOX</literal> is assumed.</para>
448
			</parameter>
448
			</parameter>
449
		</syntax>
449
		</syntax>
450
		<description>
450
		<description>
451
			<para>Returns the selected attribute from the specified <replaceable>mailbox</replaceable>.
451
			<para>Returns the selected attribute from the specified <replaceable>mailbox</replaceable>.
452
			If <replaceable>context</replaceable> is not specified, defaults to the <literal>default</literal>
452
			If <replaceable>context</replaceable> is not specified, defaults to the <literal>default</literal>
453
			context. Where the <replaceable>folder</replaceable> can be specified, common folders
453
			context. Where the <replaceable>folder</replaceable> can be specified, common folders
454
			include <literal>INBOX</literal>, <literal>Old</literal>, <literal>Work</literal>,
454
			include <literal>INBOX</literal>, <literal>Old</literal>, <literal>Work</literal>,
455
			<literal>Family</literal> and <literal>Friends</literal>.</para>
455
			<literal>Family</literal> and <literal>Friends</literal>.</para>
456
		</description>
456
		</description>
457
	</function>
457
	</function>
458
	<manager name="VoicemailUsersList" language="en_US">
458
	<manager name="VoicemailUsersList" language="en_US">
459
		<synopsis>
459
		<synopsis>
460
			List All Voicemail User Information.
460
			List All Voicemail User Information.
461
		</synopsis>
461
		</synopsis>
462
		<syntax>
462
		<syntax>
463
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
463
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
464
		</syntax>
464
		</syntax>
465
		<description>
465
		<description>
466
		</description>
466
		</description>
467
	</manager>
467
	</manager>
468
	<manager name="VoicemailRefresh" language="en_US">
468
	<manager name="VoicemailRefresh" language="en_US">
469
		<synopsis>
469
		<synopsis>
470
			Tell Asterisk to poll mailboxes for a change
470
			Tell Asterisk to poll mailboxes for a change
471
		</synopsis>
471
		</synopsis>
472
		<syntax>
472
		<syntax>
473
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
473
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
474
			<parameter name="Context" />
474
			<parameter name="Context" />
475
			<parameter name="Mailbox" />
475
			<parameter name="Mailbox" />
476
		</syntax>
476
		</syntax>
477
		<description>
477
		<description>
478
			<para>Normally, MWI indicators are only sent when Asterisk itself
478
			<para>Normally, MWI indicators are only sent when Asterisk itself
479
			changes a mailbox.  With external programs that modify the content
479
			changes a mailbox.  With external programs that modify the content
480
			of a mailbox from outside the application, an option exists called
480
			of a mailbox from outside the application, an option exists called
481
			<literal>pollmailboxes</literal> that will cause voicemail to
481
			<literal>pollmailboxes</literal> that will cause voicemail to
482
			continually scan all mailboxes on a system for changes.  This can
482
			continually scan all mailboxes on a system for changes.  This can
483
			cause a large amount of load on a system.  This command allows
483
			cause a large amount of load on a system.  This command allows
484
			external applications to signal when a particular mailbox has
484
			external applications to signal when a particular mailbox has
485
			changed, thus permitting external applications to modify mailboxes
485
			changed, thus permitting external applications to modify mailboxes
486
			and MWI to work without introducing considerable CPU load.</para>
486
			and MWI to work without introducing considerable CPU load.</para>
487
			<para>If <replaceable>Context</replaceable> is not specified, all
487
			<para>If <replaceable>Context</replaceable> is not specified, all
488
			mailboxes on the system will be polled for changes.  If
488
			mailboxes on the system will be polled for changes.  If
489
			<replaceable>Context</replaceable> is specified, but
489
			<replaceable>Context</replaceable> is specified, but
490
			<replaceable>Mailbox</replaceable> is omitted, then all mailboxes
490
			<replaceable>Mailbox</replaceable> is omitted, then all mailboxes
491
			within <replaceable>Context</replaceable> will be polled.
491
			within <replaceable>Context</replaceable> will be polled.
492
			Otherwise, only a single mailbox will be polled for changes.</para>
492
			Otherwise, only a single mailbox will be polled for changes.</para>
493
		</description>
493
		</description>
494
	</manager>
494
	</manager>
495
 ***/
495
 ***/
496

    
   
496

   
497
#ifdef IMAP_STORAGE
497
#ifdef IMAP_STORAGE
498
static char imapserver[48];
498
static char imapserver[48];
499
static char imapport[8];
499
static char imapport[8];
500
static char imapflags[128];
500
static char imapflags[128];
501
static char imapfolder[64];
501
static char imapfolder[64];
502
static char imapparentfolder[64] = "\0";
502
static char imapparentfolder[64] = "\0";
503
static char greetingfolder[64];
503
static char greetingfolder[64];
504
static char authuser[32];
504
static char authuser[32];
505
static char authpassword[42];
505
static char authpassword[42];
506
static int imapversion = 1;
506
static int imapversion = 1;
507

    
   
507

   
508
static int expungeonhangup = 1;
508
static int expungeonhangup = 1;
509
static int imapgreetings = 0;
509
static int imapgreetings = 0;
510
static char delimiter = '\0';
510
static char delimiter = '\0';
511

    
   
511

   
512
struct vm_state;
512
struct vm_state;
513
struct ast_vm_user;
513
struct ast_vm_user;
514

    
   
514

   
515
AST_THREADSTORAGE(ts_vmstate);
515
AST_THREADSTORAGE(ts_vmstate);
516

    
   
516

   
517
/* Forward declarations for IMAP */
517
/* Forward declarations for IMAP */
518
static int init_mailstream(struct vm_state *vms, int box);
518
static int init_mailstream(struct vm_state *vms, int box);
519
static void write_file(char *filename, char *buffer, unsigned long len);
519
static void write_file(char *filename, char *buffer, unsigned long len);
520
static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
520
static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
521
static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
521
static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
522
static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
522
static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
523
static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
523
static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
524
static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
524
static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
525
static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
525
static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
526
static void vmstate_insert(struct vm_state *vms);
526
static void vmstate_insert(struct vm_state *vms);
527
static void vmstate_delete(struct vm_state *vms);
527
static void vmstate_delete(struct vm_state *vms);
528
static void set_update(MAILSTREAM * stream);
528
static void set_update(MAILSTREAM * stream);
529
static void init_vm_state(struct vm_state *vms);
529
static void init_vm_state(struct vm_state *vms);
530
static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
530
static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
531
static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream);
531
static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream);
532
static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
532
static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
533
static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
533
static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
534
static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag, const char *msg_id);
534
static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag, const char *msg_id);
535
static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder);
535
static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder);
536
static void update_messages_by_imapuser(const char *user, unsigned long number);
536
static void update_messages_by_imapuser(const char *user, unsigned long number);
537
static int vm_delete(char *file);
537
static int vm_delete(char *file);
538

    
   
538

   
539
static int imap_remove_file (char *dir, int msgnum);
539
static int imap_remove_file (char *dir, int msgnum);
540
static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
540
static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
541
static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
541
static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
542
static void check_quota(struct vm_state *vms, char *mailbox);
542
static void check_quota(struct vm_state *vms, char *mailbox);
543
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
543
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
544
struct vmstate {
544
struct vmstate {
545
	struct vm_state *vms;
545
	struct vm_state *vms;
546
	AST_LIST_ENTRY(vmstate) list;
546
	AST_LIST_ENTRY(vmstate) list;
547
};
547
};
548

    
   
548

   
549
static AST_LIST_HEAD_STATIC(vmstates, vmstate);
549
static AST_LIST_HEAD_STATIC(vmstates, vmstate);
550

    
   
550

   
551
#endif
551
#endif
552

    
   
552

   
553
#define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
553
#define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
554

    
   
554

   
555
#define COMMAND_TIMEOUT 5000
555
#define COMMAND_TIMEOUT 5000
556
/* Don't modify these here; set your umask at runtime instead */
556
/* Don't modify these here; set your umask at runtime instead */
557
#define	VOICEMAIL_DIR_MODE	0777
557
#define	VOICEMAIL_DIR_MODE	0777
558
#define	VOICEMAIL_FILE_MODE	0666
558
#define	VOICEMAIL_FILE_MODE	0666
559
#define	CHUNKSIZE	65536
559
#define	CHUNKSIZE	65536
560

    
   
560

   
561
#define VOICEMAIL_CONFIG "voicemail.conf"
561
#define VOICEMAIL_CONFIG "voicemail.conf"
562
#define ASTERISK_USERNAME "asterisk"
562
#define ASTERISK_USERNAME "asterisk"
563

    
   
563

   
564
/* Define fast-forward, pause, restart, and reverse keys
564
/* Define fast-forward, pause, restart, and reverse keys
565
 * while listening to a voicemail message - these are
565
 * while listening to a voicemail message - these are
566
 * strings, not characters */
566
 * strings, not characters */
567
#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
567
#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
568
#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
568
#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
569
#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
569
#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
570
#define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
570
#define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
571
#define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
571
#define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
572
#define VALID_DTMF "1234567890*#" /* Yes ABCD are valid dtmf but what phones have those? */
572
#define VALID_DTMF "1234567890*#" /* Yes ABCD are valid dtmf but what phones have those? */
573

    
   
573

   
574
/* Default mail command to mail voicemail. Change it with the
574
/* Default mail command to mail voicemail. Change it with the
575
 * mailcmd= command in voicemail.conf */
575
 * mailcmd= command in voicemail.conf */
576
#define SENDMAIL "/usr/sbin/sendmail -t"
576
#define SENDMAIL "/usr/sbin/sendmail -t"
577

    
   
577

   
578
#define INTRO "vm-intro"
578
#define INTRO "vm-intro"
579

    
   
579

   
580
#define MAXMSG 100
580
#define MAXMSG 100
581
#define MAXMSGLIMIT 9999
581
#define MAXMSGLIMIT 9999
582

    
   
582

   
583
#define MINPASSWORD 0 /*!< Default minimum mailbox password length */
583
#define MINPASSWORD 0 /*!< Default minimum mailbox password length */
584

    
   
584

   
585
#define BASELINELEN 72
585
#define BASELINELEN 72
586
#define BASEMAXINLINE 256
586
#define BASEMAXINLINE 256
587
#ifdef IMAP_STORAGE
587
#ifdef IMAP_STORAGE
588
#define ENDL "\r\n"
588
#define ENDL "\r\n"
589
#else
589
#else
590
#define ENDL "\n"
590
#define ENDL "\n"
591
#endif
591
#endif
592

    
   
592

   
593
#define MAX_DATETIME_FORMAT	512
593
#define MAX_DATETIME_FORMAT	512
594
#define MAX_NUM_CID_CONTEXTS 10
594
#define MAX_NUM_CID_CONTEXTS 10
595

    
   
595

   
596
#define VM_REVIEW        (1 << 0)   /*!< After recording, permit the caller to review the recording before saving */
596
#define VM_REVIEW        (1 << 0)   /*!< After recording, permit the caller to review the recording before saving */
597
#define VM_OPERATOR      (1 << 1)   /*!< Allow 0 to be pressed to go to 'o' extension */
597
#define VM_OPERATOR      (1 << 1)   /*!< Allow 0 to be pressed to go to 'o' extension */
598
#define VM_SAYCID        (1 << 2)   /*!< Repeat the CallerID info during envelope playback */
598
#define VM_SAYCID        (1 << 2)   /*!< Repeat the CallerID info during envelope playback */
599
#define VM_SVMAIL        (1 << 3)   /*!< Allow the user to compose a new VM from within VoicemailMain */
599
#define VM_SVMAIL        (1 << 3)   /*!< Allow the user to compose a new VM from within VoicemailMain */
600
#define VM_ENVELOPE      (1 << 4)   /*!< Play the envelope information (who-from, time received, etc.) */
600
#define VM_ENVELOPE      (1 << 4)   /*!< Play the envelope information (who-from, time received, etc.) */
601
#define VM_SAYDURATION   (1 << 5)   /*!< Play the length of the message during envelope playback */
601
#define VM_SAYDURATION   (1 << 5)   /*!< Play the length of the message during envelope playback */
602
#define VM_SKIPAFTERCMD  (1 << 6)   /*!< After deletion, assume caller wants to go to the next message */
602
#define VM_SKIPAFTERCMD  (1 << 6)   /*!< After deletion, assume caller wants to go to the next message */
603
#define VM_FORCENAME     (1 << 7)   /*!< Have new users record their name */
603
#define VM_FORCENAME     (1 << 7)   /*!< Have new users record their name */
604
#define VM_FORCEGREET    (1 << 8)   /*!< Have new users record their greetings */
604
#define VM_FORCEGREET    (1 << 8)   /*!< Have new users record their greetings */
605
#define VM_PBXSKIP       (1 << 9)   /*!< Skip the [PBX] preamble in the Subject line of emails */
605
#define VM_PBXSKIP       (1 << 9)   /*!< Skip the [PBX] preamble in the Subject line of emails */
606
#define VM_DIRECFORWARD  (1 << 10)  /*!< Permit caller to use the Directory app for selecting to which mailbox to forward a VM */
606
#define VM_DIRECFORWARD  (1 << 10)  /*!< Permit caller to use the Directory app for selecting to which mailbox to forward a VM */
607
#define VM_ATTACH        (1 << 11)  /*!< Attach message to voicemail notifications? */
607
#define VM_ATTACH        (1 << 11)  /*!< Attach message to voicemail notifications? */
608
#define VM_DELETE        (1 << 12)  /*!< Delete message after sending notification */
608
#define VM_DELETE        (1 << 12)  /*!< Delete message after sending notification */
609
#define VM_ALLOCED       (1 << 13)  /*!< Structure was malloc'ed, instead of placed in a return (usually static) buffer */
609
#define VM_ALLOCED       (1 << 13)  /*!< Structure was malloc'ed, instead of placed in a return (usually static) buffer */
610
#define VM_SEARCH        (1 << 14)  /*!< Search all contexts for a matching mailbox */
610
#define VM_SEARCH        (1 << 14)  /*!< Search all contexts for a matching mailbox */
611
#define VM_TEMPGREETWARN (1 << 15)  /*!< Remind user tempgreeting is set */
611
#define VM_TEMPGREETWARN (1 << 15)  /*!< Remind user tempgreeting is set */
612
#define VM_MOVEHEARD     (1 << 16)  /*!< Move a "heard" message to Old after listening to it */
612
#define VM_MOVEHEARD     (1 << 16)  /*!< Move a "heard" message to Old after listening to it */
613
#define VM_MESSAGEWRAP   (1 << 17)  /*!< Wrap around from the last message to the first, and vice-versa */
613
#define VM_MESSAGEWRAP   (1 << 17)  /*!< Wrap around from the last message to the first, and vice-versa */
614
#define VM_FWDURGAUTO    (1 << 18)  /*!< Autoset of Urgent flag on forwarded Urgent messages set globally */
614
#define VM_FWDURGAUTO    (1 << 18)  /*!< Autoset of Urgent flag on forwarded Urgent messages set globally */
615
#define ERROR_LOCK_PATH  -100
615
#define ERROR_LOCK_PATH  -100
616
#define OPERATOR_EXIT     300
616
#define OPERATOR_EXIT     300
617

    
   
617

   
618
enum vm_box {
618
enum vm_box {
619
	NEW_FOLDER,
619
	NEW_FOLDER,
620
	OLD_FOLDER,
620
	OLD_FOLDER,
621
	WORK_FOLDER,
621
	WORK_FOLDER,
622
	FAMILY_FOLDER,
622
	FAMILY_FOLDER,
623
	FRIENDS_FOLDER,
623
	FRIENDS_FOLDER,
624
	GREETINGS_FOLDER
624
	GREETINGS_FOLDER
625
};
625
};
626

    
   
626

   
627
enum vm_option_flags {
627
enum vm_option_flags {
628
	OPT_SILENT =           (1 << 0),
628
	OPT_SILENT =           (1 << 0),
629
	OPT_BUSY_GREETING =    (1 << 1),
629
	OPT_BUSY_GREETING =    (1 << 1),
630
	OPT_UNAVAIL_GREETING = (1 << 2),
630
	OPT_UNAVAIL_GREETING = (1 << 2),
631
	OPT_RECORDGAIN =       (1 << 3),
631
	OPT_RECORDGAIN =       (1 << 3),
632
	OPT_PREPEND_MAILBOX =  (1 << 4),
632
	OPT_PREPEND_MAILBOX =  (1 << 4),
633
	OPT_AUTOPLAY =         (1 << 6),
633
	OPT_AUTOPLAY =         (1 << 6),
634
	OPT_DTMFEXIT =         (1 << 7),
634
	OPT_DTMFEXIT =         (1 << 7),
635
	OPT_MESSAGE_Urgent =   (1 << 8),
635
	OPT_MESSAGE_Urgent =   (1 << 8),
636
	OPT_MESSAGE_PRIORITY = (1 << 9)
636
	OPT_MESSAGE_PRIORITY = (1 << 9)
637
};
637
};
638

    
   
638

   
639
enum vm_option_args {
639
enum vm_option_args {
640
	OPT_ARG_RECORDGAIN = 0,
640
	OPT_ARG_RECORDGAIN = 0,
641
	OPT_ARG_PLAYFOLDER = 1,
641
	OPT_ARG_PLAYFOLDER = 1,
642
	OPT_ARG_DTMFEXIT   = 2,
642
	OPT_ARG_DTMFEXIT   = 2,
643
	/* This *must* be the last value in this enum! */
643
	/* This *must* be the last value in this enum! */
644
	OPT_ARG_ARRAY_SIZE = 3,
644
	OPT_ARG_ARRAY_SIZE = 3,
645
};
645
};
646

    
   
646

   
647
enum vm_passwordlocation {
647
enum vm_passwordlocation {
648
	OPT_PWLOC_VOICEMAILCONF = 0,
648
	OPT_PWLOC_VOICEMAILCONF = 0,
649
	OPT_PWLOC_SPOOLDIR      = 1,
649
	OPT_PWLOC_SPOOLDIR      = 1,
650
	OPT_PWLOC_USERSCONF     = 2,
650
	OPT_PWLOC_USERSCONF     = 2,
651
};
651
};
652

    
   
652

   
653
AST_APP_OPTIONS(vm_app_options, {
653
AST_APP_OPTIONS(vm_app_options, {
654
	AST_APP_OPTION('s', OPT_SILENT),
654
	AST_APP_OPTION('s', OPT_SILENT),
655
	AST_APP_OPTION('b', OPT_BUSY_GREETING),
655
	AST_APP_OPTION('b', OPT_BUSY_GREETING),
656
	AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
656
	AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
657
	AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
657
	AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
658
	AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
658
	AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
659
	AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
659
	AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
660
	AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
660
	AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
661
	AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
661
	AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
662
	AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
662
	AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
663
});
663
});
664

    
   
664

   
665
static const char * const mailbox_folders[] = {
665
static const char * const mailbox_folders[] = {
666
#ifdef IMAP_STORAGE
666
#ifdef IMAP_STORAGE
667
	imapfolder,
667
	imapfolder,
668
#else
668
#else
669
	"INBOX",
669
	"INBOX",
670
#endif
670
#endif
671
	"Old",
671
	"Old",
672
	"Work",
672
	"Work",
673
	"Family",
673
	"Family",
674
	"Friends",
674
	"Friends",
675
	"Cust1",
675
	"Cust1",
676
	"Cust2",
676
	"Cust2",
677
	"Cust3",
677
	"Cust3",
678
	"Cust4",
678
	"Cust4",
679
	"Cust5",
679
	"Cust5",
680
	"Deleted",
680
	"Deleted",
681
	"Urgent",
681
	"Urgent",
682
};
682
};
683

    
   
683

   
684
static int load_config(int reload);
684
static int load_config(int reload);
685
#ifdef TEST_FRAMEWORK
685
#ifdef TEST_FRAMEWORK
686
static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
686
static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
687
#endif
687
#endif
688
static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
688
static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
689

    
   
689

   
690
/*! \page vmlang Voicemail Language Syntaxes Supported
690
/*! \page vmlang Voicemail Language Syntaxes Supported
691

    
   
691

   
692
	\par Syntaxes supported, not really language codes.
692
	\par Syntaxes supported, not really language codes.
693
	\arg \b en    - English
693
	\arg \b en    - English
694
	\arg \b de    - German
694
	\arg \b de    - German
695
	\arg \b es    - Spanish
695
	\arg \b es    - Spanish
696
	\arg \b fr    - French
696
	\arg \b fr    - French
697
	\arg \b it    - Italian
697
	\arg \b it    - Italian
698
	\arg \b nl    - Dutch
698
	\arg \b nl    - Dutch
699
	\arg \b pt    - Portuguese
699
	\arg \b pt    - Portuguese
700
	\arg \b pt_BR - Portuguese (Brazil)
700
	\arg \b pt_BR - Portuguese (Brazil)
701
	\arg \b gr    - Greek
701
	\arg \b gr    - Greek
702
	\arg \b no    - Norwegian
702
	\arg \b no    - Norwegian
703
	\arg \b se    - Swedish
703
	\arg \b se    - Swedish
704
	\arg \b tw    - Chinese (Taiwan)
704
	\arg \b tw    - Chinese (Taiwan)
705
	\arg \b ua - Ukrainian
705
	\arg \b ua - Ukrainian
706

    
   
706

   
707
German requires the following additional soundfile:
707
German requires the following additional soundfile:
708
\arg \b 1F	einE (feminine)
708
\arg \b 1F	einE (feminine)
709

    
   
709

   
710
Spanish requires the following additional soundfile:
710
Spanish requires the following additional soundfile:
711
\arg \b 1M      un (masculine)
711
\arg \b 1M      un (masculine)
712

    
   
712

   
713
Dutch, Portuguese & Spanish require the following additional soundfiles:
713
Dutch, Portuguese & Spanish require the following additional soundfiles:
714
\arg \b vm-INBOXs	singular of 'new'
714
\arg \b vm-INBOXs	singular of 'new'
715
\arg \b vm-Olds		singular of 'old/heard/read'
715
\arg \b vm-Olds		singular of 'old/heard/read'
716

    
   
716

   
717
NB these are plural:
717
NB these are plural:
718
\arg \b vm-INBOX	nieuwe (nl)
718
\arg \b vm-INBOX	nieuwe (nl)
719
\arg \b vm-Old		oude (nl)
719
\arg \b vm-Old		oude (nl)
720

    
   
720

   
721
Polish uses:
721
Polish uses:
722
\arg \b vm-new-a	'new', feminine singular accusative
722
\arg \b vm-new-a	'new', feminine singular accusative
723
\arg \b vm-new-e	'new', feminine plural accusative
723
\arg \b vm-new-e	'new', feminine plural accusative
724
\arg \b vm-new-ych	'new', feminine plural genitive
724
\arg \b vm-new-ych	'new', feminine plural genitive
725
\arg \b vm-old-a	'old', feminine singular accusative
725
\arg \b vm-old-a	'old', feminine singular accusative
726
\arg \b vm-old-e	'old', feminine plural accusative
726
\arg \b vm-old-e	'old', feminine plural accusative
727
\arg \b vm-old-ych	'old', feminine plural genitive
727
\arg \b vm-old-ych	'old', feminine plural genitive
728
\arg \b digits/1-a	'one', not always same as 'digits/1'
728
\arg \b digits/1-a	'one', not always same as 'digits/1'
729
\arg \b digits/2-ie	'two', not always same as 'digits/2'
729
\arg \b digits/2-ie	'two', not always same as 'digits/2'
730

    
   
730

   
731
Swedish uses:
731
Swedish uses:
732
\arg \b vm-nytt		singular of 'new'
732
\arg \b vm-nytt		singular of 'new'
733
\arg \b vm-nya		plural of 'new'
733
\arg \b vm-nya		plural of 'new'
734
\arg \b vm-gammalt	singular of 'old'
734
\arg \b vm-gammalt	singular of 'old'
735
\arg \b vm-gamla	plural of 'old'
735
\arg \b vm-gamla	plural of 'old'
736
\arg \b digits/ett	'one', not always same as 'digits/1'
736
\arg \b digits/ett	'one', not always same as 'digits/1'
737

    
   
737

   
738
Norwegian uses:
738
Norwegian uses:
739
\arg \b vm-ny		singular of 'new'
739
\arg \b vm-ny		singular of 'new'
740
\arg \b vm-nye		plural of 'new'
740
\arg \b vm-nye		plural of 'new'
741
\arg \b vm-gammel	singular of 'old'
741
\arg \b vm-gammel	singular of 'old'
742
\arg \b vm-gamle	plural of 'old'
742
\arg \b vm-gamle	plural of 'old'
743

    
   
743

   
744
Dutch also uses:
744
Dutch also uses:
745
\arg \b nl-om		'at'?
745
\arg \b nl-om		'at'?
746

    
   
746

   
747
Spanish also uses:
747
Spanish also uses:
748
\arg \b vm-youhaveno
748
\arg \b vm-youhaveno
749

    
   
749

   
750
Italian requires the following additional soundfile:
750
Italian requires the following additional soundfile:
751

    
   
751

   
752
For vm_intro_it:
752
For vm_intro_it:
753
\arg \b vm-nuovo	new
753
\arg \b vm-nuovo	new
754
\arg \b vm-nuovi	new plural
754
\arg \b vm-nuovi	new plural
755
\arg \b vm-vecchio	old
755
\arg \b vm-vecchio	old
756
\arg \b vm-vecchi	old plural
756
\arg \b vm-vecchi	old plural
757

    
   
757

   
758
Chinese (Taiwan) requires the following additional soundfile:
758
Chinese (Taiwan) requires the following additional soundfile:
759
\arg \b vm-tong		A class-word for call (tong1)
759
\arg \b vm-tong		A class-word for call (tong1)
760
\arg \b vm-ri		A class-word for day (ri4)
760
\arg \b vm-ri		A class-word for day (ri4)
761
\arg \b vm-you		You (ni3)
761
\arg \b vm-you		You (ni3)
762
\arg \b vm-haveno   Have no (mei2 you3)
762
\arg \b vm-haveno   Have no (mei2 you3)
763
\arg \b vm-have     Have (you3)
763
\arg \b vm-have     Have (you3)
764
\arg \b vm-listen   To listen (yao4 ting1)
764
\arg \b vm-listen   To listen (yao4 ting1)
765

    
   
765

   
766

    
   
766

   
767
\note Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folders,
767
\note Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folders,
768
spelled among others when you have to change folder. For the above reasons, vm-INBOX
768
spelled among others when you have to change folder. For the above reasons, vm-INBOX
769
and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
769
and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
770

    
   
770

   
771
*/
771
*/
772

    
   
772

   
773
struct baseio {
773
struct baseio {
774
	int iocp;
774
	int iocp;
775
	int iolen;
775
	int iolen;
776
	int linelength;
776
	int linelength;
777
	int ateof;
777
	int ateof;
778
	unsigned char iobuf[BASEMAXINLINE];
778
	unsigned char iobuf[BASEMAXINLINE];
779
};
779
};
780

    
   
780

   
781
/*! Structure for linked list of users 
781
/*! Structure for linked list of users 
782
 * Use ast_vm_user_destroy() to free one of these structures. */
782
 * Use ast_vm_user_destroy() to free one of these structures. */
783
struct ast_vm_user {
783
struct ast_vm_user {
784
	char context[AST_MAX_CONTEXT];   /*!< Voicemail context */
784
	char context[AST_MAX_CONTEXT];   /*!< Voicemail context */
785
	char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
785
	char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
786
	char password[80];               /*!< Secret pin code, numbers only */
786
	char password[80];               /*!< Secret pin code, numbers only */
787
	char fullname[80];               /*!< Full name, for directory app */
787
	char fullname[80];               /*!< Full name, for directory app */
788
	char email[80];                  /*!< E-mail address */
788
	char email[512];                  /*!< E-mail address */
789
	char *emailsubject;              /*!< E-mail subject */
789
	char *emailsubject;              /*!< E-mail subject */
790
	char *emailbody;                 /*!< E-mail body */
790
	char *emailbody;                 /*!< E-mail body */
791
	char pager[80];                  /*!< E-mail address to pager (no attachment) */
791
	char pager[80];                  /*!< E-mail address to pager (no attachment) */
792
	char serveremail[80];            /*!< From: Mail address */
792
	char serveremail[80];            /*!< From: Mail address */
793
	char language[MAX_LANGUAGE];     /*!< Config: Language setting */
793
	char language[MAX_LANGUAGE];     /*!< Config: Language setting */
794
	char zonetag[80];                /*!< Time zone */
794
	char zonetag[80];                /*!< Time zone */
795
	char locale[20];                 /*!< The locale (for presentation of date/time) */
795
	char locale[20];                 /*!< The locale (for presentation of date/time) */
796
	char callback[80];
796
	char callback[80];
797
	char dialout[80];
797
	char dialout[80];
798
	char uniqueid[80];               /*!< Unique integer identifier */
798
	char uniqueid[80];               /*!< Unique integer identifier */
799
	char exit[80];
799
	char exit[80];
800
	char attachfmt[20];              /*!< Attachment format */
800
	char attachfmt[20];              /*!< Attachment format */
801
	unsigned int flags;              /*!< VM_ flags */	
801
	unsigned int flags;              /*!< VM_ flags */	
802
	int saydurationm;
802
	int saydurationm;
803
	int minsecs;                     /*!< Minimum number of seconds per message for this mailbox */
803
	int minsecs;                     /*!< Minimum number of seconds per message for this mailbox */
804
	int maxmsg;                      /*!< Maximum number of msgs per folder for this mailbox */
804
	int maxmsg;                      /*!< Maximum number of msgs per folder for this mailbox */
805
	int maxdeletedmsg;               /*!< Maximum number of deleted msgs saved for this mailbox */
805
	int maxdeletedmsg;               /*!< Maximum number of deleted msgs saved for this mailbox */
806
	int maxsecs;                     /*!< Maximum number of seconds per message for this mailbox */
806
	int maxsecs;                     /*!< Maximum number of seconds per message for this mailbox */
807
	int passwordlocation;            /*!< Storage location of the password */
807
	int passwordlocation;            /*!< Storage location of the password */
808
#ifdef IMAP_STORAGE
808
#ifdef IMAP_STORAGE
809
	char imapserver[48];             /*!< IMAP server address */
809
	char imapserver[48];             /*!< IMAP server address */
810
	char imapport[8];                /*!< IMAP server port */
810
	char imapport[8];                /*!< IMAP server port */
811
	char imapflags[128];             /*!< IMAP optional flags */
811
	char imapflags[128];             /*!< IMAP optional flags */
812
	char imapuser[80];               /*!< IMAP server login */
812
	char imapuser[80];               /*!< IMAP server login */
813
	char imappassword[80];           /*!< IMAP server password if authpassword not defined */
813
	char imappassword[80];           /*!< IMAP server password if authpassword not defined */
814
	char imapfolder[64];             /*!< IMAP voicemail folder */
814
	char imapfolder[64];             /*!< IMAP voicemail folder */
815
	char imapvmshareid[80];          /*!< Shared mailbox ID to use rather than the dialed one */
815
	char imapvmshareid[80];          /*!< Shared mailbox ID to use rather than the dialed one */
816
	int imapversion;                 /*!< If configuration changes, use the new values */
816
	int imapversion;                 /*!< If configuration changes, use the new values */
817
#endif
817
#endif
818
	double volgain;                  /*!< Volume gain for voicemails sent via email */
818
	double volgain;                  /*!< Volume gain for voicemails sent via email */
819
	AST_LIST_ENTRY(ast_vm_user) list;
819
	AST_LIST_ENTRY(ast_vm_user) list;
820
};
820
};
821

    
   
821

   
822
/*! Voicemail time zones */
822
/*! Voicemail time zones */
823
struct vm_zone {
823
struct vm_zone {
824
	AST_LIST_ENTRY(vm_zone) list;
824
	AST_LIST_ENTRY(vm_zone) list;
825
	char name[80];
825
	char name[80];
826
	char timezone[80];
826
	char timezone[80];
827
	char msg_format[512];
827
	char msg_format[512];
828
};
828
};
829

    
   
829

   
830
#define VMSTATE_MAX_MSG_ARRAY 256
830
#define VMSTATE_MAX_MSG_ARRAY 256
831

    
   
831

   
832
/*! Voicemail mailbox state */
832
/*! Voicemail mailbox state */
833
struct vm_state {
833
struct vm_state {
834
	char curbox[80];
834
	char curbox[80];
835
	char username[80];
835
	char username[80];
836
	char context[80];
836
	char context[80];
837
	char curdir[PATH_MAX];
837
	char curdir[PATH_MAX];
838
	char vmbox[PATH_MAX];
838
	char vmbox[PATH_MAX];
839
	char fn[PATH_MAX];
839
	char fn[PATH_MAX];
840
	char intro[PATH_MAX];
840
	char intro[PATH_MAX];
841
	int *deleted;
841
	int *deleted;
842
	int *heard;
842
	int *heard;
843
	int dh_arraysize; /* used for deleted / heard allocation */
843
	int dh_arraysize; /* used for deleted / heard allocation */
844
	int curmsg;
844
	int curmsg;
845
	int lastmsg;
845
	int lastmsg;
846
	int newmessages;
846
	int newmessages;
847
	int oldmessages;
847
	int oldmessages;
848
	int urgentmessages;
848
	int urgentmessages;
849
	int starting;
849
	int starting;
850
	int repeats;
850
	int repeats;
851
#ifdef IMAP_STORAGE
851
#ifdef IMAP_STORAGE
852
	ast_mutex_t lock;
852
	ast_mutex_t lock;
853
	int updated;                         /*!< decremented on each mail check until 1 -allows delay */
853
	int updated;                         /*!< decremented on each mail check until 1 -allows delay */
854
	long msgArray[VMSTATE_MAX_MSG_ARRAY];
854
	long msgArray[VMSTATE_MAX_MSG_ARRAY];
855
	MAILSTREAM *mailstream;
855
	MAILSTREAM *mailstream;
856
	int vmArrayIndex;
856
	int vmArrayIndex;
857
	char imapuser[80];                   /*!< IMAP server login */
857
	char imapuser[80];                   /*!< IMAP server login */
858
	char imapfolder[64];                 /*!< IMAP voicemail folder */
858
	char imapfolder[64];                 /*!< IMAP voicemail folder */
859
	char imapserver[48];                 /*!< IMAP server address */
859
	char imapserver[48];                 /*!< IMAP server address */
860
	char imapport[8];                    /*!< IMAP server port */
860
	char imapport[8];                    /*!< IMAP server port */
861
	char imapflags[128];                 /*!< IMAP optional flags */
861
	char imapflags[128];                 /*!< IMAP optional flags */
862
	int imapversion;
862
	int imapversion;
863
	int interactive;
863
	int interactive;
864
	char introfn[PATH_MAX];              /*!< Name of prepended file */
864
	char introfn[PATH_MAX];              /*!< Name of prepended file */
865
	unsigned int quota_limit;
865
	unsigned int quota_limit;
866
	unsigned int quota_usage;
866
	unsigned int quota_usage;
867
	struct vm_state *persist_vms;
867
	struct vm_state *persist_vms;
868
#endif
868
#endif
869
};
869
};
870

    
   
870

   
871
#ifdef ODBC_STORAGE
871
#ifdef ODBC_STORAGE
872
static char odbc_database[80];
872
static char odbc_database[80];
873
static char odbc_table[80];
873
static char odbc_table[80];
874
#define RETRIEVE(a,b,c,d) retrieve_file(a,b)
874
#define RETRIEVE(a,b,c,d) retrieve_file(a,b)
875
#define DISPOSE(a,b) remove_file(a,b)
875
#define DISPOSE(a,b) remove_file(a,b)
876
#define STORE(a,b,c,d,e,f,g,h,i,j,k) store_file(a,b,c,d)
876
#define STORE(a,b,c,d,e,f,g,h,i,j,k) store_file(a,b,c,d)
877
#define EXISTS(a,b,c,d) (message_exists(a,b))
877
#define EXISTS(a,b,c,d) (message_exists(a,b))
878
#define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
878
#define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
879
#define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
879
#define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
880
#define DELETE(a,b,c,d) (delete_file(a,b))
880
#define DELETE(a,b,c,d) (delete_file(a,b))
881
#define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
881
#define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
882
#else
882
#else
883
#ifdef IMAP_STORAGE
883
#ifdef IMAP_STORAGE
884
#define DISPOSE(a,b) (imap_remove_file(a,b))
884
#define DISPOSE(a,b) (imap_remove_file(a,b))
885
#define STORE(a,b,c,d,e,f,g,h,i,j,k) (imap_store_file(a,b,c,d,e,f,g,h,i,j,k))
885
#define STORE(a,b,c,d,e,f,g,h,i,j,k) (imap_store_file(a,b,c,d,e,f,g,h,i,j,k))
886
#define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
886
#define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
887
#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
887
#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
888
#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
888
#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
889
#define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
889
#define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
890
#define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
890
#define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
891
#define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
891
#define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
892
#else
892
#else
893
#define RETRIEVE(a,b,c,d)
893
#define RETRIEVE(a,b,c,d)
894
#define DISPOSE(a,b)
894
#define DISPOSE(a,b)
895
#define STORE(a,b,c,d,e,f,g,h,i,j,k)
895
#define STORE(a,b,c,d,e,f,g,h,i,j,k)
896
#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
896
#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
897
#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
897
#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
898
#define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h)); 
898
#define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h)); 
899
#define DELETE(a,b,c,d) (vm_delete(c))
899
#define DELETE(a,b,c,d) (vm_delete(c))
900
#define UPDATE_MSG_ID(a, b, c, d, e, f)
900
#define UPDATE_MSG_ID(a, b, c, d, e, f)
901
#endif
901
#endif
902
#endif
902
#endif
903

    
   
903

   
904
static char VM_SPOOL_DIR[PATH_MAX];
904
static char VM_SPOOL_DIR[PATH_MAX];
905

    
   
905

   
906
static char ext_pass_cmd[128];
906
static char ext_pass_cmd[128];
907
static char ext_pass_check_cmd[128];
907
static char ext_pass_check_cmd[128];
908

    
   
908

   
909
static int my_umask;
909
static int my_umask;
910

    
   
910

   
911
#define PWDCHANGE_INTERNAL (1 << 1)
911
#define PWDCHANGE_INTERNAL (1 << 1)
912
#define PWDCHANGE_EXTERNAL (1 << 2)
912
#define PWDCHANGE_EXTERNAL (1 << 2)
913
static int pwdchange = PWDCHANGE_INTERNAL;
913
static int pwdchange = PWDCHANGE_INTERNAL;
914

    
   
914

   
915
#ifdef ODBC_STORAGE
915
#ifdef ODBC_STORAGE
916
#define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
916
#define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
917
#else
917
#else
918
# ifdef IMAP_STORAGE
918
# ifdef IMAP_STORAGE
919
# define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
919
# define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
920
# else
920
# else
921
# define tdesc "Comedian Mail (Voicemail System)"
921
# define tdesc "Comedian Mail (Voicemail System)"
922
# endif
922
# endif
923
#endif
923
#endif
924

    
   
924

   
925
static char userscontext[AST_MAX_EXTENSION] = "default";
925
static char userscontext[AST_MAX_EXTENSION] = "default";
926

    
   
926

   
927
static char *addesc = "Comedian Mail";
927
static char *addesc = "Comedian Mail";
928

    
   
928

   
929
/* Leave a message */
929
/* Leave a message */
930
static char *app = "VoiceMail";
930
static char *app = "VoiceMail";
931

    
   
931

   
932
/* Check mail, control, etc */
932
/* Check mail, control, etc */
933
static char *app2 = "VoiceMailMain";
933
static char *app2 = "VoiceMailMain";
934

    
   
934

   
935
static char *app3 = "MailboxExists";
935
static char *app3 = "MailboxExists";
936
static char *app4 = "VMAuthenticate";
936
static char *app4 = "VMAuthenticate";
937

    
   
937

   
938
static char *playmsg_app = "VoiceMailPlayMsg";
938
static char *playmsg_app = "VoiceMailPlayMsg";
939

    
   
939

   
940
static char *sayname_app = "VMSayName";
940
static char *sayname_app = "VMSayName";
941

    
   
941

   
942
static AST_LIST_HEAD_STATIC(users, ast_vm_user);
942
static AST_LIST_HEAD_STATIC(users, ast_vm_user);
943
static AST_LIST_HEAD_STATIC(zones, vm_zone);
943
static AST_LIST_HEAD_STATIC(zones, vm_zone);
944
static char zonetag[80];
944
static char zonetag[80];
945
static char locale[20];
945
static char locale[20];
946
static int maxsilence;
946
static int maxsilence;
947
static int maxmsg;
947
static int maxmsg;
948
static int maxdeletedmsg;
948
static int maxdeletedmsg;
949
static int silencethreshold = 128;
949
static int silencethreshold = 128;
950
static char serveremail[80];
950
static char serveremail[80];
951
static char mailcmd[160];	/* Configurable mail cmd */
951
static char mailcmd[160];	/* Configurable mail cmd */
952
static char externnotify[160]; 
952
static char externnotify[160]; 
953
static struct ast_smdi_interface *smdi_iface = NULL;
953
static struct ast_smdi_interface *smdi_iface = NULL;
954
static char vmfmts[80];
954
static char vmfmts[80];
955
static double volgain;
955
static double volgain;
956
static int vmminsecs;
956
static int vmminsecs;
957
static int vmmaxsecs;
957
static int vmmaxsecs;
958
static int maxgreet;
958
static int maxgreet;
959
static int skipms;
959
static int skipms;
960
static int maxlogins;
960
static int maxlogins;
961
static int minpassword;
961
static int minpassword;
962
static int passwordlocation;
962
static int passwordlocation;
963

    
   
963

   
964
/*! Poll mailboxes for changes since there is something external to
964
/*! Poll mailboxes for changes since there is something external to
965
 *  app_voicemail that may change them. */
965
 *  app_voicemail that may change them. */
966
static unsigned int poll_mailboxes;
966
static unsigned int poll_mailboxes;
967

    
   
967

   
968
/*! Polling frequency */
968
/*! Polling frequency */
969
static unsigned int poll_freq;
969
static unsigned int poll_freq;
970
/*! By default, poll every 30 seconds */
970
/*! By default, poll every 30 seconds */
971
#define DEFAULT_POLL_FREQ 30
971
#define DEFAULT_POLL_FREQ 30
972

    
   
972

   
973
AST_MUTEX_DEFINE_STATIC(poll_lock);
973
AST_MUTEX_DEFINE_STATIC(poll_lock);
974
static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
974
static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
975
static pthread_t poll_thread = AST_PTHREADT_NULL;
975
static pthread_t poll_thread = AST_PTHREADT_NULL;
976
static unsigned char poll_thread_run;
976
static unsigned char poll_thread_run;
977

    
   
977

   
978
/*! Subscription to MWI event subscription changes */
978
/*! Subscription to MWI event subscription changes */
979
static struct stasis_subscription *mwi_sub_sub;
979
static struct stasis_subscription *mwi_sub_sub;
980

    
   
980

   
981
/*!
981
/*!
982
 * \brief An MWI subscription
982
 * \brief An MWI subscription
983
 *
983
 *
984
 * This is so we can keep track of which mailboxes are subscribed to.
984
 * This is so we can keep track of which mailboxes are subscribed to.
985
 * This way, we know which mailboxes to poll when the pollmailboxes
985
 * This way, we know which mailboxes to poll when the pollmailboxes
986
 * option is being used.
986
 * option is being used.
987
 */
987
 */
988
struct mwi_sub {
988
struct mwi_sub {
989
	AST_RWLIST_ENTRY(mwi_sub) entry;
989
	AST_RWLIST_ENTRY(mwi_sub) entry;
990
	int old_urgent;
990
	int old_urgent;
991
	int old_new;
991
	int old_new;
992
	int old_old;
992
	int old_old;
993
	char *uniqueid;
993
	char *uniqueid;
994
	char mailbox[1];
994
	char mailbox[1];
995
};
995
};
996

    
   
996

   
997
struct mwi_sub_task {
997
struct mwi_sub_task {
998
	const char *mailbox;
998
	const char *mailbox;
999
	const char *context;
999
	const char *context;
1000
	const char *uniqueid;
1000
	const char *uniqueid;
1001
};
1001
};
1002

    
   
1002

   
1003
static void mwi_sub_task_dtor(struct mwi_sub_task *mwist)
1003
static void mwi_sub_task_dtor(struct mwi_sub_task *mwist)
1004
{
1004
{
1005
	ast_free((void *) mwist->mailbox);
1005
	ast_free((void *) mwist->mailbox);
1006
	ast_free((void *) mwist->context);
1006
	ast_free((void *) mwist->context);
1007
	ast_free((void *) mwist->uniqueid);
1007
	ast_free((void *) mwist->uniqueid);
1008
	ast_free(mwist);
1008
	ast_free(mwist);
1009
}
1009
}
1010

    
   
1010

   
1011
static struct ast_taskprocessor *mwi_subscription_tps;
1011
static struct ast_taskprocessor *mwi_subscription_tps;
1012

    
   
1012

   
1013
static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
1013
static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
1014

    
   
1014

   
1015
/* custom audio control prompts for voicemail playback */
1015
/* custom audio control prompts for voicemail playback */
1016
static char listen_control_forward_key[12];
1016
static char listen_control_forward_key[12];
1017
static char listen_control_reverse_key[12];
1017
static char listen_control_reverse_key[12];
1018
static char listen_control_pause_key[12];
1018
static char listen_control_pause_key[12];
1019
static char listen_control_restart_key[12];
1019
static char listen_control_restart_key[12];
1020
static char listen_control_stop_key[12];
1020
static char listen_control_stop_key[12];
1021

    
   
1021

   
1022
/* custom password sounds */
1022
/* custom password sounds */
1023
static char vm_password[80] = "vm-password";
1023
static char vm_password[80] = "vm-password";
1024
static char vm_newpassword[80] = "vm-newpassword";
1024
static char vm_newpassword[80] = "vm-newpassword";
1025
static char vm_passchanged[80] = "vm-passchanged";
1025
static char vm_passchanged[80] = "vm-passchanged";
1026
static char vm_reenterpassword[80] = "vm-reenterpassword";
1026
static char vm_reenterpassword[80] = "vm-reenterpassword";
1027
static char vm_mismatch[80] = "vm-mismatch";
1027
static char vm_mismatch[80] = "vm-mismatch";
1028
static char vm_invalid_password[80] = "vm-invalid-password";
1028
static char vm_invalid_password[80] = "vm-invalid-password";
1029
static char vm_pls_try_again[80] = "vm-pls-try-again";
1029
static char vm_pls_try_again[80] = "vm-pls-try-again";
1030

    
   
1030

   
1031
/*
1031
/*
1032
 * XXX If we have the time, motivation, etc. to fix up this prompt, one of the following would be appropriate:
1032
 * XXX If we have the time, motivation, etc. to fix up this prompt, one of the following would be appropriate:
1033
 * 1. create a sound along the lines of "Please try again.  When done, press the pound key" which could be spliced
1033
 * 1. create a sound along the lines of "Please try again.  When done, press the pound key" which could be spliced
1034
 * from existing sound clips.  This would require some programming changes in the area of vm_forward options and also
1034
 * from existing sound clips.  This would require some programming changes in the area of vm_forward options and also
1035
 * app.c's __ast_play_and_record function
1035
 * app.c's __ast_play_and_record function
1036
 * 2. create a sound prompt saying "Please try again.  When done recording, press any key to stop and send the prepended
1036
 * 2. create a sound prompt saying "Please try again.  When done recording, press any key to stop and send the prepended
1037
 * message."  At the time of this comment, I think this would require new voice work to be commissioned.
1037
 * message."  At the time of this comment, I think this would require new voice work to be commissioned.
1038
 * 3. Something way different like providing instructions before a time out or a post-recording menu.  This would require
1038
 * 3. Something way different like providing instructions before a time out or a post-recording menu.  This would require
1039
 * more effort than either of the other two.
1039
 * more effort than either of the other two.
1040
 */
1040
 */
1041
static char vm_prepend_timeout[80] = "vm-then-pound";
1041
static char vm_prepend_timeout[80] = "vm-then-pound";
1042

    
   
1042

   
1043
static struct ast_flags globalflags = {0};
1043
static struct ast_flags globalflags = {0};
1044

    
   
1044

   
1045
static int saydurationminfo;
1045
static int saydurationminfo;
1046

    
   
1046

   
1047
static char dialcontext[AST_MAX_CONTEXT] = "";
1047
static char dialcontext[AST_MAX_CONTEXT] = "";
1048
static char callcontext[AST_MAX_CONTEXT] = "";
1048
static char callcontext[AST_MAX_CONTEXT] = "";
1049
static char exitcontext[AST_MAX_CONTEXT] = "";
1049
static char exitcontext[AST_MAX_CONTEXT] = "";
1050

    
   
1050

   
1051
static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
1051
static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
1052

    
   
1052

   
1053

    
   
1053

   
1054
static char *emailbody = NULL;
1054
static char *emailbody = NULL;
1055
static char *emailsubject = NULL;
1055
static char *emailsubject = NULL;
1056
static char *pagerbody = NULL;
1056
static char *pagerbody = NULL;
1057
static char *pagersubject = NULL;
1057
static char *pagersubject = NULL;
1058
static char fromstring[100];
1058
static char fromstring[100];
1059
static char pagerfromstring[100];
1059
static char pagerfromstring[100];
1060
static char charset[32] = "ISO-8859-1";
1060
static char charset[32] = "ISO-8859-1";
1061

    
   
1061

   
1062
static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
1062
static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
1063
static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
1063
static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
1064
static int adsiver = 1;
1064
static int adsiver = 1;
1065
static char emaildateformat[32] = "%A, %B %d, %Y at %r";
1065
static char emaildateformat[32] = "%A, %B %d, %Y at %r";
1066
static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
1066
static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
1067

    
   
1067

   
1068
/* Forward declarations - generic */
1068
/* Forward declarations - generic */
1069
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
1069
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
1070
static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu);
1070
static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu);
1071
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);
1071
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);
1072
static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
1072
static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
1073
static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
1073
static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
1074
			char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
1074
			char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
1075
			signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id);
1075
			signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id);
1076
static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
1076
static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
1077
static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
1077
static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
1078
static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
1078
static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
1079
static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag, const char *msg_id);
1079
static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag, const char *msg_id);
1080
static void apply_options(struct ast_vm_user *vmu, const char *options);
1080
static void apply_options(struct ast_vm_user *vmu, const char *options);
1081
static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
1081
static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
1082
static int is_valid_dtmf(const char *key);
1082
static int is_valid_dtmf(const char *key);
1083
static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
1083
static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
1084
static int write_password_to_file(const char *secretfn, const char *password);
1084
static int write_password_to_file(const char *secretfn, const char *password);
1085
static const char *substitute_escapes(const char *value);
1085
static const char *substitute_escapes(const char *value);
1086
static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu);
1086
static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu);
1087
/*!
1087
/*!
1088
 * Place a message in the indicated folder
1088
 * Place a message in the indicated folder
1089
 *
1089
 *
1090
 * \param vmu Voicemail user
1090
 * \param vmu Voicemail user
1091
 * \param vms Current voicemail state for the user
1091
 * \param vms Current voicemail state for the user
1092
 * \param msg The message number to save
1092
 * \param msg The message number to save
1093
 * \param box The folder into which the message should be saved
1093
 * \param box The folder into which the message should be saved
1094
 * \param[out] newmsg The new message number of the saved message
1094
 * \param[out] newmsg The new message number of the saved message
1095
 * \param move Tells whether to copy or to move the message
1095
 * \param move Tells whether to copy or to move the message
1096
 *
1096
 *
1097
 * \note the "move" parameter is only honored for IMAP voicemail presently
1097
 * \note the "move" parameter is only honored for IMAP voicemail presently
1098
 * \retval 0 Success
1098
 * \retval 0 Success
1099
 * \retval other Failure
1099
 * \retval other Failure
1100
 */
1100
 */
1101
static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move);
1101
static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move);
1102

    
   
1102

   
1103
static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD);
1103
static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD);
1104
static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot);
1104
static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot);
1105

    
   
1105

   
1106
static int vm_msg_forward(const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old);
1106
static int vm_msg_forward(const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old);
1107
static int vm_msg_move(const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder);
1107
static int vm_msg_move(const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder);
1108
static int vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[]);
1108
static int vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[]);
1109
static int vm_msg_play(struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb);
1109
static int vm_msg_play(struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb);
1110

    
   
1110

   
1111
#ifdef TEST_FRAMEWORK
1111
#ifdef TEST_FRAMEWORK
1112
static int vm_test_destroy_user(const char *context, const char *mailbox);
1112
static int vm_test_destroy_user(const char *context, const char *mailbox);
1113
static int vm_test_create_user(const char *context, const char *mailbox);
1113
static int vm_test_create_user(const char *context, const char *mailbox);
1114
#endif
1114
#endif
1115

    
   
1115

   
1116
/*!
1116
/*!
1117
 * \internal
1117
 * \internal
1118
 * \brief Parse the given mailbox_id into mailbox and context.
1118
 * \brief Parse the given mailbox_id into mailbox and context.
1119
 * \since 12.0.0
1119
 * \since 12.0.0
1120
 *
1120
 *
1121
 * \param mailbox_id The mailbox@context string to separate.
1121
 * \param mailbox_id The mailbox@context string to separate.
1122
 * \param mailbox Where the mailbox part will start.
1122
 * \param mailbox Where the mailbox part will start.
1123
 * \param context Where the context part will start.  ("default" if not present)
1123
 * \param context Where the context part will start.  ("default" if not present)
1124
 *
1124
 *
1125
 * \retval 0 on success.
1125
 * \retval 0 on success.
1126
 * \retval -1 on error.
1126
 * \retval -1 on error.
1127
 */
1127
 */
1128
static int separate_mailbox(char *mailbox_id, char **mailbox, char **context)
1128
static int separate_mailbox(char *mailbox_id, char **mailbox, char **context)
1129
{
1129
{
1130
	if (ast_strlen_zero(mailbox_id) || !mailbox || !context) {
1130
	if (ast_strlen_zero(mailbox_id) || !mailbox || !context) {
1131
		return -1;
1131
		return -1;
1132
	}
1132
	}
1133
	*context = mailbox_id;
1133
	*context = mailbox_id;
1134
	*mailbox = strsep(context, "@");
1134
	*mailbox = strsep(context, "@");
1135
	if (ast_strlen_zero(*mailbox)) {
1135
	if (ast_strlen_zero(*mailbox)) {
1136
		return -1;
1136
		return -1;
1137
	}
1137
	}
1138
	if (ast_strlen_zero(*context)) {
1138
	if (ast_strlen_zero(*context)) {
1139
		*context = "default";
1139
		*context = "default";
1140
	}
1140
	}
1141
	return 0;
1141
	return 0;
1142
}
1142
}
1143

    
   
1143

   
1144
struct ao2_container *inprocess_container;
1144
struct ao2_container *inprocess_container;
1145

    
   
1145

   
1146
struct inprocess {
1146
struct inprocess {
1147
	int count;
1147
	int count;
1148
	char *context;
1148
	char *context;
1149
	char mailbox[0];
1149
	char mailbox[0];
1150
};
1150
};
1151

    
   
1151

   
1152
static int inprocess_hash_fn(const void *obj, const int flags)
1152
static int inprocess_hash_fn(const void *obj, const int flags)
1153
{
1153
{
1154
	const struct inprocess *i = obj;
1154
	const struct inprocess *i = obj;
1155
	return atoi(i->mailbox);
1155
	return atoi(i->mailbox);
1156
}
1156
}
1157

    
   
1157

   
1158
static int inprocess_cmp_fn(void *obj, void *arg, int flags)
1158
static int inprocess_cmp_fn(void *obj, void *arg, int flags)
1159
{
1159
{
1160
	struct inprocess *i = obj, *j = arg;
1160
	struct inprocess *i = obj, *j = arg;
1161
	if (strcmp(i->mailbox, j->mailbox)) {
1161
	if (strcmp(i->mailbox, j->mailbox)) {
1162
		return 0;
1162
		return 0;
1163
	}
1163
	}
1164
	return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
1164
	return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
1165
}
1165
}
1166

    
   
1166

   
1167
static int inprocess_count(const char *context, const char *mailbox, int delta)
1167
static int inprocess_count(const char *context, const char *mailbox, int delta)
1168
{
1168
{
1169
	struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
1169
	struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
1170
	arg->context = arg->mailbox + strlen(mailbox) + 1;
1170
	arg->context = arg->mailbox + strlen(mailbox) + 1;
1171
	strcpy(arg->mailbox, mailbox); /* SAFE */
1171
	strcpy(arg->mailbox, mailbox); /* SAFE */
1172
	strcpy(arg->context, context); /* SAFE */
1172
	strcpy(arg->context, context); /* SAFE */
1173
	ao2_lock(inprocess_container);
1173
	ao2_lock(inprocess_container);
1174
	if ((i = ao2_find(inprocess_container, arg, 0))) {
1174
	if ((i = ao2_find(inprocess_container, arg, 0))) {
1175
		int ret = ast_atomic_fetchadd_int(&i->count, delta);
1175
		int ret = ast_atomic_fetchadd_int(&i->count, delta);
1176
		ao2_unlock(inprocess_container);
1176
		ao2_unlock(inprocess_container);
1177
		ao2_ref(i, -1);
1177
		ao2_ref(i, -1);
1178
		return ret;
1178
		return ret;
1179
	}
1179
	}
1180
	if (delta < 0) {
1180
	if (delta < 0) {
1181
		ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
1181
		ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
1182
	}
1182
	}
1183
	if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
1183
	if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
1184
		ao2_unlock(inprocess_container);
1184
		ao2_unlock(inprocess_container);
1185
		return 0;
1185
		return 0;
1186
	}
1186
	}
1187
	i->context = i->mailbox + strlen(mailbox) + 1;
1187
	i->context = i->mailbox + strlen(mailbox) + 1;
1188
	strcpy(i->mailbox, mailbox); /* SAFE */
1188
	strcpy(i->mailbox, mailbox); /* SAFE */
1189
	strcpy(i->context, context); /* SAFE */
1189
	strcpy(i->context, context); /* SAFE */
1190
	i->count = delta;
1190
	i->count = delta;
1191
	ao2_link(inprocess_container, i);
1191
	ao2_link(inprocess_container, i);
1192
	ao2_unlock(inprocess_container);
1192
	ao2_unlock(inprocess_container);
1193
	ao2_ref(i, -1);
1193
	ao2_ref(i, -1);
1194
	return 0;
1194
	return 0;
1195
}
1195
}
1196

    
   
1196

   
1197
#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
1197
#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
1198
static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
1198
static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
1199
#endif
1199
#endif
1200

    
   
1200

   
1201
/*!
1201
/*!
1202
 * \brief Strips control and non 7-bit clean characters from input string.
1202
 * \brief Strips control and non 7-bit clean characters from input string.
1203
 *
1203
 *
1204
 * \note To map control and none 7-bit characters to a 7-bit clean characters
1204
 * \note To map control and none 7-bit characters to a 7-bit clean characters
1205
 *  please use ast_str_encode_mine().
1205
 *  please use ast_str_encode_mine().
1206
 */
1206
 */
1207
static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
1207
static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
1208
{
1208
{
1209
	char *bufptr = buf;
1209
	char *bufptr = buf;
1210
	for (; *input; input++) {
1210
	for (; *input; input++) {
1211
		if (*input < 32) {
1211
		if (*input < 32) {
1212
			continue;
1212
			continue;
1213
		}
1213
		}
1214
		*bufptr++ = *input;
1214
		*bufptr++ = *input;
1215
		if (bufptr == buf + buflen - 1) {
1215
		if (bufptr == buf + buflen - 1) {
1216
			break;
1216
			break;
1217
		}
1217
		}
1218
	}
1218
	}
1219
	*bufptr = '\0';
1219
	*bufptr = '\0';
1220
	return buf;
1220
	return buf;
1221
}
1221
}
1222

    
   
1222

   
1223

    
   
1223

   
1224
/*!
1224
/*!
1225
 * \brief Sets default voicemail system options to a voicemail user.
1225
 * \brief Sets default voicemail system options to a voicemail user.
1226
 *
1226
 *
1227
 * This applies select global settings to a newly created (dynamic) instance of a voicemail user.
1227
 * This applies select global settings to a newly created (dynamic) instance of a voicemail user.
1228
 * - all the globalflags
1228
 * - all the globalflags
1229
 * - the saydurationminfo
1229
 * - the saydurationminfo
1230
 * - the callcontext
1230
 * - the callcontext
1231
 * - the dialcontext
1231
 * - the dialcontext
1232
 * - the exitcontext
1232
 * - the exitcontext
1233
 * - vmmaxsecs, vmmaxmsg, maxdeletedmsg
1233
 * - vmmaxsecs, vmmaxmsg, maxdeletedmsg
1234
 * - volume gain.
1234
 * - volume gain.
1235
 * - emailsubject, emailbody set to NULL
1235
 * - emailsubject, emailbody set to NULL
1236
 */
1236
 */
1237
static void populate_defaults(struct ast_vm_user *vmu)
1237
static void populate_defaults(struct ast_vm_user *vmu)
1238
{
1238
{
1239
	ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
1239
	ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
1240
	vmu->passwordlocation = passwordlocation;
1240
	vmu->passwordlocation = passwordlocation;
1241
	if (saydurationminfo) {
1241
	if (saydurationminfo) {
1242
		vmu->saydurationm = saydurationminfo;
1242
		vmu->saydurationm = saydurationminfo;
1243
	}
1243
	}
1244
	ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
1244
	ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
1245
	ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
1245
	ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
1246
	ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
1246
	ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
1247
	ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
1247
	ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
1248
	ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
1248
	ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
1249
	if (vmminsecs) {
1249
	if (vmminsecs) {
1250
		vmu->minsecs = vmminsecs;
1250
		vmu->minsecs = vmminsecs;
1251
	}
1251
	}
1252
	if (vmmaxsecs) {
1252
	if (vmmaxsecs) {
1253
		vmu->maxsecs = vmmaxsecs;
1253
		vmu->maxsecs = vmmaxsecs;
1254
	}
1254
	}
1255
	if (maxmsg) {
1255
	if (maxmsg) {
1256
		vmu->maxmsg = maxmsg;
1256
		vmu->maxmsg = maxmsg;
1257
	}
1257
	}
1258
	if (maxdeletedmsg) {
1258
	if (maxdeletedmsg) {
1259
		vmu->maxdeletedmsg = maxdeletedmsg;
1259
		vmu->maxdeletedmsg = maxdeletedmsg;
1260
	}
1260
	}
1261
	vmu->volgain = volgain;
1261
	vmu->volgain = volgain;
1262
	ast_free(vmu->emailsubject);
1262
	ast_free(vmu->emailsubject);
1263
	vmu->emailsubject = NULL;
1263
	vmu->emailsubject = NULL;
1264
	ast_free(vmu->emailbody);
1264
	ast_free(vmu->emailbody);
1265
	vmu->emailbody = NULL;
1265
	vmu->emailbody = NULL;
1266
#ifdef IMAP_STORAGE
1266
#ifdef IMAP_STORAGE
1267
	ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
1267
	ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
1268
	ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
1268
	ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
1269
	ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
1269
	ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
1270
	ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
1270
	ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
1271
#endif
1271
#endif
1272
}
1272
}
1273

    
   
1273

   
1274
/*!
1274
/*!
1275
 * \brief Sets a a specific property value.
1275
 * \brief Sets a a specific property value.
1276
 * \param vmu The voicemail user object to work with.
1276
 * \param vmu The voicemail user object to work with.
1277
 * \param var The name of the property to be set.
1277
 * \param var The name of the property to be set.
1278
 * \param value The value to be set to the property.
1278
 * \param value The value to be set to the property.
1279
 * 
1279
 * 
1280
 * The property name must be one of the understood properties. See the source for details.
1280
 * The property name must be one of the understood properties. See the source for details.
1281
 */
1281
 */
1282
static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
1282
static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
1283
{
1283
{
1284
	int x;
1284
	int x;
1285
	if (!strcasecmp(var, "attach")) {
1285
	if (!strcasecmp(var, "attach")) {
1286
		ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
1286
		ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
1287
	} else if (!strcasecmp(var, "attachfmt")) {
1287
	} else if (!strcasecmp(var, "attachfmt")) {
1288
		ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
1288
		ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
1289
	} else if (!strcasecmp(var, "serveremail")) {
1289
	} else if (!strcasecmp(var, "serveremail")) {
1290
		ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
1290
		ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
1291
	} else if (!strcasecmp(var, "emailbody")) {
1291
	} else if (!strcasecmp(var, "emailbody")) {
1292
		ast_free(vmu->emailbody);
1292
		ast_free(vmu->emailbody);
1293
		vmu->emailbody = ast_strdup(substitute_escapes(value));
1293
		vmu->emailbody = ast_strdup(substitute_escapes(value));
1294
	} else if (!strcasecmp(var, "emailsubject")) {
1294
	} else if (!strcasecmp(var, "emailsubject")) {
1295
		ast_free(vmu->emailsubject);
1295
		ast_free(vmu->emailsubject);
1296
		vmu->emailsubject = ast_strdup(substitute_escapes(value));
1296
		vmu->emailsubject = ast_strdup(substitute_escapes(value));
1297
	} else if (!strcasecmp(var, "language")) {
1297
	} else if (!strcasecmp(var, "language")) {
1298
		ast_copy_string(vmu->language, value, sizeof(vmu->language));
1298
		ast_copy_string(vmu->language, value, sizeof(vmu->language));
1299
	} else if (!strcasecmp(var, "tz")) {
1299
	} else if (!strcasecmp(var, "tz")) {
1300
		ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
1300
		ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
1301
	} else if (!strcasecmp(var, "locale")) {
1301
	} else if (!strcasecmp(var, "locale")) {
1302
		ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
1302
		ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
1303
#ifdef IMAP_STORAGE
1303
#ifdef IMAP_STORAGE
1304
	} else if (!strcasecmp(var, "imapuser")) {
1304
	} else if (!strcasecmp(var, "imapuser")) {
1305
		ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
1305
		ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
1306
		vmu->imapversion = imapversion;
1306
		vmu->imapversion = imapversion;
1307
	} else if (!strcasecmp(var, "imapserver")) {
1307
	} else if (!strcasecmp(var, "imapserver")) {
1308
		ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
1308
		ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
1309
		vmu->imapversion = imapversion;
1309
		vmu->imapversion = imapversion;
1310
	} else if (!strcasecmp(var, "imapport")) {
1310
	} else if (!strcasecmp(var, "imapport")) {
1311
		ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
1311
		ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
1312
		vmu->imapversion = imapversion;
1312
		vmu->imapversion = imapversion;
1313
	} else if (!strcasecmp(var, "imapflags")) {
1313
	} else if (!strcasecmp(var, "imapflags")) {
1314
		ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
1314
		ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
1315
		vmu->imapversion = imapversion;
1315
		vmu->imapversion = imapversion;
1316
	} else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
1316
	} else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
1317
		ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
1317
		ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
1318
		vmu->imapversion = imapversion;
1318
		vmu->imapversion = imapversion;
1319
	} else if (!strcasecmp(var, "imapfolder")) {
1319
	} else if (!strcasecmp(var, "imapfolder")) {
1320
		ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
1320
		ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
1321
		vmu->imapversion = imapversion;
1321
		vmu->imapversion = imapversion;
1322
	} else if (!strcasecmp(var, "imapvmshareid")) {
1322
	} else if (!strcasecmp(var, "imapvmshareid")) {
1323
		ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
1323
		ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
1324
		vmu->imapversion = imapversion;
1324
		vmu->imapversion = imapversion;
1325
#endif
1325
#endif
1326
	} else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
1326
	} else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
1327
		ast_set2_flag(vmu, ast_true(value), VM_DELETE);	
1327
		ast_set2_flag(vmu, ast_true(value), VM_DELETE);	
1328
	} else if (!strcasecmp(var, "saycid")){
1328
	} else if (!strcasecmp(var, "saycid")){
1329
		ast_set2_flag(vmu, ast_true(value), VM_SAYCID);	
1329
		ast_set2_flag(vmu, ast_true(value), VM_SAYCID);	
1330
	} else if (!strcasecmp(var, "sendvoicemail")){
1330
	} else if (!strcasecmp(var, "sendvoicemail")){
1331
		ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);	
1331
		ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);	
1332
	} else if (!strcasecmp(var, "review")){
1332
	} else if (!strcasecmp(var, "review")){
1333
		ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
1333
		ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
1334
	} else if (!strcasecmp(var, "tempgreetwarn")){
1334
	} else if (!strcasecmp(var, "tempgreetwarn")){
1335
		ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);	
1335
		ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);	
1336
	} else if (!strcasecmp(var, "messagewrap")){
1336
	} else if (!strcasecmp(var, "messagewrap")){
1337
		ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);	
1337
		ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);	
1338
	} else if (!strcasecmp(var, "operator")) {
1338
	} else if (!strcasecmp(var, "operator")) {
1339
		ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);	
1339
		ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);	
1340
	} else if (!strcasecmp(var, "envelope")){
1340
	} else if (!strcasecmp(var, "envelope")){
1341
		ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);	
1341
		ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);	
1342
	} else if (!strcasecmp(var, "moveheard")){
1342
	} else if (!strcasecmp(var, "moveheard")){
1343
		ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
1343
		ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
1344
	} else if (!strcasecmp(var, "sayduration")){
1344
	} else if (!strcasecmp(var, "sayduration")){
1345
		ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);	
1345
		ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);	
1346
	} else if (!strcasecmp(var, "saydurationm")){
1346
	} else if (!strcasecmp(var, "saydurationm")){
1347
		if (sscanf(value, "%30d", &x) == 1) {
1347
		if (sscanf(value, "%30d", &x) == 1) {
1348
			vmu->saydurationm = x;
1348
			vmu->saydurationm = x;
1349
		} else {
1349
		} else {
1350
			ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
1350
			ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
1351
		}
1351
		}
1352
	} else if (!strcasecmp(var, "forcename")){
1352
	} else if (!strcasecmp(var, "forcename")){
1353
		ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);	
1353
		ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);	
1354
	} else if (!strcasecmp(var, "forcegreetings")){
1354
	} else if (!strcasecmp(var, "forcegreetings")){
1355
		ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);	
1355
		ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);	
1356
	} else if (!strcasecmp(var, "callback")) {
1356
	} else if (!strcasecmp(var, "callback")) {
1357
		ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
1357
		ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
1358
	} else if (!strcasecmp(var, "dialout")) {
1358
	} else if (!strcasecmp(var, "dialout")) {
1359
		ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
1359
		ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
1360
	} else if (!strcasecmp(var, "exitcontext")) {
1360
	} else if (!strcasecmp(var, "exitcontext")) {
1361
		ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
1361
		ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
1362
	} else if (!strcasecmp(var, "minsecs")) {
1362
	} else if (!strcasecmp(var, "minsecs")) {
1363
		if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
1363
		if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
1364
			vmu->minsecs = x;
1364
			vmu->minsecs = x;
1365
		} else {
1365
		} else {
1366
			ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1366
			ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1367
			vmu->minsecs = vmminsecs;
1367
			vmu->minsecs = vmminsecs;
1368
		}
1368
		}
1369
	} else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
1369
	} else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
1370
		vmu->maxsecs = atoi(value);
1370
		vmu->maxsecs = atoi(value);
1371
		if (vmu->maxsecs <= 0) {
1371
		if (vmu->maxsecs <= 0) {
1372
			ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
1372
			ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
1373
			vmu->maxsecs = vmmaxsecs;
1373
			vmu->maxsecs = vmmaxsecs;
1374
		} else {
1374
		} else {
1375
			vmu->maxsecs = atoi(value);
1375
			vmu->maxsecs = atoi(value);
1376
		}
1376
		}
1377
		if (!strcasecmp(var, "maxmessage"))
1377
		if (!strcasecmp(var, "maxmessage"))
1378
			ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'.  Please make that change in your voicemail config.\n");
1378
			ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'.  Please make that change in your voicemail config.\n");
1379
	} else if (!strcasecmp(var, "maxmsg")) {
1379
	} else if (!strcasecmp(var, "maxmsg")) {
1380
		vmu->maxmsg = atoi(value);
1380
		vmu->maxmsg = atoi(value);
1381
		/* Accept maxmsg=0 (Greetings only voicemail) */
1381
		/* Accept maxmsg=0 (Greetings only voicemail) */
1382
		if (vmu->maxmsg < 0) {
1382
		if (vmu->maxmsg < 0) {
1383
			ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
1383
			ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
1384
			vmu->maxmsg = MAXMSG;
1384
			vmu->maxmsg = MAXMSG;
1385
		} else if (vmu->maxmsg > MAXMSGLIMIT) {
1385
		} else if (vmu->maxmsg > MAXMSGLIMIT) {
1386
			ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
1386
			ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
1387
			vmu->maxmsg = MAXMSGLIMIT;
1387
			vmu->maxmsg = MAXMSGLIMIT;
1388
		}
1388
		}
1389
	} else if (!strcasecmp(var, "nextaftercmd")) {
1389
	} else if (!strcasecmp(var, "nextaftercmd")) {
1390
		ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
1390
		ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
1391
	} else if (!strcasecmp(var, "backupdeleted")) {
1391
	} else if (!strcasecmp(var, "backupdeleted")) {
1392
		if (sscanf(value, "%30d", &x) == 1)
1392
		if (sscanf(value, "%30d", &x) == 1)
1393
			vmu->maxdeletedmsg = x;
1393
			vmu->maxdeletedmsg = x;
1394
		else if (ast_true(value))
1394
		else if (ast_true(value))
1395
			vmu->maxdeletedmsg = MAXMSG;
1395
			vmu->maxdeletedmsg = MAXMSG;
1396
		else
1396
		else
1397
			vmu->maxdeletedmsg = 0;
1397
			vmu->maxdeletedmsg = 0;
1398

    
   
1398

   
1399
		if (vmu->maxdeletedmsg < 0) {
1399
		if (vmu->maxdeletedmsg < 0) {
1400
			ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
1400
			ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
1401
			vmu->maxdeletedmsg = MAXMSG;
1401
			vmu->maxdeletedmsg = MAXMSG;
1402
		} else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
1402
		} else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
1403
			ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
1403
			ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
1404
			vmu->maxdeletedmsg = MAXMSGLIMIT;
1404
			vmu->maxdeletedmsg = MAXMSGLIMIT;
1405
		}
1405
		}
1406
	} else if (!strcasecmp(var, "volgain")) {
1406
	} else if (!strcasecmp(var, "volgain")) {
1407
		sscanf(value, "%30lf", &vmu->volgain);
1407
		sscanf(value, "%30lf", &vmu->volgain);
1408
	} else if (!strcasecmp(var, "passwordlocation")) {
1408
	} else if (!strcasecmp(var, "passwordlocation")) {
1409
		if (!strcasecmp(value, "spooldir")) {
1409
		if (!strcasecmp(value, "spooldir")) {
1410
			vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
1410
			vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
1411
		} else {
1411
		} else {
1412
			vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
1412
			vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
1413
		}
1413
		}
1414
	} else if (!strcasecmp(var, "options")) {
1414
	} else if (!strcasecmp(var, "options")) {
1415
		apply_options(vmu, value);
1415
		apply_options(vmu, value);
1416
	}
1416
	}
1417
}
1417
}
1418

    
   
1418

   
1419
static char *vm_check_password_shell(char *command, char *buf, size_t len) 
1419
static char *vm_check_password_shell(char *command, char *buf, size_t len) 
1420
{
1420
{
1421
	int fds[2], pid = 0;
1421
	int fds[2], pid = 0;
1422

    
   
1422

   
1423
	memset(buf, 0, len);
1423
	memset(buf, 0, len);
1424

    
   
1424

   
1425
	if (pipe(fds)) {
1425
	if (pipe(fds)) {
1426
		snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
1426
		snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
1427
	} else {
1427
	} else {
1428
		/* good to go*/
1428
		/* good to go*/
1429
		pid = ast_safe_fork(0);
1429
		pid = ast_safe_fork(0);
1430

    
   
1430

   
1431
		if (pid < 0) {
1431
		if (pid < 0) {
1432
			/* ok maybe not */
1432
			/* ok maybe not */
1433
			close(fds[0]);
1433
			close(fds[0]);
1434
			close(fds[1]);
1434
			close(fds[1]);
1435
			snprintf(buf, len, "FAILURE: Fork failed");
1435
			snprintf(buf, len, "FAILURE: Fork failed");
1436
		} else if (pid) {
1436
		} else if (pid) {
1437
			/* parent */
1437
			/* parent */
1438
			close(fds[1]);
1438
			close(fds[1]);
1439
			if (read(fds[0], buf, len) < 0) {
1439
			if (read(fds[0], buf, len) < 0) {
1440
				ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
1440
				ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
1441
			}
1441
			}
1442
			close(fds[0]);
1442
			close(fds[0]);
1443
		} else {
1443
		} else {
1444
			/*  child */
1444
			/*  child */
1445
			AST_DECLARE_APP_ARGS(arg,
1445
			AST_DECLARE_APP_ARGS(arg,
1446
				AST_APP_ARG(v)[20];
1446
				AST_APP_ARG(v)[20];
1447
			);
1447
			);
1448
			char *mycmd = ast_strdupa(command);
1448
			char *mycmd = ast_strdupa(command);
1449

    
   
1449

   
1450
			close(fds[0]);
1450
			close(fds[0]);
1451
			dup2(fds[1], STDOUT_FILENO);
1451
			dup2(fds[1], STDOUT_FILENO);
1452
			close(fds[1]);
1452
			close(fds[1]);
1453
			ast_close_fds_above_n(STDOUT_FILENO);
1453
			ast_close_fds_above_n(STDOUT_FILENO);
1454

    
   
1454

   
1455
			AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
1455
			AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
1456

    
   
1456

   
1457
			execv(arg.v[0], arg.v); 
1457
			execv(arg.v[0], arg.v); 
1458
			printf("FAILURE: %s", strerror(errno));
1458
			printf("FAILURE: %s", strerror(errno));
1459
			_exit(0);
1459
			_exit(0);
1460
		}
1460
		}
1461
	}
1461
	}
1462
	return buf;
1462
	return buf;
1463
}
1463
}
1464

    
   
1464

   
1465
/*!
1465
/*!
1466
 * \brief Check that password meets minimum required length
1466
 * \brief Check that password meets minimum required length
1467
 * \param vmu The voicemail user to change the password for.
1467
 * \param vmu The voicemail user to change the password for.
1468
 * \param password The password string to check
1468
 * \param password The password string to check
1469
 *
1469
 *
1470
 * \return zero on ok, 1 on not ok.
1470
 * \return zero on ok, 1 on not ok.
1471
 */
1471
 */
1472
static int check_password(struct ast_vm_user *vmu, char *password)
1472
static int check_password(struct ast_vm_user *vmu, char *password)
1473
{
1473
{
1474
	/* check minimum length */
1474
	/* check minimum length */
1475
	if (strlen(password) < minpassword)
1475
	if (strlen(password) < minpassword)
1476
		return 1;
1476
		return 1;
1477
	/* check that password does not contain '*' character */
1477
	/* check that password does not contain '*' character */
1478
	if (!ast_strlen_zero(password) && password[0] == '*')
1478
	if (!ast_strlen_zero(password) && password[0] == '*')
1479
		return 1;
1479
		return 1;
1480
	if (!ast_strlen_zero(ext_pass_check_cmd)) {
1480
	if (!ast_strlen_zero(ext_pass_check_cmd)) {
1481
		char cmd[255], buf[255];
1481
		char cmd[255], buf[255];
1482

    
   
1482

   
1483
		ast_debug(1, "Verify password policies for %s\n", password);
1483
		ast_debug(1, "Verify password policies for %s\n", password);
1484

    
   
1484

   
1485
		snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
1485
		snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
1486
		if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
1486
		if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
1487
			ast_debug(5, "Result: %s\n", buf);
1487
			ast_debug(5, "Result: %s\n", buf);
1488
			if (!strncasecmp(buf, "VALID", 5)) {
1488
			if (!strncasecmp(buf, "VALID", 5)) {
1489
				ast_debug(3, "Passed password check: '%s'\n", buf);
1489
				ast_debug(3, "Passed password check: '%s'\n", buf);
1490
				return 0;
1490
				return 0;
1491
			} else if (!strncasecmp(buf, "FAILURE", 7)) {
1491
			} else if (!strncasecmp(buf, "FAILURE", 7)) {
1492
				ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
1492
				ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
1493
				return 0;
1493
				return 0;
1494
			} else {
1494
			} else {
1495
				ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
1495
				ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
1496
				return 1;
1496
				return 1;
1497
			}
1497
			}
1498
		}
1498
		}
1499
	}
1499
	}
1500
	return 0;
1500
	return 0;
1501
}
1501
}
1502

    
   
1502

   
1503
/*! 
1503
/*! 
1504
 * \brief Performs a change of the voicemail passowrd in the realtime engine.
1504
 * \brief Performs a change of the voicemail passowrd in the realtime engine.
1505
 * \param vmu The voicemail user to change the password for.
1505
 * \param vmu The voicemail user to change the password for.
1506
 * \param password The new value to be set to the password for this user.
1506
 * \param password The new value to be set to the password for this user.
1507
 * 
1507
 * 
1508
 * This only works if there is a realtime engine configured.
1508
 * This only works if there is a realtime engine configured.
1509
 * This is called from the (top level) vm_change_password.
1509
 * This is called from the (top level) vm_change_password.
1510
 *
1510
 *
1511
 * \return zero on success, -1 on error.
1511
 * \return zero on success, -1 on error.
1512
 */
1512
 */
1513
static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
1513
static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
1514
{
1514
{
1515
	int res = -1;
1515
	int res = -1;
1516
	if (!strcmp(vmu->password, password)) {
1516
	if (!strcmp(vmu->password, password)) {
1517
		/* No change (but an update would return 0 rows updated, so we opt out here) */
1517
		/* No change (but an update would return 0 rows updated, so we opt out here) */
1518
		return 0;
1518
		return 0;
1519
	}
1519
	}
1520

    
   
1520

   
1521
	if (strlen(password) > 10) {
1521
	if (strlen(password) > 10) {
1522
		ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
1522
		ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
1523
	}
1523
	}
1524
	if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
1524
	if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
1525
		ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
1525
		ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
1526
		ast_copy_string(vmu->password, password, sizeof(vmu->password));
1526
		ast_copy_string(vmu->password, password, sizeof(vmu->password));
1527
		res = 0;
1527
		res = 0;
1528
	}
1528
	}
1529
	return res;
1529
	return res;
1530
}
1530
}
1531

    
   
1531

   
1532
/*!
1532
/*!
1533
 * \brief Destructively Parse options and apply.
1533
 * \brief Destructively Parse options and apply.
1534
 */
1534
 */
1535
static void apply_options(struct ast_vm_user *vmu, const char *options)
1535
static void apply_options(struct ast_vm_user *vmu, const char *options)
1536
{	
1536
{	
1537
	char *stringp;
1537
	char *stringp;
1538
	char *s;
1538
	char *s;
1539
	char *var, *value;
1539
	char *var, *value;
1540
	stringp = ast_strdupa(options);
1540
	stringp = ast_strdupa(options);
1541
	while ((s = strsep(&stringp, "|"))) {
1541
	while ((s = strsep(&stringp, "|"))) {
1542
		value = s;
1542
		value = s;
1543
		if ((var = strsep(&value, "=")) && value) {
1543
		if ((var = strsep(&value, "=")) && value) {
1544
			apply_option(vmu, var, value);
1544
			apply_option(vmu, var, value);
1545
		}
1545
		}
1546
	}	
1546
	}	
1547
}
1547
}
1548

    
   
1548

   
1549
/*!
1549
/*!
1550
 * \brief Loads the options specific to a voicemail user.
1550
 * \brief Loads the options specific to a voicemail user.
1551
 * 
1551
 * 
1552
 * This is called when a vm_user structure is being set up, such as from load_options.
1552
 * This is called when a vm_user structure is being set up, such as from load_options.
1553
 */
1553
 */
1554
static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
1554
static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
1555
{
1555
{
1556
	for (; var; var = var->next) {
1556
	for (; var; var = var->next) {
1557
		if (!strcasecmp(var->name, "vmsecret")) {
1557
		if (!strcasecmp(var->name, "vmsecret")) {
1558
			ast_copy_string(retval->password, var->value, sizeof(retval->password));
1558
			ast_copy_string(retval->password, var->value, sizeof(retval->password));
1559
		} else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */
1559
		} else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */
1560
			if (ast_strlen_zero(retval->password)) {
1560
			if (ast_strlen_zero(retval->password)) {
1561
				if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
1561
				if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
1562
					ast_log(LOG_WARNING, "Invalid password detected for mailbox %s.  The password"
1562
					ast_log(LOG_WARNING, "Invalid password detected for mailbox %s.  The password"
1563
						"\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
1563
						"\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
1564
				} else {
1564
				} else {
1565
					ast_copy_string(retval->password, var->value, sizeof(retval->password));
1565
					ast_copy_string(retval->password, var->value, sizeof(retval->password));
1566
				}
1566
				}
1567
			}
1567
			}
1568
		} else if (!strcasecmp(var->name, "uniqueid")) {
1568
		} else if (!strcasecmp(var->name, "uniqueid")) {
1569
			ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
1569
			ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
1570
		} else if (!strcasecmp(var->name, "pager")) {
1570
		} else if (!strcasecmp(var->name, "pager")) {
1571
			ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
1571
			ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
1572
		} else if (!strcasecmp(var->name, "email")) {
1572
		} else if (!strcasecmp(var->name, "email")) {
1573
			ast_copy_string(retval->email, var->value, sizeof(retval->email));
1573
			ast_copy_string(retval->email, var->value, sizeof(retval->email));
1574
		} else if (!strcasecmp(var->name, "fullname")) {
1574
		} else if (!strcasecmp(var->name, "fullname")) {
1575
			ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
1575
			ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
1576
		} else if (!strcasecmp(var->name, "context")) {
1576
		} else if (!strcasecmp(var->name, "context")) {
1577
			ast_copy_string(retval->context, var->value, sizeof(retval->context));
1577
			ast_copy_string(retval->context, var->value, sizeof(retval->context));
1578
		} else if (!strcasecmp(var->name, "emailsubject")) {
1578
		} else if (!strcasecmp(var->name, "emailsubject")) {
1579
			ast_free(retval->emailsubject);
1579
			ast_free(retval->emailsubject);
1580
			retval->emailsubject = ast_strdup(substitute_escapes(var->value));
1580
			retval->emailsubject = ast_strdup(substitute_escapes(var->value));
1581
		} else if (!strcasecmp(var->name, "emailbody")) {
1581
		} else if (!strcasecmp(var->name, "emailbody")) {
1582
			ast_free(retval->emailbody);
1582
			ast_free(retval->emailbody);
1583
			retval->emailbody = ast_strdup(substitute_escapes(var->value));
1583
			retval->emailbody = ast_strdup(substitute_escapes(var->value));
1584
#ifdef IMAP_STORAGE
1584
#ifdef IMAP_STORAGE
1585
		} else if (!strcasecmp(var->name, "imapuser")) {
1585
		} else if (!strcasecmp(var->name, "imapuser")) {
1586
			ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
1586
			ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
1587
			retval->imapversion = imapversion;
1587
			retval->imapversion = imapversion;
1588
		} else if (!strcasecmp(var->name, "imapserver")) {
1588
		} else if (!strcasecmp(var->name, "imapserver")) {
1589
			ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
1589
			ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
1590
			retval->imapversion = imapversion;
1590
			retval->imapversion = imapversion;
1591
		} else if (!strcasecmp(var->name, "imapport")) {
1591
		} else if (!strcasecmp(var->name, "imapport")) {
1592
			ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
1592
			ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
1593
			retval->imapversion = imapversion;
1593
			retval->imapversion = imapversion;
1594
		} else if (!strcasecmp(var->name, "imapflags")) {
1594
		} else if (!strcasecmp(var->name, "imapflags")) {
1595
			ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
1595
			ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
1596
			retval->imapversion = imapversion;
1596
			retval->imapversion = imapversion;
1597
		} else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
1597
		} else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
1598
			ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
1598
			ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
1599
			retval->imapversion = imapversion;
1599
			retval->imapversion = imapversion;
1600
		} else if (!strcasecmp(var->name, "imapfolder")) {
1600
		} else if (!strcasecmp(var->name, "imapfolder")) {
1601
			ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
1601
			ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
1602
			retval->imapversion = imapversion;
1602
			retval->imapversion = imapversion;
1603
		} else if (!strcasecmp(var->name, "imapvmshareid")) {
1603
		} else if (!strcasecmp(var->name, "imapvmshareid")) {
1604
			ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
1604
			ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
1605
			retval->imapversion = imapversion;
1605
			retval->imapversion = imapversion;
1606
#endif
1606
#endif
1607
		} else
1607
		} else
1608
			apply_option(retval, var->name, var->value);
1608
			apply_option(retval, var->name, var->value);
1609
	}
1609
	}
1610
}
1610
}
1611

    
   
1611

   
1612
/*!
1612
/*!
1613
 * \brief Determines if a DTMF key entered is valid.
1613
 * \brief Determines if a DTMF key entered is valid.
1614
 * \param key The character to be compared. expects a single character. Though is capable of handling a string, this is internally copies using ast_strdupa.
1614
 * \param key The character to be compared. expects a single character. Though is capable of handling a string, this is internally copies using ast_strdupa.
1615
 *
1615
 *
1616
 * Tests the character entered against the set of valid DTMF characters. 
1616
 * Tests the character entered against the set of valid DTMF characters. 
1617
 * \return 1 if the character entered is a valid DTMF digit, 0 if the character is invalid.
1617
 * \return 1 if the character entered is a valid DTMF digit, 0 if the character is invalid.
1618
 */
1618
 */
1619
static int is_valid_dtmf(const char *key)
1619
static int is_valid_dtmf(const char *key)
1620
{
1620
{
1621
	int i;
1621
	int i;
1622
	char *local_key = ast_strdupa(key);
1622
	char *local_key = ast_strdupa(key);
1623

    
   
1623

   
1624
	for (i = 0; i < strlen(key); ++i) {
1624
	for (i = 0; i < strlen(key); ++i) {
1625
		if (!strchr(VALID_DTMF, *local_key)) {
1625
		if (!strchr(VALID_DTMF, *local_key)) {
1626
			ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
1626
			ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
1627
			return 0;
1627
			return 0;
1628
		}
1628
		}
1629
		local_key++;
1629
		local_key++;
1630
	}
1630
	}
1631
	return 1;
1631
	return 1;
1632
}
1632
}
1633

    
   
1633

   
1634
/*!
1634
/*!
1635
 * \brief Finds a voicemail user from the realtime engine.
1635
 * \brief Finds a voicemail user from the realtime engine.
1636
 * \param ivm
1636
 * \param ivm
1637
 * \param context
1637
 * \param context
1638
 * \param mailbox
1638
 * \param mailbox
1639
 *
1639
 *
1640
 * This is called as a fall through case when the normal find_user() was not able to find a user. That is, the default it so look in the usual voicemail users file first.
1640
 * This is called as a fall through case when the normal find_user() was not able to find a user. That is, the default it so look in the usual voicemail users file first.
1641
 *
1641
 *
1642
 * \return The ast_vm_user structure for the user that was found.
1642
 * \return The ast_vm_user structure for the user that was found.
1643
 */
1643
 */
1644
static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
1644
static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
1645
{
1645
{
1646
	struct ast_variable *var;
1646
	struct ast_variable *var;
1647
	struct ast_vm_user *retval;
1647
	struct ast_vm_user *retval;
1648

    
   
1648

   
1649
	if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
1649
	if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
1650
		if (ivm) {
1650
		if (ivm) {
1651
			memset(retval, 0, sizeof(*retval));
1651
			memset(retval, 0, sizeof(*retval));
1652
		}
1652
		}
1653
		populate_defaults(retval);
1653
		populate_defaults(retval);
1654
		if (!ivm) {
1654
		if (!ivm) {
1655
			ast_set_flag(retval, VM_ALLOCED);
1655
			ast_set_flag(retval, VM_ALLOCED);
1656
		}
1656
		}
1657
		if (mailbox) {
1657
		if (mailbox) {
1658
			ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
1658
			ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
1659
		}
1659
		}
1660
		if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
1660
		if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
1661
			var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
1661
			var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
1662
		} else {
1662
		} else {
1663
			var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
1663
			var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
1664
		}
1664
		}
1665
		if (var) {
1665
		if (var) {
1666
			apply_options_full(retval, var);
1666
			apply_options_full(retval, var);
1667
			ast_variables_destroy(var);
1667
			ast_variables_destroy(var);
1668
		} else { 
1668
		} else { 
1669
			if (!ivm) 
1669
			if (!ivm) 
1670
				ast_free(retval);
1670
				ast_free(retval);
1671
			retval = NULL;
1671
			retval = NULL;
1672
		}	
1672
		}	
1673
	} 
1673
	} 
1674
	return retval;
1674
	return retval;
1675
}
1675
}
1676

    
   
1676

   
1677
/*!
1677
/*!
1678
 * \brief Finds a voicemail user from the users file or the realtime engine.
1678
 * \brief Finds a voicemail user from the users file or the realtime engine.
1679
 * \param ivm
1679
 * \param ivm
1680
 * \param context
1680
 * \param context
1681
 * \param mailbox
1681
 * \param mailbox
1682
 * 
1682
 * 
1683
 * \return The ast_vm_user structure for the user that was found.
1683
 * \return The ast_vm_user structure for the user that was found.
1684
 */
1684
 */
1685
static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
1685
static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
1686
{
1686
{
1687
	/* This function could be made to generate one from a database, too */
1687
	/* This function could be made to generate one from a database, too */
1688
	struct ast_vm_user *vmu = NULL, *cur;
1688
	struct ast_vm_user *vmu = NULL, *cur;
1689
	AST_LIST_LOCK(&users);
1689
	AST_LIST_LOCK(&users);
1690

    
   
1690

   
1691
	if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
1691
	if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
1692
		context = "default";
1692
		context = "default";
1693

    
   
1693

   
1694
	AST_LIST_TRAVERSE(&users, cur, list) {
1694
	AST_LIST_TRAVERSE(&users, cur, list) {
1695
#ifdef IMAP_STORAGE
1695
#ifdef IMAP_STORAGE
1696
		if (cur->imapversion != imapversion) {
1696
		if (cur->imapversion != imapversion) {
1697
			continue;
1697
			continue;
1698
		}
1698
		}
1699
#endif
1699
#endif
1700
		if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
1700
		if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
1701
			break;
1701
			break;
1702
		if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1702
		if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1703
			break;
1703
			break;
1704
	}
1704
	}
1705
	if (cur) {
1705
	if (cur) {
1706
		/* Make a copy, so that on a reload, we have no race */
1706
		/* Make a copy, so that on a reload, we have no race */
1707
		if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
1707
		if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
1708
			*vmu = *cur;
1708
			*vmu = *cur;
1709
			if (!ivm) {
1709
			if (!ivm) {
1710
				vmu->emailbody = ast_strdup(cur->emailbody);
1710
				vmu->emailbody = ast_strdup(cur->emailbody);
1711
				vmu->emailsubject = ast_strdup(cur->emailsubject);
1711
				vmu->emailsubject = ast_strdup(cur->emailsubject);
1712
			}
1712
			}
1713
			ast_set2_flag(vmu, !ivm, VM_ALLOCED);
1713
			ast_set2_flag(vmu, !ivm, VM_ALLOCED);
1714
			AST_LIST_NEXT(vmu, list) = NULL;
1714
			AST_LIST_NEXT(vmu, list) = NULL;
1715
		}
1715
		}
1716
	} else
1716
	} else
1717
		vmu = find_user_realtime(ivm, context, mailbox);
1717
		vmu = find_user_realtime(ivm, context, mailbox);
1718
	AST_LIST_UNLOCK(&users);
1718
	AST_LIST_UNLOCK(&users);
1719
	return vmu;
1719
	return vmu;
1720
}
1720
}
1721

    
   
1721

   
1722
/*!
1722
/*!
1723
 * \brief Resets a user password to a specified password.
1723
 * \brief Resets a user password to a specified password.
1724
 * \param context
1724
 * \param context
1725
 * \param mailbox
1725
 * \param mailbox
1726
 * \param newpass
1726
 * \param newpass
1727
 *
1727
 *
1728
 * This does the actual change password work, called by the vm_change_password() function.
1728
 * This does the actual change password work, called by the vm_change_password() function.
1729
 *
1729
 *
1730
 * \return zero on success, -1 on error.
1730
 * \return zero on success, -1 on error.
1731
 */
1731
 */
1732
static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
1732
static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
1733
{
1733
{
1734
	/* This function could be made to generate one from a database, too */
1734
	/* This function could be made to generate one from a database, too */
1735
	struct ast_vm_user *cur;
1735
	struct ast_vm_user *cur;
1736
	int res = -1;
1736
	int res = -1;
1737
	AST_LIST_LOCK(&users);
1737
	AST_LIST_LOCK(&users);
1738
	AST_LIST_TRAVERSE(&users, cur, list) {
1738
	AST_LIST_TRAVERSE(&users, cur, list) {
1739
		if ((!context || !strcasecmp(context, cur->context)) &&
1739
		if ((!context || !strcasecmp(context, cur->context)) &&
1740
			(!strcasecmp(mailbox, cur->mailbox)))
1740
			(!strcasecmp(mailbox, cur->mailbox)))
1741
				break;
1741
				break;
1742
	}
1742
	}
1743
	if (cur) {
1743
	if (cur) {
1744
		ast_copy_string(cur->password, newpass, sizeof(cur->password));
1744
		ast_copy_string(cur->password, newpass, sizeof(cur->password));
1745
		res = 0;
1745
		res = 0;
1746
	}
1746
	}
1747
	AST_LIST_UNLOCK(&users);
1747
	AST_LIST_UNLOCK(&users);
1748
	return res;
1748
	return res;
1749
}
1749
}
1750

    
   
1750

   
1751
/*!
1751
/*!
1752
 * \brief Check if configuration file is valid
1752
 * \brief Check if configuration file is valid
1753
 */
1753
 */
1754
static inline int valid_config(const struct ast_config *cfg)
1754
static inline int valid_config(const struct ast_config *cfg)
1755
{
1755
{
1756
	return cfg && cfg != CONFIG_STATUS_FILEINVALID;
1756
	return cfg && cfg != CONFIG_STATUS_FILEINVALID;
1757
}
1757
}
1758

    
   
1758

   
1759
/*! 
1759
/*! 
1760
 * \brief The handler for the change password option.
1760
 * \brief The handler for the change password option.
1761
 * \param vmu The voicemail user to work with.
1761
 * \param vmu The voicemail user to work with.
1762
 * \param newpassword The new password (that has been gathered from the appropriate prompting).
1762
 * \param newpassword The new password (that has been gathered from the appropriate prompting).
1763
 * This is called when a new user logs in for the first time and the option to force them to change their password is set.
1763
 * This is called when a new user logs in for the first time and the option to force them to change their password is set.
1764
 * It is also called when the user wants to change their password from menu option '5' on the mailbox options menu.
1764
 * It is also called when the user wants to change their password from menu option '5' on the mailbox options menu.
1765
 */
1765
 */
1766
static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
1766
static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
1767
{
1767
{
1768
	struct ast_config   *cfg = NULL;
1768
	struct ast_config   *cfg = NULL;
1769
	struct ast_variable *var = NULL;
1769
	struct ast_variable *var = NULL;
1770
	struct ast_category *cat = NULL;
1770
	struct ast_category *cat = NULL;
1771
	char *category = NULL, *value = NULL, *new = NULL;
1771
	char *category = NULL, *value = NULL, *new = NULL;
1772
	const char *tmp = NULL;
1772
	const char *tmp = NULL;
1773
	struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
1773
	struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
1774
	char secretfn[PATH_MAX] = "";
1774
	char secretfn[PATH_MAX] = "";
1775
	int found = 0;
1775
	int found = 0;
1776

    
   
1776

   
1777
	if (!change_password_realtime(vmu, newpassword))
1777
	if (!change_password_realtime(vmu, newpassword))
1778
		return;
1778
		return;
1779

    
   
1779

   
1780
	/* check if we should store the secret in the spool directory next to the messages */
1780
	/* check if we should store the secret in the spool directory next to the messages */
1781
	switch (vmu->passwordlocation) {
1781
	switch (vmu->passwordlocation) {
1782
	case OPT_PWLOC_SPOOLDIR:
1782
	case OPT_PWLOC_SPOOLDIR:
1783
		snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
1783
		snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
1784
		if (write_password_to_file(secretfn, newpassword) == 0) {
1784
		if (write_password_to_file(secretfn, newpassword) == 0) {
1785
			ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
1785
			ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
1786
			ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
1786
			ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
1787
			reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1787
			reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1788
			ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1788
			ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1789
			break;
1789
			break;
1790
		} else {
1790
		} else {
1791
			ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
1791
			ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
1792
		}
1792
		}
1793
		/* Fall-through */
1793
		/* Fall-through */
1794
	case OPT_PWLOC_VOICEMAILCONF:
1794
	case OPT_PWLOC_VOICEMAILCONF:
1795
		if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
1795
		if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
1796
			while ((category = ast_category_browse(cfg, category))) {
1796
			while ((category = ast_category_browse(cfg, category))) {
1797
				if (!strcasecmp(category, vmu->context)) {
1797
				if (!strcasecmp(category, vmu->context)) {
1798
					if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
1798
					if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
1799
						ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
1799
						ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
1800
						break;
1800
						break;
1801
					}
1801
					}
1802
					value = strstr(tmp, ",");
1802
					value = strstr(tmp, ",");
1803
					if (!value) {
1803
					if (!value) {
1804
						new = ast_alloca(strlen(newpassword)+1);
1804
						new = ast_alloca(strlen(newpassword)+1);
1805
						sprintf(new, "%s", newpassword);
1805
						sprintf(new, "%s", newpassword);
1806
					} else {
1806
					} else {
1807
						new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
1807
						new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
1808
						sprintf(new, "%s%s", newpassword, value);
1808
						sprintf(new, "%s%s", newpassword, value);
1809
					}
1809
					}
1810
					if (!(cat = ast_category_get(cfg, category))) {
1810
					if (!(cat = ast_category_get(cfg, category))) {
1811
						ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
1811
						ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
1812
						break;
1812
						break;
1813
					}
1813
					}
1814
					ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
1814
					ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
1815
					found = 1;
1815
					found = 1;
1816
				}
1816
				}
1817
			}
1817
			}
1818
			/* save the results */
1818
			/* save the results */
1819
			if (found) {
1819
			if (found) {
1820
				ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
1820
				ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
1821
				reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1821
				reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1822
				ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1822
				ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1823
				ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
1823
				ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
1824
				ast_config_destroy(cfg);
1824
				ast_config_destroy(cfg);
1825
				break;
1825
				break;
1826
			}
1826
			}
1827

    
   
1827

   
1828
			ast_config_destroy(cfg);
1828
			ast_config_destroy(cfg);
1829
		}
1829
		}
1830
		/* Fall-through */
1830
		/* Fall-through */
1831
	case OPT_PWLOC_USERSCONF:
1831
	case OPT_PWLOC_USERSCONF:
1832
		/* check users.conf and update the password stored for the mailbox */
1832
		/* check users.conf and update the password stored for the mailbox */
1833
		/* if no vmsecret entry exists create one. */
1833
		/* if no vmsecret entry exists create one. */
1834
		if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
1834
		if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
1835
			ast_debug(4, "we are looking for %s\n", vmu->mailbox);
1835
			ast_debug(4, "we are looking for %s\n", vmu->mailbox);
1836
			for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
1836
			for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
1837
				ast_debug(4, "users.conf: %s\n", category);
1837
				ast_debug(4, "users.conf: %s\n", category);
1838
				if (!strcasecmp(category, vmu->mailbox)) {
1838
				if (!strcasecmp(category, vmu->mailbox)) {
1839
					if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
1839
					if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
1840
						ast_debug(3, "looks like we need to make vmsecret!\n");
1840
						ast_debug(3, "looks like we need to make vmsecret!\n");
1841
						var = ast_variable_new("vmsecret", newpassword, "");
1841
						var = ast_variable_new("vmsecret", newpassword, "");
1842
					} else {
1842
					} else {
1843
						var = NULL;
1843
						var = NULL;
1844
					}
1844
					}
1845
					new = ast_alloca(strlen(newpassword) + 1);
1845
					new = ast_alloca(strlen(newpassword) + 1);
1846
					sprintf(new, "%s", newpassword);
1846
					sprintf(new, "%s", newpassword);
1847
					if (!(cat = ast_category_get(cfg, category))) {
1847
					if (!(cat = ast_category_get(cfg, category))) {
1848
						ast_debug(4, "failed to get category!\n");
1848
						ast_debug(4, "failed to get category!\n");
1849
						ast_free(var);
1849
						ast_free(var);
1850
						break;
1850
						break;
1851
					}
1851
					}
1852
					if (!var) {
1852
					if (!var) {
1853
						ast_variable_update(cat, "vmsecret", new, NULL, 0);
1853
						ast_variable_update(cat, "vmsecret", new, NULL, 0);
1854
					} else {
1854
					} else {
1855
						ast_variable_append(cat, var);
1855
						ast_variable_append(cat, var);
1856
					}
1856
					}
1857
					found = 1;
1857
					found = 1;
1858
					break;
1858
					break;
1859
				}
1859
				}
1860
			}
1860
			}
1861
			/* save the results and clean things up */
1861
			/* save the results and clean things up */
1862
			if (found) {
1862
			if (found) {
1863
				ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
1863
				ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
1864
				reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1864
				reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1865
				ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1865
				ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1866
				ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
1866
				ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
1867
			}
1867
			}
1868

    
   
1868

   
1869
			ast_config_destroy(cfg);
1869
			ast_config_destroy(cfg);
1870
		}
1870
		}
1871
	}
1871
	}
1872
}
1872
}
1873

    
   
1873

   
1874
static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
1874
static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
1875
{
1875
{
1876
	char buf[255];
1876
	char buf[255];
1877
	snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
1877
	snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
1878
	ast_debug(1, "External password: %s\n",buf);
1878
	ast_debug(1, "External password: %s\n",buf);
1879
	if (!ast_safe_system(buf)) {
1879
	if (!ast_safe_system(buf)) {
1880
		ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
1880
		ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
1881
		ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1881
		ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
1882
		/* Reset the password in memory, too */
1882
		/* Reset the password in memory, too */
1883
		reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1883
		reset_user_pw(vmu->context, vmu->mailbox, newpassword);
1884
	}
1884
	}
1885
}
1885
}
1886

    
   
1886

   
1887
/*! 
1887
/*! 
1888
 * \brief Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
1888
 * \brief Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
1889
 * \param dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
1889
 * \param dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
1890
 * \param len The length of the path string that was written out.
1890
 * \param len The length of the path string that was written out.
1891
 * \param context
1891
 * \param context
1892
 * \param ext 
1892
 * \param ext 
1893
 * \param folder 
1893
 * \param folder 
1894
 * 
1894
 * 
1895
 * The path is constructed as 
1895
 * The path is constructed as 
1896
 * 	VM_SPOOL_DIRcontext/ext/folder
1896
 * 	VM_SPOOL_DIRcontext/ext/folder
1897
 *
1897
 *
1898
 * \return zero on success, -1 on error.
1898
 * \return zero on success, -1 on error.
1899
 */
1899
 */
1900
static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
1900
static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
1901
{
1901
{
1902
	return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
1902
	return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
1903
}
1903
}
1904

    
   
1904

   
1905
/*! 
1905
/*! 
1906
 * \brief Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
1906
 * \brief Creates a file system path expression for a folder within the voicemail data folder and the appropriate context.
1907
 * \param dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
1907
 * \param dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX.
1908
 * \param len The length of the path string that was written out.
1908
 * \param len The length of the path string that was written out.
1909
 * \param dir 
1909
 * \param dir 
1910
 * \param num 
1910
 * \param num 
1911
 * 
1911
 * 
1912
 * The path is constructed as 
1912
 * The path is constructed as 
1913
 * 	VM_SPOOL_DIRcontext/ext/folder
1913
 * 	VM_SPOOL_DIRcontext/ext/folder
1914
 *
1914
 *
1915
 * \return zero on success, -1 on error.
1915
 * \return zero on success, -1 on error.
1916
 */
1916
 */
1917
static int make_file(char *dest, const int len, const char *dir, const int num)
1917
static int make_file(char *dest, const int len, const char *dir, const int num)
1918
{
1918
{
1919
	return snprintf(dest, len, "%s/msg%04d", dir, num);
1919
	return snprintf(dest, len, "%s/msg%04d", dir, num);
1920
}
1920
}
1921

    
   
1921

   
1922
/* same as mkstemp, but return a FILE * */
1922
/* same as mkstemp, but return a FILE * */
1923
static FILE *vm_mkftemp(char *template)
1923
static FILE *vm_mkftemp(char *template)
1924
{
1924
{
1925
	FILE *p = NULL;
1925
	FILE *p = NULL;
1926
	int pfd = mkstemp(template);
1926
	int pfd = mkstemp(template);
1927
	chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
1927
	chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
1928
	if (pfd > -1) {
1928
	if (pfd > -1) {
1929
		p = fdopen(pfd, "w+");
1929
		p = fdopen(pfd, "w+");
1930
		if (!p) {
1930
		if (!p) {
1931
			close(pfd);
1931
			close(pfd);
1932
			pfd = -1;
1932
			pfd = -1;
1933
		}
1933
		}
1934
	}
1934
	}
1935
	return p;
1935
	return p;
1936
}
1936
}
1937

    
   
1937

   
1938
/*! \brief basically mkdir -p $dest/$context/$ext/$folder
1938
/*! \brief basically mkdir -p $dest/$context/$ext/$folder
1939
 * \param dest    String. base directory.
1939
 * \param dest    String. base directory.
1940
 * \param len     Length of dest.
1940
 * \param len     Length of dest.
1941
 * \param context String. Ignored if is null or empty string.
1941
 * \param context String. Ignored if is null or empty string.
1942
 * \param ext     String. Ignored if is null or empty string.
1942
 * \param ext     String. Ignored if is null or empty string.
1943
 * \param folder  String. Ignored if is null or empty string. 
1943
 * \param folder  String. Ignored if is null or empty string. 
1944
 * \return -1 on failure, 0 on success.
1944
 * \return -1 on failure, 0 on success.
1945
 */
1945
 */
1946
static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
1946
static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
1947
{
1947
{
1948
	mode_t	mode = VOICEMAIL_DIR_MODE;
1948
	mode_t	mode = VOICEMAIL_DIR_MODE;
1949
	int res;
1949
	int res;
1950

    
   
1950

   
1951
	make_dir(dest, len, context, ext, folder);
1951
	make_dir(dest, len, context, ext, folder);
1952
	if ((res = ast_mkdir(dest, mode))) {
1952
	if ((res = ast_mkdir(dest, mode))) {
1953
		ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
1953
		ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
1954
		return -1;
1954
		return -1;
1955
	}
1955
	}
1956
	return 0;
1956
	return 0;
1957
}
1957
}
1958

    
   
1958

   
1959
static const char *mbox(struct ast_vm_user *vmu, int id)
1959
static const char *mbox(struct ast_vm_user *vmu, int id)
1960
{
1960
{
1961
#ifdef IMAP_STORAGE
1961
#ifdef IMAP_STORAGE
1962
	if (vmu && id == 0) {
1962
	if (vmu && id == 0) {
1963
		return vmu->imapfolder;
1963
		return vmu->imapfolder;
1964
	}
1964
	}
1965
#endif
1965
#endif
1966
	return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
1966
	return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
1967
}
1967
}
1968

    
   
1968

   
1969
static const char *vm_index_to_foldername(int id)
1969
static const char *vm_index_to_foldername(int id)
1970
{
1970
{
1971
	return mbox(NULL, id);
1971
	return mbox(NULL, id);
1972
}
1972
}
1973

    
   
1973

   
1974

    
   
1974

   
1975
static int get_folder_by_name(const char *name)
1975
static int get_folder_by_name(const char *name)
1976
{
1976
{
1977
	size_t i;
1977
	size_t i;
1978

    
   
1978

   
1979
	for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
1979
	for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
1980
		if (strcasecmp(name, mailbox_folders[i]) == 0) {
1980
		if (strcasecmp(name, mailbox_folders[i]) == 0) {
1981
			return i;
1981
			return i;
1982
		}
1982
		}
1983
	}
1983
	}
1984

    
   
1984

   
1985
	return -1;
1985
	return -1;
1986
}
1986
}
1987

    
   
1987

   
1988
static void free_user(struct ast_vm_user *vmu)
1988
static void free_user(struct ast_vm_user *vmu)
1989
{
1989
{
1990
	if (ast_test_flag(vmu, VM_ALLOCED)) {
1990
	if (ast_test_flag(vmu, VM_ALLOCED)) {
1991

    
   
1991

   
1992
		ast_free(vmu->emailbody);
1992
		ast_free(vmu->emailbody);
1993
		vmu->emailbody = NULL;
1993
		vmu->emailbody = NULL;
1994

    
   
1994

   
1995
		ast_free(vmu->emailsubject);
1995
		ast_free(vmu->emailsubject);
1996
		vmu->emailsubject = NULL;
1996
		vmu->emailsubject = NULL;
1997

    
   
1997

   
1998
		ast_free(vmu);
1998
		ast_free(vmu);
1999
	}
1999
	}
2000
}
2000
}
2001

    
   
2001

   
2002
static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
2002
static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
2003

    
   
2003

   
2004
	int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
2004
	int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
2005

    
   
2005

   
2006
	/* remove old allocation */
2006
	/* remove old allocation */
2007
	if (vms->deleted) {
2007
	if (vms->deleted) {
2008
		ast_free(vms->deleted);
2008
		ast_free(vms->deleted);
2009
		vms->deleted = NULL;
2009
		vms->deleted = NULL;
2010
	}
2010
	}
2011
	if (vms->heard) {
2011
	if (vms->heard) {
2012
		ast_free(vms->heard);
2012
		ast_free(vms->heard);
2013
		vms->heard = NULL;
2013
		vms->heard = NULL;
2014
	}
2014
	}
2015
	vms->dh_arraysize = 0;
2015
	vms->dh_arraysize = 0;
2016

    
   
2016

   
2017
	if (arraysize > 0) {
2017
	if (arraysize > 0) {
2018
		if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
2018
		if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
2019
			return -1;
2019
			return -1;
2020
		}
2020
		}
2021
		if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
2021
		if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
2022
			ast_free(vms->deleted);
2022
			ast_free(vms->deleted);
2023
			vms->deleted = NULL;
2023
			vms->deleted = NULL;
2024
			return -1;
2024
			return -1;
2025
		}
2025
		}
2026
		vms->dh_arraysize = arraysize;
2026
		vms->dh_arraysize = arraysize;
2027
	}
2027
	}
2028

    
   
2028

   
2029
	return 0;
2029
	return 0;
2030
}
2030
}
2031

    
   
2031

   
2032
/* All IMAP-specific functions should go in this block. This
2032
/* All IMAP-specific functions should go in this block. This
2033
 * keeps them from being spread out all over the code */
2033
 * keeps them from being spread out all over the code */
2034
#ifdef IMAP_STORAGE
2034
#ifdef IMAP_STORAGE
2035
static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
2035
static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
2036
{
2036
{
2037
	char arg[10];
2037
	char arg[10];
2038
	struct vm_state *vms;
2038
	struct vm_state *vms;
2039
	unsigned long messageNum;
2039
	unsigned long messageNum;
2040

    
   
2040

   
2041
	/* If greetings aren't stored in IMAP, just delete the file */
2041
	/* If greetings aren't stored in IMAP, just delete the file */
2042
	if (msgnum < 0 && !imapgreetings) {
2042
	if (msgnum < 0 && !imapgreetings) {
2043
		ast_filedelete(file, NULL);
2043
		ast_filedelete(file, NULL);
2044
		return;
2044
		return;
2045
	}
2045
	}
2046

    
   
2046

   
2047
	if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2047
	if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2048
		ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
2048
		ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
2049
		return;
2049
		return;
2050
	}
2050
	}
2051

    
   
2051

   
2052
	if (msgnum < 0) {
2052
	if (msgnum < 0) {
2053
		imap_delete_old_greeting(file, vms);
2053
		imap_delete_old_greeting(file, vms);
2054
		return;
2054
		return;
2055
	}
2055
	}
2056

    
   
2056

   
2057
	/* find real message number based on msgnum */
2057
	/* find real message number based on msgnum */
2058
	/* this may be an index into vms->msgArray based on the msgnum. */
2058
	/* this may be an index into vms->msgArray based on the msgnum. */
2059
	messageNum = vms->msgArray[msgnum];
2059
	messageNum = vms->msgArray[msgnum];
2060
	if (messageNum == 0) {
2060
	if (messageNum == 0) {
2061
		ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2061
		ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2062
		return;
2062
		return;
2063
	}
2063
	}
2064
	ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
2064
	ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
2065
	/* delete message */
2065
	/* delete message */
2066
	snprintf (arg, sizeof(arg), "%lu", messageNum);
2066
	snprintf (arg, sizeof(arg), "%lu", messageNum);
2067
	ast_mutex_lock(&vms->lock);
2067
	ast_mutex_lock(&vms->lock);
2068
	mail_setflag (vms->mailstream, arg, "\\DELETED");
2068
	mail_setflag (vms->mailstream, arg, "\\DELETED");
2069
	mail_expunge(vms->mailstream);
2069
	mail_expunge(vms->mailstream);
2070
	ast_mutex_unlock(&vms->lock);
2070
	ast_mutex_unlock(&vms->lock);
2071
}
2071
}
2072

    
   
2072

   
2073
static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder)
2073
static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder)
2074
{
2074
{
2075
	struct ast_channel *chan;
2075
	struct ast_channel *chan;
2076
	char *cid;
2076
	char *cid;
2077
	char *cid_name;
2077
	char *cid_name;
2078
	char *cid_num;
2078
	char *cid_num;
2079
	struct vm_state *vms;
2079
	struct vm_state *vms;
2080
	const char *duration_str;
2080
	const char *duration_str;
2081
	int duration = 0;
2081
	int duration = 0;
2082

    
   
2082

   
2083
	/*
2083
	/*
2084
	 * First, get things initially set up. If any of this fails, then
2084
	 * First, get things initially set up. If any of this fails, then
2085
	 * back out before doing anything substantial
2085
	 * back out before doing anything substantial
2086
	 */
2086
	 */
2087
	vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0);
2087
	vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0);
2088
	if (!vms) {
2088
	if (!vms) {
2089
		return;
2089
		return;
2090
	}
2090
	}
2091

    
   
2091

   
2092
	if (open_mailbox(vms, vmu, folder)) {
2092
	if (open_mailbox(vms, vmu, folder)) {
2093
		return;
2093
		return;
2094
	}
2094
	}
2095

    
   
2095

   
2096
	chan = ast_dummy_channel_alloc();
2096
	chan = ast_dummy_channel_alloc();
2097
	if (!chan) {
2097
	if (!chan) {
2098
		close_mailbox(vms, vmu);
2098
		close_mailbox(vms, vmu);
2099
		return;
2099
		return;
2100
	}
2100
	}
2101

    
   
2101

   
2102
	/*
2102
	/*
2103
	 * We need to make sure the new message we save has the same
2103
	 * We need to make sure the new message we save has the same
2104
	 * callerid, flag, and duration as the original message
2104
	 * callerid, flag, and duration as the original message
2105
	 */
2105
	 */
2106
	cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
2106
	cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
2107

    
   
2107

   
2108
	if (!ast_strlen_zero(cid)) {
2108
	if (!ast_strlen_zero(cid)) {
2109
		ast_callerid_parse(cid, &cid_name, &cid_num);
2109
		ast_callerid_parse(cid, &cid_name, &cid_num);
2110
		ast_party_caller_init(ast_channel_caller(chan));
2110
		ast_party_caller_init(ast_channel_caller(chan));
2111
		if (!ast_strlen_zero(cid_name)) {
2111
		if (!ast_strlen_zero(cid_name)) {
2112
			ast_channel_caller(chan)->id.name.valid = 1;
2112
			ast_channel_caller(chan)->id.name.valid = 1;
2113
			ast_channel_caller(chan)->id.name.str = ast_strdup(cid_name);
2113
			ast_channel_caller(chan)->id.name.str = ast_strdup(cid_name);
2114
		}
2114
		}
2115
		if (!ast_strlen_zero(cid_num)) {
2115
		if (!ast_strlen_zero(cid_num)) {
2116
			ast_channel_caller(chan)->id.number.valid = 1;
2116
			ast_channel_caller(chan)->id.number.valid = 1;
2117
			ast_channel_caller(chan)->id.number.str = ast_strdup(cid_num);
2117
			ast_channel_caller(chan)->id.number.str = ast_strdup(cid_num);
2118
		}
2118
		}
2119
	}
2119
	}
2120

    
   
2120

   
2121
	duration_str = ast_variable_retrieve(msg_cfg, "message", "duration");
2121
	duration_str = ast_variable_retrieve(msg_cfg, "message", "duration");
2122

    
   
2122

   
2123
	if (!ast_strlen_zero(duration_str)) {
2123
	if (!ast_strlen_zero(duration_str)) {
2124
		sscanf(duration_str, "%30d", &duration);
2124
		sscanf(duration_str, "%30d", &duration);
2125
	}
2125
	}
2126

    
   
2126

   
2127
	/*
2127
	/*
2128
	 * IMAP messages cannot be altered once delivered. So we have to delete the
2128
	 * IMAP messages cannot be altered once delivered. So we have to delete the
2129
	 * current message and then re-add it with the updated message ID.
2129
	 * current message and then re-add it with the updated message ID.
2130
	 *
2130
	 *
2131
	 * Furthermore, there currently is no atomic way to create a new message and to
2131
	 * Furthermore, there currently is no atomic way to create a new message and to
2132
	 * store it in an arbitrary folder. So we have to save it to the INBOX and then
2132
	 * store it in an arbitrary folder. So we have to save it to the INBOX and then
2133
	 * move to the appropriate folder.
2133
	 * move to the appropriate folder.
2134
	 */
2134
	 */
2135
	if (!imap_store_file(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, vmfmts,
2135
	if (!imap_store_file(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, vmfmts,
2136
			duration, vms, ast_variable_retrieve(msg_cfg, "message", "flag"), msg_id)) {
2136
			duration, vms, ast_variable_retrieve(msg_cfg, "message", "flag"), msg_id)) {
2137
		if (folder != NEW_FOLDER) {
2137
		if (folder != NEW_FOLDER) {
2138
			save_to_folder(vmu, vms, msgnum, folder, NULL, 1);
2138
			save_to_folder(vmu, vms, msgnum, folder, NULL, 1);
2139
		}
2139
		}
2140
		vm_imap_delete(dir, msgnum, vmu);
2140
		vm_imap_delete(dir, msgnum, vmu);
2141
	}
2141
	}
2142
	close_mailbox(vms, vmu);
2142
	close_mailbox(vms, vmu);
2143
	ast_channel_unref(chan);
2143
	ast_channel_unref(chan);
2144
}
2144
}
2145

    
   
2145

   
2146
static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
2146
static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
2147
{
2147
{
2148
	struct vm_state *vms_p;
2148
	struct vm_state *vms_p;
2149
	char *file, *filename;
2149
	char *file, *filename;
2150
	char *attachment;
2150
	char *attachment;
2151
	int i;
2151
	int i;
2152
	BODY *body;
2152
	BODY *body;
2153

    
   
2153

   
2154
	/* This function is only used for retrieval of IMAP greetings
2154
	/* This function is only used for retrieval of IMAP greetings
2155
	 * regular messages are not retrieved this way, nor are greetings
2155
	 * regular messages are not retrieved this way, nor are greetings
2156
	 * if they are stored locally*/
2156
	 * if they are stored locally*/
2157
	if (msgnum > -1 || !imapgreetings) {
2157
	if (msgnum > -1 || !imapgreetings) {
2158
		return 0;
2158
		return 0;
2159
	} else {
2159
	} else {
2160
		file = strrchr(ast_strdupa(dir), '/');
2160
		file = strrchr(ast_strdupa(dir), '/');
2161
		if (file)
2161
		if (file)
2162
			*file++ = '\0';
2162
			*file++ = '\0';
2163
		else {
2163
		else {
2164
			ast_debug(1, "Failed to procure file name from directory passed.\n");
2164
			ast_debug(1, "Failed to procure file name from directory passed.\n");
2165
			return -1;
2165
			return -1;
2166
		}
2166
		}
2167
	}
2167
	}
2168

    
   
2168

   
2169
	/* check if someone is accessing this box right now... */
2169
	/* check if someone is accessing this box right now... */
2170
	if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && 
2170
	if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && 
2171
		!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2171
		!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2172
		/* Unlike when retrieving a message, it is reasonable not to be able to find a 
2172
		/* Unlike when retrieving a message, it is reasonable not to be able to find a 
2173
		* vm_state for a mailbox when trying to retrieve a greeting. Just create one,
2173
		* vm_state for a mailbox when trying to retrieve a greeting. Just create one,
2174
		* that's all we need to do.
2174
		* that's all we need to do.
2175
		*/
2175
		*/
2176
		if (!(vms_p = create_vm_state_from_user(vmu))) {
2176
		if (!(vms_p = create_vm_state_from_user(vmu))) {
2177
			ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
2177
			ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
2178
			return -1;
2178
			return -1;
2179
		}
2179
		}
2180
	}
2180
	}
2181

    
   
2181

   
2182
	/* Greetings will never have a prepended message */
2182
	/* Greetings will never have a prepended message */
2183
	*vms_p->introfn = '\0';
2183
	*vms_p->introfn = '\0';
2184

    
   
2184

   
2185
	ast_mutex_lock(&vms_p->lock);
2185
	ast_mutex_lock(&vms_p->lock);
2186
	if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
2186
	if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
2187
		ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
2187
		ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
2188
		ast_mutex_unlock(&vms_p->lock);
2188
		ast_mutex_unlock(&vms_p->lock);
2189
		return -1;
2189
		return -1;
2190
	}
2190
	}
2191

    
   
2191

   
2192
	/*XXX Yuck, this could probably be done a lot better */
2192
	/*XXX Yuck, this could probably be done a lot better */
2193
	for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2193
	for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2194
		mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2194
		mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2195
		/* We have the body, now we extract the file name of the first attachment. */
2195
		/* We have the body, now we extract the file name of the first attachment. */
2196
		if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2196
		if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2197
			attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
2197
			attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
2198
		} else {
2198
		} else {
2199
			ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
2199
			ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
2200
			ast_mutex_unlock(&vms_p->lock);
2200
			ast_mutex_unlock(&vms_p->lock);
2201
			return -1;
2201
			return -1;
2202
		}
2202
		}
2203
		filename = strsep(&attachment, ".");
2203
		filename = strsep(&attachment, ".");
2204
		if (!strcmp(filename, file)) {
2204
		if (!strcmp(filename, file)) {
2205
			ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
2205
			ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
2206
			vms_p->msgArray[vms_p->curmsg] = i + 1;
2206
			vms_p->msgArray[vms_p->curmsg] = i + 1;
2207
			save_body(body, vms_p, "2", attachment, 0);
2207
			save_body(body, vms_p, "2", attachment, 0);
2208
			ast_mutex_unlock(&vms_p->lock);
2208
			ast_mutex_unlock(&vms_p->lock);
2209
			return 0;
2209
			return 0;
2210
		}
2210
		}
2211
	}
2211
	}
2212
	ast_mutex_unlock(&vms_p->lock);
2212
	ast_mutex_unlock(&vms_p->lock);
2213

    
   
2213

   
2214
	return -1;
2214
	return -1;
2215
}
2215
}
2216

    
   
2216

   
2217
static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
2217
static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
2218
{
2218
{
2219
	BODY *body;
2219
	BODY *body;
2220
	char *header_content;
2220
	char *header_content;
2221
	char *attachedfilefmt;
2221
	char *attachedfilefmt;
2222
	char buf[80];
2222
	char buf[80];
2223
	struct vm_state *vms;
2223
	struct vm_state *vms;
2224
	char text_file[PATH_MAX];
2224
	char text_file[PATH_MAX];
2225
	FILE *text_file_ptr;
2225
	FILE *text_file_ptr;
2226
	int res = 0;
2226
	int res = 0;
2227
	struct ast_vm_user *vmu;
2227
	struct ast_vm_user *vmu;
2228

    
   
2228

   
2229
	if (!(vmu = find_user(NULL, context, mailbox))) {
2229
	if (!(vmu = find_user(NULL, context, mailbox))) {
2230
		ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
2230
		ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
2231
		return -1;
2231
		return -1;
2232
	}
2232
	}
2233
	
2233
	
2234
	if (msgnum < 0) {
2234
	if (msgnum < 0) {
2235
		if (imapgreetings) {
2235
		if (imapgreetings) {
2236
			res = imap_retrieve_greeting(dir, msgnum, vmu);
2236
			res = imap_retrieve_greeting(dir, msgnum, vmu);
2237
			goto exit;
2237
			goto exit;
2238
		} else {
2238
		} else {
2239
			res = 0;
2239
			res = 0;
2240
			goto exit;
2240
			goto exit;
2241
		}
2241
		}
2242
	}
2242
	}
2243

    
   
2243

   
2244
	/* Before anything can happen, we need a vm_state so that we can
2244
	/* Before anything can happen, we need a vm_state so that we can
2245
	 * actually access the imap server through the vms->mailstream
2245
	 * actually access the imap server through the vms->mailstream
2246
	 */
2246
	 */
2247
	if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2247
	if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
2248
		/* This should not happen. If it does, then I guess we'd
2248
		/* This should not happen. If it does, then I guess we'd
2249
		 * need to create the vm_state, extract which mailbox to
2249
		 * need to create the vm_state, extract which mailbox to
2250
		 * open, and then set up the msgArray so that the correct
2250
		 * open, and then set up the msgArray so that the correct
2251
		 * IMAP message could be accessed. If I have seen correctly
2251
		 * IMAP message could be accessed. If I have seen correctly
2252
		 * though, the vms should be obtainable from the vmstates list
2252
		 * though, the vms should be obtainable from the vmstates list
2253
		 * and should have its msgArray properly set up.
2253
		 * and should have its msgArray properly set up.
2254
		 */
2254
		 */
2255
		ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
2255
		ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
2256
		res = -1;
2256
		res = -1;
2257
		goto exit;
2257
		goto exit;
2258
	}
2258
	}
2259

    
   
2259

   
2260
	make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
2260
	make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
2261
	snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
2261
	snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
2262

    
   
2262

   
2263
	/* Don't try to retrieve a message from IMAP if it already is on the file system */
2263
	/* Don't try to retrieve a message from IMAP if it already is on the file system */
2264
	if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
2264
	if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
2265
		res = 0;
2265
		res = 0;
2266
		goto exit;
2266
		goto exit;
2267
	}
2267
	}
2268

    
   
2268

   
2269
	ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
2269
	ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
2270
	if (vms->msgArray[msgnum] == 0) {
2270
	if (vms->msgArray[msgnum] == 0) {
2271
		ast_log(LOG_WARNING, "Trying to access unknown message\n");
2271
		ast_log(LOG_WARNING, "Trying to access unknown message\n");
2272
		res = -1;
2272
		res = -1;
2273
		goto exit;
2273
		goto exit;
2274
	}
2274
	}
2275

    
   
2275

   
2276
	/* This will only work for new messages... */
2276
	/* This will only work for new messages... */
2277
	ast_mutex_lock(&vms->lock);
2277
	ast_mutex_lock(&vms->lock);
2278
	header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2278
	header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2279
	ast_mutex_unlock(&vms->lock);
2279
	ast_mutex_unlock(&vms->lock);
2280
	/* empty string means no valid header */
2280
	/* empty string means no valid header */
2281
	if (ast_strlen_zero(header_content)) {
2281
	if (ast_strlen_zero(header_content)) {
2282
		ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2282
		ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2283
		res = -1;
2283
		res = -1;
2284
		goto exit;
2284
		goto exit;
2285
	}
2285
	}
2286

    
   
2286

   
2287
	ast_mutex_lock(&vms->lock);
2287
	ast_mutex_lock(&vms->lock);
2288
	mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2288
	mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2289
	ast_mutex_unlock(&vms->lock);
2289
	ast_mutex_unlock(&vms->lock);
2290

    
   
2290

   
2291
	/* We have the body, now we extract the file name of the first attachment. */
2291
	/* We have the body, now we extract the file name of the first attachment. */
2292
	if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2292
	if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2293
		attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
2293
		attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
2294
	} else {
2294
	} else {
2295
		ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
2295
		ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
2296
		res = -1;
2296
		res = -1;
2297
		goto exit;
2297
		goto exit;
2298
	}
2298
	}
2299
	
2299
	
2300
	/* Find the format of the attached file */
2300
	/* Find the format of the attached file */
2301

    
   
2301

   
2302
	strsep(&attachedfilefmt, ".");
2302
	strsep(&attachedfilefmt, ".");
2303
	if (!attachedfilefmt) {
2303
	if (!attachedfilefmt) {
2304
		ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
2304
		ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
2305
		res = -1;
2305
		res = -1;
2306
		goto exit;
2306
		goto exit;
2307
	}
2307
	}
2308
	
2308
	
2309
	save_body(body, vms, "2", attachedfilefmt, 0);
2309
	save_body(body, vms, "2", attachedfilefmt, 0);
2310
	if (save_body(body, vms, "3", attachedfilefmt, 1)) {
2310
	if (save_body(body, vms, "3", attachedfilefmt, 1)) {
2311
		*vms->introfn = '\0';
2311
		*vms->introfn = '\0';
2312
	}
2312
	}
2313

    
   
2313

   
2314
	/* Get info from headers!! */
2314
	/* Get info from headers!! */
2315
	snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
2315
	snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
2316

    
   
2316

   
2317
	if (!(text_file_ptr = fopen(text_file, "w"))) {
2317
	if (!(text_file_ptr = fopen(text_file, "w"))) {
2318
		ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
2318
		ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
2319
	}
2319
	}
2320

    
   
2320

   
2321
	fprintf(text_file_ptr, "%s\n", "[message]");
2321
	fprintf(text_file_ptr, "%s\n", "[message]");
2322

    
   
2322

   
2323
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf))) {
2323
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf))) {
2324
		fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
2324
		fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
2325
	}
2325
	}
2326
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf))) {
2326
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf))) {
2327
		fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
2327
		fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
2328
	}
2328
	}
2329
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf))) {
2329
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf))) {
2330
		fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
2330
		fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
2331
	}
2331
	}
2332
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf))) {
2332
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf))) {
2333
		fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
2333
		fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
2334
	}
2334
	}
2335
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf))) {
2335
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf))) {
2336
		fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
2336
		fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
2337
	}
2337
	}
2338
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf))) {
2338
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf))) {
2339
		fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
2339
		fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
2340
	}
2340
	}
2341
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf))) {
2341
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf))) {
2342
		fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
2342
		fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
2343
	}
2343
	}
2344
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Message-ID:", buf, sizeof(buf))) {
2344
	if (get_header_by_tag(header_content, "X-Asterisk-VM-Message-ID:", buf, sizeof(buf))) {
2345
		fprintf(text_file_ptr, "msg_id=%s\n", S_OR(buf, ""));
2345
		fprintf(text_file_ptr, "msg_id=%s\n", S_OR(buf, ""));
2346
	}
2346
	}
2347
	fclose(text_file_ptr);
2347
	fclose(text_file_ptr);
2348

    
   
2348

   
2349
exit:
2349
exit:
2350
	free_user(vmu);
2350
	free_user(vmu);
2351
	return res;
2351
	return res;
2352
}
2352
}
2353

    
   
2353

   
2354
static int folder_int(const char *folder)
2354
static int folder_int(const char *folder)
2355
{
2355
{
2356
	/*assume a NULL folder means INBOX*/
2356
	/*assume a NULL folder means INBOX*/
2357
	if (!folder) {
2357
	if (!folder) {
2358
		return 0;
2358
		return 0;
2359
	}
2359
	}
2360
	if (!strcasecmp(folder, imapfolder)) {
2360
	if (!strcasecmp(folder, imapfolder)) {
2361
		return 0;
2361
		return 0;
2362
	} else if (!strcasecmp(folder, "Old")) {
2362
	} else if (!strcasecmp(folder, "Old")) {
2363
		return 1;
2363
		return 1;
2364
	} else if (!strcasecmp(folder, "Work")) {
2364
	} else if (!strcasecmp(folder, "Work")) {
2365
		return 2;
2365
		return 2;
2366
	} else if (!strcasecmp(folder, "Family")) {
2366
	} else if (!strcasecmp(folder, "Family")) {
2367
		return 3;
2367
		return 3;
2368
	} else if (!strcasecmp(folder, "Friends")) {
2368
	} else if (!strcasecmp(folder, "Friends")) {
2369
		return 4;
2369
		return 4;
2370
	} else if (!strcasecmp(folder, "Cust1")) {
2370
	} else if (!strcasecmp(folder, "Cust1")) {
2371
		return 5;
2371
		return 5;
2372
	} else if (!strcasecmp(folder, "Cust2")) {
2372
	} else if (!strcasecmp(folder, "Cust2")) {
2373
		return 6;
2373
		return 6;
2374
	} else if (!strcasecmp(folder, "Cust3")) {
2374
	} else if (!strcasecmp(folder, "Cust3")) {
2375
		return 7;
2375
		return 7;
2376
	} else if (!strcasecmp(folder, "Cust4")) {
2376
	} else if (!strcasecmp(folder, "Cust4")) {
2377
		return 8;
2377
		return 8;
2378
	} else if (!strcasecmp(folder, "Cust5")) {
2378
	} else if (!strcasecmp(folder, "Cust5")) {
2379
		return 9;
2379
		return 9;
2380
	} else if (!strcasecmp(folder, "Urgent")) {
2380
	} else if (!strcasecmp(folder, "Urgent")) {
2381
		return 11;
2381
		return 11;
2382
	} else { /*assume they meant INBOX if folder is not found otherwise*/
2382
	} else { /*assume they meant INBOX if folder is not found otherwise*/
2383
		return 0;
2383
		return 0;
2384
	}
2384
	}
2385
}
2385
}
2386

    
   
2386

   
2387
static int __messagecount(const char *context, const char *mailbox, const char *folder)
2387
static int __messagecount(const char *context, const char *mailbox, const char *folder)
2388
{
2388
{
2389
	SEARCHPGM *pgm;
2389
	SEARCHPGM *pgm;
2390
	SEARCHHEADER *hdr;
2390
	SEARCHHEADER *hdr;
2391

    
   
2391

   
2392
	struct ast_vm_user *vmu, vmus;
2392
	struct ast_vm_user *vmu, vmus;
2393
	struct vm_state *vms_p;
2393
	struct vm_state *vms_p;
2394
	int ret = 0;
2394
	int ret = 0;
2395
	int fold = folder_int(folder);
2395
	int fold = folder_int(folder);
2396
	int urgent = 0;
2396
	int urgent = 0;
2397
	
2397
	
2398
	/* If URGENT, then look at INBOX */
2398
	/* If URGENT, then look at INBOX */
2399
	if (fold == 11) {
2399
	if (fold == 11) {
2400
		fold = NEW_FOLDER;
2400
		fold = NEW_FOLDER;
2401
		urgent = 1;
2401
		urgent = 1;
2402
	}
2402
	}
2403

    
   
2403

   
2404
	if (ast_strlen_zero(mailbox))
2404
	if (ast_strlen_zero(mailbox))
2405
		return 0;
2405
		return 0;
2406

    
   
2406

   
2407
	/* We have to get the user before we can open the stream! */
2407
	/* We have to get the user before we can open the stream! */
2408
	vmu = find_user(&vmus, context, mailbox);
2408
	vmu = find_user(&vmus, context, mailbox);
2409
	if (!vmu) {
2409
	if (!vmu) {
2410
		ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
2410
		ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
2411
		return -1;
2411
		return -1;
2412
	} else {
2412
	} else {
2413
		/* No IMAP account available */
2413
		/* No IMAP account available */
2414
		if (vmu->imapuser[0] == '\0') {
2414
		if (vmu->imapuser[0] == '\0') {
2415
			ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
2415
			ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
2416
			return -1;
2416
			return -1;
2417
		}
2417
		}
2418
	}
2418
	}
2419

    
   
2419

   
2420
	/* No IMAP account available */
2420
	/* No IMAP account available */
2421
	if (vmu->imapuser[0] == '\0') {
2421
	if (vmu->imapuser[0] == '\0') {
2422
		ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
2422
		ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
2423
		free_user(vmu);
2423
		free_user(vmu);
2424
		return -1;
2424
		return -1;
2425
	}
2425
	}
2426

    
   
2426

   
2427
	/* check if someone is accessing this box right now... */
2427
	/* check if someone is accessing this box right now... */
2428
	vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2428
	vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2429
	if (!vms_p) {
2429
	if (!vms_p) {
2430
		vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
2430
		vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
2431
	}
2431
	}
2432
	if (vms_p) {
2432
	if (vms_p) {
2433
		ast_debug(3, "Returning before search - user is logged in\n");
2433
		ast_debug(3, "Returning before search - user is logged in\n");
2434
		if (fold == 0) { /* INBOX */
2434
		if (fold == 0) { /* INBOX */
2435
			return urgent ? vms_p->urgentmessages : vms_p->newmessages;
2435
			return urgent ? vms_p->urgentmessages : vms_p->newmessages;
2436
		}
2436
		}
2437
		if (fold == 1) { /* Old messages */
2437
		if (fold == 1) { /* Old messages */
2438
			return vms_p->oldmessages;
2438
			return vms_p->oldmessages;
2439
		}
2439
		}
2440
	}
2440
	}
2441

    
   
2441

   
2442
	/* add one if not there... */
2442
	/* add one if not there... */
2443
	vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2443
	vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2444
	if (!vms_p) {
2444
	if (!vms_p) {
2445
		vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
2445
		vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
2446
	}
2446
	}
2447

    
   
2447

   
2448
	if (!vms_p) {
2448
	if (!vms_p) {
2449
		vms_p = create_vm_state_from_user(vmu);
2449
		vms_p = create_vm_state_from_user(vmu);
2450
	}
2450
	}
2451
	ret = init_mailstream(vms_p, fold);
2451
	ret = init_mailstream(vms_p, fold);
2452
	if (!vms_p->mailstream) {
2452
	if (!vms_p->mailstream) {
2453
		ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
2453
		ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
2454
		return -1;
2454
		return -1;
2455
	}
2455
	}
2456
	if (ret == 0) {
2456
	if (ret == 0) {
2457
		ast_mutex_lock(&vms_p->lock);
2457
		ast_mutex_lock(&vms_p->lock);
2458
		pgm = mail_newsearchpgm ();
2458
		pgm = mail_newsearchpgm ();
2459
		hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
2459
		hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
2460
		hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
2460
		hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
2461
		pgm->header = hdr;
2461
		pgm->header = hdr;
2462
		if (fold != OLD_FOLDER) {
2462
		if (fold != OLD_FOLDER) {
2463
			pgm->unseen = 1;
2463
			pgm->unseen = 1;
2464
			pgm->seen = 0;
2464
			pgm->seen = 0;
2465
		}
2465
		}
2466
		/* In the special case where fold is 1 (old messages) we have to do things a bit
2466
		/* In the special case where fold is 1 (old messages) we have to do things a bit
2467
		 * differently. Old messages are stored in the INBOX but are marked as "seen"
2467
		 * differently. Old messages are stored in the INBOX but are marked as "seen"
2468
		 */
2468
		 */
2469
		else {
2469
		else {
2470
			pgm->unseen = 0;
2470
			pgm->unseen = 0;
2471
			pgm->seen = 1;
2471
			pgm->seen = 1;
2472
		}
2472
		}
2473
		/* look for urgent messages */
2473
		/* look for urgent messages */
2474
		if (fold == NEW_FOLDER) {
2474
		if (fold == NEW_FOLDER) {
2475
			if (urgent) {
2475
			if (urgent) {
2476
				pgm->flagged = 1;
2476
				pgm->flagged = 1;
2477
				pgm->unflagged = 0;
2477
				pgm->unflagged = 0;
2478
			} else {
2478
			} else {
2479
				pgm->flagged = 0;
2479
				pgm->flagged = 0;
2480
				pgm->unflagged = 1;
2480
				pgm->unflagged = 1;
2481
			}
2481
			}
2482
		}
2482
		}
2483
		pgm->undeleted = 1;
2483
		pgm->undeleted = 1;
2484
		pgm->deleted = 0;
2484
		pgm->deleted = 0;
2485

    
   
2485

   
2486
		vms_p->vmArrayIndex = 0;
2486
		vms_p->vmArrayIndex = 0;
2487
		mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
2487
		mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
2488
		if (fold == 0 && urgent == 0)
2488
		if (fold == 0 && urgent == 0)
2489
			vms_p->newmessages = vms_p->vmArrayIndex;
2489
			vms_p->newmessages = vms_p->vmArrayIndex;
2490
		if (fold == 1)
2490
		if (fold == 1)
2491
			vms_p->oldmessages = vms_p->vmArrayIndex;
2491
			vms_p->oldmessages = vms_p->vmArrayIndex;
2492
		if (fold == 0 && urgent == 1)
2492
		if (fold == 0 && urgent == 1)
2493
			vms_p->urgentmessages = vms_p->vmArrayIndex;
2493
			vms_p->urgentmessages = vms_p->vmArrayIndex;
2494
		/*Freeing the searchpgm also frees the searchhdr*/
2494
		/*Freeing the searchpgm also frees the searchhdr*/
2495
		mail_free_searchpgm(&pgm);
2495
		mail_free_searchpgm(&pgm);
2496
		ast_mutex_unlock(&vms_p->lock);
2496
		ast_mutex_unlock(&vms_p->lock);
2497
		vms_p->updated = 0;
2497
		vms_p->updated = 0;
2498
		return vms_p->vmArrayIndex;
2498
		return vms_p->vmArrayIndex;
2499
	} else {
2499
	} else {
2500
		ast_mutex_lock(&vms_p->lock);
2500
		ast_mutex_lock(&vms_p->lock);
2501
		mail_ping(vms_p->mailstream);
2501
		mail_ping(vms_p->mailstream);
2502
		ast_mutex_unlock(&vms_p->lock);
2502
		ast_mutex_unlock(&vms_p->lock);
2503
	}
2503
	}
2504
	return 0;
2504
	return 0;
2505
}
2505
}
2506

    
   
2506

   
2507
static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
2507
static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
2508
{
2508
{
2509
	/* Check if mailbox is full */
2509
	/* Check if mailbox is full */
2510
	check_quota(vms, vmu->imapfolder);
2510
	check_quota(vms, vmu->imapfolder);
2511
	if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2511
	if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2512
		ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2512
		ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2513
		if (chan) {
2513
		if (chan) {
2514
			ast_play_and_wait(chan, "vm-mailboxfull");
2514
			ast_play_and_wait(chan, "vm-mailboxfull");
2515
		}
2515
		}
2516
		return -1;
2516
		return -1;
2517
	}
2517
	}
2518

    
   
2518

   
2519
	/* Check if we have exceeded maxmsg */
2519
	/* Check if we have exceeded maxmsg */
2520
	ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
2520
	ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
2521
	if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
2521
	if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
2522
		ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
2522
		ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
2523
		if (chan) {
2523
		if (chan) {
2524
			ast_play_and_wait(chan, "vm-mailboxfull");
2524
			ast_play_and_wait(chan, "vm-mailboxfull");
2525
			pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2525
			pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2526
		}
2526
		}
2527
		return -1;
2527
		return -1;
2528
	}
2528
	}
2529

    
   
2529

   
2530
	return 0;
2530
	return 0;
2531
}
2531
}
2532

    
   
2532

   
2533
/*!
2533
/*!
2534
 * \brief Gets the number of messages that exist in a mailbox folder.
2534
 * \brief Gets the number of messages that exist in a mailbox folder.
2535
 * \param mailbox_id
2535
 * \param mailbox_id
2536
 * \param folder
2536
 * \param folder
2537
 * 
2537
 * 
2538
 * This method is used when IMAP backend is used.
2538
 * This method is used when IMAP backend is used.
2539
 * \return The number of messages in this mailbox folder (zero or more).
2539
 * \return The number of messages in this mailbox folder (zero or more).
2540
 */
2540
 */
2541
static int messagecount(const char *mailbox_id, const char *folder)
2541
static int messagecount(const char *mailbox_id, const char *folder)
2542
{
2542
{
2543
	char *context;
2543
	char *context;
2544
	char *mailbox;
2544
	char *mailbox;
2545

    
   
2545

   
2546
	if (ast_strlen_zero(mailbox_id)
2546
	if (ast_strlen_zero(mailbox_id)
2547
		|| separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
2547
		|| separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
2548
		return 0;
2548
		return 0;
2549
	}
2549
	}
2550

    
   
2550

   
2551
	if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
2551
	if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
2552
		return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
2552
		return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
2553
	} else {
2553
	} else {
2554
		return __messagecount(context, mailbox, folder);
2554
		return __messagecount(context, mailbox, folder);
2555
	}
2555
	}
2556
}
2556
}
2557

    
   
2557

   
2558
static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag, const char *msg_id)
2558
static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag, const char *msg_id)
2559
{
2559
{
2560
	char *myserveremail = serveremail;
2560
	char *myserveremail = serveremail;
2561
	char fn[PATH_MAX];
2561
	char fn[PATH_MAX];
2562
	char introfn[PATH_MAX];
2562
	char introfn[PATH_MAX];
2563
	char mailbox[256];
2563
	char mailbox[256];
2564
	char *stringp;
2564
	char *stringp;
2565
	FILE *p = NULL;
2565
	FILE *p = NULL;
2566
	char tmp[80] = "/tmp/astmail-XXXXXX";
2566
	char tmp[80] = "/tmp/astmail-XXXXXX";
2567
	long len;
2567
	long len;
2568
	void *buf;
2568
	void *buf;
2569
	int tempcopy = 0;
2569
	int tempcopy = 0;
2570
	STRING str;
2570
	STRING str;
2571
	int ret; /* for better error checking */
2571
	int ret; /* for better error checking */
2572
	char *imap_flags = NIL;
2572
	char *imap_flags = NIL;
2573
	int msgcount;
2573
	int msgcount;
2574
	int box = NEW_FOLDER;
2574
	int box = NEW_FOLDER;
2575

    
   
2575

   
2576
	snprintf(mailbox, sizeof(mailbox), "%s@%s", vmu->mailbox, vmu->context);
2576
	snprintf(mailbox, sizeof(mailbox), "%s@%s", vmu->mailbox, vmu->context);
2577
	msgcount = messagecount(mailbox, "INBOX") + messagecount(mailbox, "Old");
2577
	msgcount = messagecount(mailbox, "INBOX") + messagecount(mailbox, "Old");
2578

    
   
2578

   
2579
	/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
2579
	/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
2580
	if (msgnum < 0) {
2580
	if (msgnum < 0) {
2581
		if(!imapgreetings) {
2581
		if(!imapgreetings) {
2582
			return 0;
2582
			return 0;
2583
		} else {
2583
		} else {
2584
			box = GREETINGS_FOLDER;
2584
			box = GREETINGS_FOLDER;
2585
		}
2585
		}
2586
	}
2586
	}
2587

    
   
2587

   
2588
	if (imap_check_limits(chan, vms, vmu, msgcount)) {
2588
	if (imap_check_limits(chan, vms, vmu, msgcount)) {
2589
		return -1;
2589
		return -1;
2590
	}
2590
	}
2591

    
   
2591

   
2592
	/* Set urgent flag for IMAP message */
2592
	/* Set urgent flag for IMAP message */
2593
	if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
2593
	if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
2594
		ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
2594
		ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
2595
		imap_flags = "\\FLAGGED";
2595
		imap_flags = "\\FLAGGED";
2596
	}
2596
	}
2597

    
   
2597

   
2598
	/* Attach only the first format */
2598
	/* Attach only the first format */
2599
	fmt = ast_strdupa(fmt);
2599
	fmt = ast_strdupa(fmt);
2600
	stringp = fmt;
2600
	stringp = fmt;
2601
	strsep(&stringp, "|");
2601
	strsep(&stringp, "|");
2602

    
   
2602

   
2603
	if (!ast_strlen_zero(vmu->serveremail))
2603
	if (!ast_strlen_zero(vmu->serveremail))
2604
		myserveremail = vmu->serveremail;
2604
		myserveremail = vmu->serveremail;
2605

    
   
2605

   
2606
	if (msgnum > -1)
2606
	if (msgnum > -1)
2607
		make_file(fn, sizeof(fn), dir, msgnum);
2607
		make_file(fn, sizeof(fn), dir, msgnum);
2608
	else
2608
	else
2609
		ast_copy_string (fn, dir, sizeof(fn));
2609
		ast_copy_string (fn, dir, sizeof(fn));
2610

    
   
2610

   
2611
	snprintf(introfn, sizeof(introfn), "%sintro", fn);
2611
	snprintf(introfn, sizeof(introfn), "%sintro", fn);
2612
	if (ast_fileexists(introfn, NULL, NULL) <= 0) {
2612
	if (ast_fileexists(introfn, NULL, NULL) <= 0) {
2613
		*introfn = '\0';
2613
		*introfn = '\0';
2614
	}
2614
	}
2615

    
   
2615

   
2616
	if (ast_strlen_zero(vmu->email)) {
2616
	if (ast_strlen_zero(vmu->email)) {
2617
		/* We need the vmu->email to be set when we call make_email_file, but
2617
		/* We need the vmu->email to be set when we call make_email_file, but
2618
		 * if we keep it set, a duplicate e-mail will be created. So at the end
2618
		 * if we keep it set, a duplicate e-mail will be created. So at the end
2619
		 * of this function, we will revert back to an empty string if tempcopy
2619
		 * of this function, we will revert back to an empty string if tempcopy
2620
		 * is 1.
2620
		 * is 1.
2621
		 */
2621
		 */
2622
		ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
2622
		ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
2623
		tempcopy = 1;
2623
		tempcopy = 1;
2624
	}
2624
	}
2625

    
   
2625

   
2626
	if (!strcmp(fmt, "wav49"))
2626
	if (!strcmp(fmt, "wav49"))
2627
		fmt = "WAV";
2627
		fmt = "WAV";
2628
	ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
2628
	ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
2629

    
   
2629

   
2630
	/* Make a temporary file instead of piping directly to sendmail, in case the mail
2630
	/* Make a temporary file instead of piping directly to sendmail, in case the mail
2631
	   command hangs. */
2631
	   command hangs. */
2632
	if (!(p = vm_mkftemp(tmp))) {
2632
	if (!(p = vm_mkftemp(tmp))) {
2633
		ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
2633
		ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
2634
		if (tempcopy)
2634
		if (tempcopy)
2635
			*(vmu->email) = '\0';
2635
			*(vmu->email) = '\0';
2636
		return -1;
2636
		return -1;
2637
	}
2637
	}
2638

    
   
2638

   
2639
	if (msgnum < 0 && imapgreetings) {
2639
	if (msgnum < 0 && imapgreetings) {
2640
		if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
2640
		if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
2641
			ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
2641
			ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
2642
			return -1;
2642
			return -1;
2643
		}
2643
		}
2644
		imap_delete_old_greeting(fn, vms);
2644
		imap_delete_old_greeting(fn, vms);
2645
	}
2645
	}
2646

    
   
2646

   
2647
	make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
2647
	make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
2648
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
2648
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
2649
		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
2649
		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
2650
		fn, introfn, fmt, duration, 1, chan, NULL, 1, flag, msg_id);
2650
		fn, introfn, fmt, duration, 1, chan, NULL, 1, flag, msg_id);
2651
	/* read mail file to memory */
2651
	/* read mail file to memory */
2652
	len = ftell(p);
2652
	len = ftell(p);
2653
	rewind(p);
2653
	rewind(p);
2654
	if (!(buf = ast_malloc(len + 1))) {
2654
	if (!(buf = ast_malloc(len + 1))) {
2655
		ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
2655
		ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
2656
		fclose(p);
2656
		fclose(p);
2657
		if (tempcopy)
2657
		if (tempcopy)
2658
			*(vmu->email) = '\0';
2658
			*(vmu->email) = '\0';
2659
		return -1;
2659
		return -1;
2660
	}
2660
	}
2661
	if (fread(buf, len, 1, p) < len) {
2661
	if (fread(buf, len, 1, p) < len) {
2662
		if (ferror(p)) {
2662
		if (ferror(p)) {
2663
			ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
2663
			ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
2664
			return -1;
2664
			return -1;
2665
		}
2665
		}
2666
	}
2666
	}
2667
	((char *) buf)[len] = '\0';
2667
	((char *) buf)[len] = '\0';
2668
	INIT(&str, mail_string, buf, len);
2668
	INIT(&str, mail_string, buf, len);
2669
	ret = init_mailstream(vms, box);
2669
	ret = init_mailstream(vms, box);
2670
	if (ret == 0) {
2670
	if (ret == 0) {
2671
		imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
2671
		imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
2672
		ast_mutex_lock(&vms->lock);
2672
		ast_mutex_lock(&vms->lock);
2673
		if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
2673
		if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
2674
			ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
2674
			ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
2675
		ast_mutex_unlock(&vms->lock);
2675
		ast_mutex_unlock(&vms->lock);
2676
		fclose(p);
2676
		fclose(p);
2677
		unlink(tmp);
2677
		unlink(tmp);
2678
		ast_free(buf);
2678
		ast_free(buf);
2679
	} else {
2679
	} else {
2680
		ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
2680
		ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
2681
		fclose(p);
2681
		fclose(p);
2682
		unlink(tmp);
2682
		unlink(tmp);
2683
		ast_free(buf);
2683
		ast_free(buf);
2684
		return -1;
2684
		return -1;
2685
	}
2685
	}
2686
	ast_debug(3, "%s stored\n", fn);
2686
	ast_debug(3, "%s stored\n", fn);
2687

    
   
2687

   
2688
	if (tempcopy)
2688
	if (tempcopy)
2689
		*(vmu->email) = '\0';
2689
		*(vmu->email) = '\0';
2690
	inprocess_count(vmu->mailbox, vmu->context, -1);
2690
	inprocess_count(vmu->mailbox, vmu->context, -1);
2691
	return 0;
2691
	return 0;
2692

    
   
2692

   
2693
}
2693
}
2694

    
   
2694

   
2695
/*!
2695
/*!
2696
 * \brief Gets the number of messages that exist in the inbox folder.
2696
 * \brief Gets the number of messages that exist in the inbox folder.
2697
 * \param mailbox_context
2697
 * \param mailbox_context
2698
 * \param newmsgs The variable that is updated with the count of new messages within this inbox.
2698
 * \param newmsgs The variable that is updated with the count of new messages within this inbox.
2699
 * \param oldmsgs The variable that is updated with the count of old messages within this inbox.
2699
 * \param oldmsgs The variable that is updated with the count of old messages within this inbox.
2700
 * \param urgentmsgs The variable that is updated with the count of urgent messages within this inbox.
2700
 * \param urgentmsgs The variable that is updated with the count of urgent messages within this inbox.
2701
 * 
2701
 * 
2702
 * This method is used when IMAP backend is used.
2702
 * This method is used when IMAP backend is used.
2703
 * Simultaneously determines the count of new,old, and urgent messages. The total messages would then be the sum of these three.
2703
 * Simultaneously determines the count of new,old, and urgent messages. The total messages would then be the sum of these three.
2704
 *
2704
 *
2705
 * \return zero on success, -1 on error.
2705
 * \return zero on success, -1 on error.
2706
 */
2706
 */
2707

    
   
2707

   
2708
static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
2708
static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
2709
{
2709
{
2710
	char tmp[PATH_MAX] = "";
2710
	char tmp[PATH_MAX] = "";
2711
	char *mailboxnc;
2711
	char *mailboxnc;
2712
	char *context;
2712
	char *context;
2713
	char *mb;
2713
	char *mb;
2714
	char *cur;
2714
	char *cur;
2715
	if (newmsgs)
2715
	if (newmsgs)
2716
		*newmsgs = 0;
2716
		*newmsgs = 0;
2717
	if (oldmsgs)
2717
	if (oldmsgs)
2718
		*oldmsgs = 0;
2718
		*oldmsgs = 0;
2719
	if (urgentmsgs)
2719
	if (urgentmsgs)
2720
		*urgentmsgs = 0;
2720
		*urgentmsgs = 0;
2721

    
   
2721

   
2722
	ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
2722
	ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
2723
	/* If no mailbox, return immediately */
2723
	/* If no mailbox, return immediately */
2724
	if (ast_strlen_zero(mailbox_context))
2724
	if (ast_strlen_zero(mailbox_context))
2725
		return 0;
2725
		return 0;
2726

    
   
2726

   
2727
	ast_copy_string(tmp, mailbox_context, sizeof(tmp));
2727
	ast_copy_string(tmp, mailbox_context, sizeof(tmp));
2728
	context = strchr(tmp, '@');
2728
	context = strchr(tmp, '@');
2729
	if (strchr(mailbox_context, ',')) {
2729
	if (strchr(mailbox_context, ',')) {
2730
		int tmpnew, tmpold, tmpurgent;
2730
		int tmpnew, tmpold, tmpurgent;
2731
		ast_copy_string(tmp, mailbox_context, sizeof(tmp));
2731
		ast_copy_string(tmp, mailbox_context, sizeof(tmp));
2732
		mb = tmp;
2732
		mb = tmp;
2733
		while ((cur = strsep(&mb, ", "))) {
2733
		while ((cur = strsep(&mb, ", "))) {
2734
			if (!ast_strlen_zero(cur)) {
2734
			if (!ast_strlen_zero(cur)) {
2735
				if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
2735
				if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
2736
					return -1;
2736
					return -1;
2737
				else {
2737
				else {
2738
					if (newmsgs)
2738
					if (newmsgs)
2739
						*newmsgs += tmpnew; 
2739
						*newmsgs += tmpnew; 
2740
					if (oldmsgs)
2740
					if (oldmsgs)
2741
						*oldmsgs += tmpold;
2741
						*oldmsgs += tmpold;
2742
					if (urgentmsgs)
2742
					if (urgentmsgs)
2743
						*urgentmsgs += tmpurgent;
2743
						*urgentmsgs += tmpurgent;
2744
				}
2744
				}
2745
			}
2745
			}
2746
		}
2746
		}
2747
		return 0;
2747
		return 0;
2748
	}
2748
	}
2749
	if (context) {
2749
	if (context) {
2750
		*context = '\0';
2750
		*context = '\0';
2751
		mailboxnc = tmp;
2751
		mailboxnc = tmp;
2752
		context++;
2752
		context++;
2753
	} else {
2753
	} else {
2754
		context = "default";
2754
		context = "default";
2755
		mailboxnc = (char *) mailbox_context;
2755
		mailboxnc = (char *) mailbox_context;
2756
	}
2756
	}
2757

    
   
2757

   
2758
	if (newmsgs) {
2758
	if (newmsgs) {
2759
		struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
2759
		struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
2760
		if (!vmu) {
2760
		if (!vmu) {
2761
			ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
2761
			ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
2762
			return -1;
2762
			return -1;
2763
		}
2763
		}
2764
		if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
2764
		if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
2765
			free_user(vmu);
2765
			free_user(vmu);
2766
			return -1;
2766
			return -1;
2767
		}
2767
		}
2768
		free_user(vmu);
2768
		free_user(vmu);
2769
	}
2769
	}
2770
	if (oldmsgs) {
2770
	if (oldmsgs) {
2771
		if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
2771
		if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
2772
			return -1;
2772
			return -1;
2773
		}
2773
		}
2774
	}
2774
	}
2775
	if (urgentmsgs) {
2775
	if (urgentmsgs) {
2776
		if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
2776
		if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
2777
			return -1;
2777
			return -1;
2778
		}
2778
		}
2779
	}
2779
	}
2780
	return 0;
2780
	return 0;
2781
}
2781
}
2782

    
   
2782

   
2783
/** 
2783
/** 
2784
 * \brief Determines if the given folder has messages.
2784
 * \brief Determines if the given folder has messages.
2785
 * \param mailbox The @ delimited string for user@context. If no context is found, uses 'default' for the context.
2785
 * \param mailbox The @ delimited string for user@context. If no context is found, uses 'default' for the context.
2786
 * \param folder the folder to look in
2786
 * \param folder the folder to look in
2787
 *
2787
 *
2788
 * This function is used when the mailbox is stored in an IMAP back end.
2788
 * This function is used when the mailbox is stored in an IMAP back end.
2789
 * This invokes the messagecount(). Here we are interested in the presence of messages (> 0) only, not the actual count.
2789
 * This invokes the messagecount(). Here we are interested in the presence of messages (> 0) only, not the actual count.
2790
 * \return 1 if the folder has one or more messages. zero otherwise.
2790
 * \return 1 if the folder has one or more messages. zero otherwise.
2791
 */
2791
 */
2792

    
   
2792

   
2793
static int has_voicemail(const char *mailbox, const char *folder)
2793
static int has_voicemail(const char *mailbox, const char *folder)
2794
{
2794
{
2795
	char tmp[256], *tmp2, *box, *context;
2795
	char tmp[256], *tmp2, *box, *context;
2796
	ast_copy_string(tmp, mailbox, sizeof(tmp));
2796
	ast_copy_string(tmp, mailbox, sizeof(tmp));
2797
	tmp2 = tmp;
2797
	tmp2 = tmp;
2798
	if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
2798
	if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
2799
		while ((box = strsep(&tmp2, ",&"))) {
2799
		while ((box = strsep(&tmp2, ",&"))) {
2800
			if (!ast_strlen_zero(box)) {
2800
			if (!ast_strlen_zero(box)) {
2801
				if (has_voicemail(box, folder)) {
2801
				if (has_voicemail(box, folder)) {
2802
					return 1;
2802
					return 1;
2803
				}
2803
				}
2804
			}
2804
			}
2805
		}
2805
		}
2806
	}
2806
	}
2807
	if ((context = strchr(tmp, '@'))) {
2807
	if ((context = strchr(tmp, '@'))) {
2808
		*context++ = '\0';
2808
		*context++ = '\0';
2809
	} else {
2809
	} else {
2810
		context = "default";
2810
		context = "default";
2811
	}
2811
	}
2812
	return __messagecount(context, tmp, folder) ? 1 : 0;
2812
	return __messagecount(context, tmp, folder) ? 1 : 0;
2813
}
2813
}
2814

    
   
2814

   
2815
/*!
2815
/*!
2816
 * \brief Copies a message from one mailbox to another.
2816
 * \brief Copies a message from one mailbox to another.
2817
 * \param chan
2817
 * \param chan
2818
 * \param vmu
2818
 * \param vmu
2819
 * \param imbox
2819
 * \param imbox
2820
 * \param msgnum
2820
 * \param msgnum
2821
 * \param duration
2821
 * \param duration
2822
 * \param recip
2822
 * \param recip
2823
 * \param fmt
2823
 * \param fmt
2824
 * \param dir
2824
 * \param dir
2825
 *
2825
 *
2826
 * This works with IMAP storage based mailboxes.
2826
 * This works with IMAP storage based mailboxes.
2827
 *
2827
 *
2828
 * \return zero on success, -1 on error.
2828
 * \return zero on success, -1 on error.
2829
 */
2829
 */
2830
static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, char *flag, const char *dest_folder)
2830
static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir, char *flag, const char *dest_folder)
2831
{
2831
{
2832
	struct vm_state *sendvms = NULL;
2832
	struct vm_state *sendvms = NULL;
2833
	char messagestring[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/
2833
	char messagestring[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/
2834
	if (msgnum >= recip->maxmsg) {
2834
	if (msgnum >= recip->maxmsg) {
2835
		ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
2835
		ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
2836
		return -1;
2836
		return -1;
2837
	}
2837
	}
2838
	if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
2838
	if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
2839
		ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
2839
		ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
2840
		return -1;
2840
		return -1;
2841
	}
2841
	}
2842
	if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
2842
	if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
2843
		ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
2843
		ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
2844
		return -1;
2844
		return -1;
2845
	}
2845
	}
2846
	snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
2846
	snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
2847
	ast_mutex_lock(&sendvms->lock);
2847
	ast_mutex_lock(&sendvms->lock);
2848
	if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
2848
	if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
2849
		ast_mutex_unlock(&sendvms->lock);
2849
		ast_mutex_unlock(&sendvms->lock);
2850
		return 0;
2850
		return 0;
2851
	}
2851
	}
2852
	ast_mutex_unlock(&sendvms->lock);
2852
	ast_mutex_unlock(&sendvms->lock);
2853
	ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
2853
	ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
2854
	return -1;
2854
	return -1;
2855
}
2855
}
2856

    
   
2856

   
2857
static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
2857
static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
2858
{
2858
{
2859
	char tmp[256], *t = tmp;
2859
	char tmp[256], *t = tmp;
2860
	size_t left = sizeof(tmp);
2860
	size_t left = sizeof(tmp);
2861
	
2861
	
2862
	if (box == OLD_FOLDER) {
2862
	if (box == OLD_FOLDER) {
2863
		ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
2863
		ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
2864
	} else {
2864
	} else {
2865
		ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
2865
		ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
2866
	}
2866
	}
2867

    
   
2867

   
2868
	if (box == NEW_FOLDER) {
2868
	if (box == NEW_FOLDER) {
2869
		ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
2869
		ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
2870
	} else {
2870
	} else {
2871
		snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
2871
		snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
2872
	}
2872
	}
2873

    
   
2873

   
2874
	/* Build up server information */
2874
	/* Build up server information */
2875
	ast_build_string(&t, &left, "{%s:%s/imap", S_OR(vms->imapserver, imapserver), S_OR(vms->imapport, imapport));
2875
	ast_build_string(&t, &left, "{%s:%s/imap", S_OR(vms->imapserver, imapserver), S_OR(vms->imapport, imapport));
2876

    
   
2876

   
2877
	/* Add authentication user if present */
2877
	/* Add authentication user if present */
2878
	if (!ast_strlen_zero(authuser))
2878
	if (!ast_strlen_zero(authuser))
2879
		ast_build_string(&t, &left, "/authuser=%s", authuser);
2879
		ast_build_string(&t, &left, "/authuser=%s", authuser);
2880

    
   
2880

   
2881
	/* Add flags if present */
2881
	/* Add flags if present */
2882
	if (!ast_strlen_zero(imapflags) || !(ast_strlen_zero(vms->imapflags))) {
2882
	if (!ast_strlen_zero(imapflags) || !(ast_strlen_zero(vms->imapflags))) {
2883
		ast_build_string(&t, &left, "/%s", S_OR(vms->imapflags, imapflags));
2883
		ast_build_string(&t, &left, "/%s", S_OR(vms->imapflags, imapflags));
2884
	}
2884
	}
2885

    
   
2885

   
2886
	/* End with username */
2886
	/* End with username */
2887
#if 1
2887
#if 1
2888
	ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
2888
	ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
2889
#else
2889
#else
2890
	ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
2890
	ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
2891
#endif
2891
#endif
2892
	if (box == NEW_FOLDER || box == OLD_FOLDER)
2892
	if (box == NEW_FOLDER || box == OLD_FOLDER)
2893
		snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
2893
		snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
2894
	else if (box == GREETINGS_FOLDER)
2894
	else if (box == GREETINGS_FOLDER)
2895
		snprintf(spec, len, "%s%s", tmp, greetingfolder);
2895
		snprintf(spec, len, "%s%s", tmp, greetingfolder);
2896
	else {	/* Other folders such as Friends, Family, etc... */
2896
	else {	/* Other folders such as Friends, Family, etc... */
2897
		if (!ast_strlen_zero(imapparentfolder)) {
2897
		if (!ast_strlen_zero(imapparentfolder)) {
2898
			/* imapparentfolder would typically be set to INBOX */
2898
			/* imapparentfolder would typically be set to INBOX */
2899
			snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
2899
			snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
2900
		} else {
2900
		} else {
2901
			snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
2901
			snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
2902
		}
2902
		}
2903
	}
2903
	}
2904
}
2904
}
2905

    
   
2905

   
2906
static int init_mailstream(struct vm_state *vms, int box)
2906
static int init_mailstream(struct vm_state *vms, int box)
2907
{
2907
{
2908
	MAILSTREAM *stream = NIL;
2908
	MAILSTREAM *stream = NIL;
2909
	long debug;
2909
	long debug;
2910
	char tmp[256];
2910
	char tmp[256];
2911

    
   
2911

   
2912
	if (!vms) {
2912
	if (!vms) {
2913
		ast_log(LOG_ERROR, "vm_state is NULL!\n");
2913
		ast_log(LOG_ERROR, "vm_state is NULL!\n");
2914
		return -1;
2914
		return -1;
2915
	}
2915
	}
2916
	ast_debug(3, "vm_state user is:%s\n", vms->imapuser);
2916
	ast_debug(3, "vm_state user is:%s\n", vms->imapuser);
2917
	if (vms->mailstream == NIL || !vms->mailstream) {
2917
	if (vms->mailstream == NIL || !vms->mailstream) {
2918
		ast_debug(1, "mailstream not set.\n");
2918
		ast_debug(1, "mailstream not set.\n");
2919
	} else {
2919
	} else {
2920
		stream = vms->mailstream;
2920
		stream = vms->mailstream;
2921
	}
2921
	}
2922
	/* debug = T;  user wants protocol telemetry? */
2922
	/* debug = T;  user wants protocol telemetry? */
2923
	debug = NIL;  /* NO protocol telemetry? */
2923
	debug = NIL;  /* NO protocol telemetry? */
2924

    
   
2924

   
2925
	if (delimiter == '\0') {		/* did not probe the server yet */
2925
	if (delimiter == '\0') {		/* did not probe the server yet */
2926
		char *cp;
2926
		char *cp;
2927
#ifdef USE_SYSTEM_IMAP
2927
#ifdef USE_SYSTEM_IMAP
2928
#include <imap/linkage.c>
2928
#include <imap/linkage.c>
2929
#elif defined(USE_SYSTEM_CCLIENT)
2929
#elif defined(USE_SYSTEM_CCLIENT)
2930
#include <c-client/linkage.c>
2930
#include <c-client/linkage.c>
2931
#else
2931
#else
2932
#include "linkage.c"
2932
#include "linkage.c"
2933
#endif
2933
#endif
2934
		/* Connect to INBOX first to get folders delimiter */
2934
		/* Connect to INBOX first to get folders delimiter */
2935
		imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
2935
		imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
2936
		ast_mutex_lock(&vms->lock);
2936
		ast_mutex_lock(&vms->lock);
2937
		stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
2937
		stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
2938
		ast_mutex_unlock(&vms->lock);
2938
		ast_mutex_unlock(&vms->lock);
2939
		if (stream == NIL) {
2939
		if (stream == NIL) {
2940
			ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
2940
			ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
2941
			return -1;
2941
			return -1;
2942
		}
2942
		}
2943
		get_mailbox_delimiter(vms, stream);
2943
		get_mailbox_delimiter(vms, stream);
2944
		/* update delimiter in imapfolder */
2944
		/* update delimiter in imapfolder */
2945
		for (cp = vms->imapfolder; *cp; cp++)
2945
		for (cp = vms->imapfolder; *cp; cp++)
2946
			if (*cp == '/')
2946
			if (*cp == '/')
2947
				*cp = delimiter;
2947
				*cp = delimiter;
2948
	}
2948
	}
2949
	/* Now connect to the target folder */
2949
	/* Now connect to the target folder */
2950
	imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
2950
	imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
2951
	ast_debug(3, "Before mail_open, server: %s, box:%d\n", tmp, box);
2951
	ast_debug(3, "Before mail_open, server: %s, box:%d\n", tmp, box);
2952
	ast_mutex_lock(&vms->lock);
2952
	ast_mutex_lock(&vms->lock);
2953
	vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
2953
	vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
2954
	ast_mutex_unlock(&vms->lock);
2954
	ast_mutex_unlock(&vms->lock);
2955
	if (vms->mailstream == NIL) {
2955
	if (vms->mailstream == NIL) {
2956
		return -1;
2956
		return -1;
2957
	} else {
2957
	} else {
2958
		return 0;
2958
		return 0;
2959
	}
2959
	}
2960
}
2960
}
2961

    
   
2961

   
2962
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
2962
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
2963
{
2963
{
2964
	SEARCHPGM *pgm;
2964
	SEARCHPGM *pgm;
2965
	SEARCHHEADER *hdr;
2965
	SEARCHHEADER *hdr;
2966
	int urgent = 0;
2966
	int urgent = 0;
2967

    
   
2967

   
2968
	/* If Urgent, then look at INBOX */
2968
	/* If Urgent, then look at INBOX */
2969
	if (box == 11) {
2969
	if (box == 11) {
2970
		box = NEW_FOLDER;
2970
		box = NEW_FOLDER;
2971
		urgent = 1;
2971
		urgent = 1;
2972
	}
2972
	}
2973

    
   
2973

   
2974
	ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
2974
	ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
2975
	ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
2975
	ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
2976
	ast_copy_string(vms->imapserver, vmu->imapserver, sizeof(vms->imapserver));
2976
	ast_copy_string(vms->imapserver, vmu->imapserver, sizeof(vms->imapserver));
2977
	ast_copy_string(vms->imapport, vmu->imapport, sizeof(vms->imapport));
2977
	ast_copy_string(vms->imapport, vmu->imapport, sizeof(vms->imapport));
2978
	ast_copy_string(vms->imapflags, vmu->imapflags, sizeof(vms->imapflags));
2978
	ast_copy_string(vms->imapflags, vmu->imapflags, sizeof(vms->imapflags));
2979
	vms->imapversion = vmu->imapversion;
2979
	vms->imapversion = vmu->imapversion;
2980
	ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
2980
	ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
2981

    
   
2981

   
2982
	if (init_mailstream(vms, box) || !vms->mailstream) {
2982
	if (init_mailstream(vms, box) || !vms->mailstream) {
2983
		ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
2983
		ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
2984
		return -1;
2984
		return -1;
2985
	}
2985
	}
2986

    
   
2986

   
2987
	create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
2987
	create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
2988

    
   
2988

   
2989
	/* Check Quota */
2989
	/* Check Quota */
2990
	if  (box == 0)  {
2990
	if  (box == 0)  {
2991
		ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
2991
		ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
2992
		check_quota(vms, (char *) mbox(vmu, box));
2992
		check_quota(vms, (char *) mbox(vmu, box));
2993
	}
2993
	}
2994

    
   
2994

   
2995
	ast_mutex_lock(&vms->lock);
2995
	ast_mutex_lock(&vms->lock);
2996
	pgm = mail_newsearchpgm();
2996
	pgm = mail_newsearchpgm();
2997

    
   
2997

   
2998
	/* Check IMAP folder for Asterisk messages only... */
2998
	/* Check IMAP folder for Asterisk messages only... */
2999
	hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
2999
	hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
3000
	hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
3000
	hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
3001
	pgm->header = hdr;
3001
	pgm->header = hdr;
3002
	pgm->deleted = 0;
3002
	pgm->deleted = 0;
3003
	pgm->undeleted = 1;
3003
	pgm->undeleted = 1;
3004

    
   
3004

   
3005
	/* if box = NEW_FOLDER, check for new, if box = OLD_FOLDER, check for read */
3005
	/* if box = NEW_FOLDER, check for new, if box = OLD_FOLDER, check for read */
3006
	if (box == NEW_FOLDER && urgent == 1) {
3006
	if (box == NEW_FOLDER && urgent == 1) {
3007
		pgm->unseen = 1;
3007
		pgm->unseen = 1;
3008
		pgm->seen = 0;
3008
		pgm->seen = 0;
3009
		pgm->flagged = 1;
3009
		pgm->flagged = 1;
3010
		pgm->unflagged = 0;
3010
		pgm->unflagged = 0;
3011
	} else if (box == NEW_FOLDER && urgent == 0) {
3011
	} else if (box == NEW_FOLDER && urgent == 0) {
3012
		pgm->unseen = 1;
3012
		pgm->unseen = 1;
3013
		pgm->seen = 0;
3013
		pgm->seen = 0;
3014
		pgm->flagged = 0;
3014
		pgm->flagged = 0;
3015
		pgm->unflagged = 1;
3015
		pgm->unflagged = 1;
3016
	} else if (box == OLD_FOLDER) {
3016
	} else if (box == OLD_FOLDER) {
3017
		pgm->seen = 1;
3017
		pgm->seen = 1;
3018
		pgm->unseen = 0;
3018
		pgm->unseen = 0;
3019
	}
3019
	}
3020

    
   
3020

   
3021
	ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
3021
	ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
3022

    
   
3022

   
3023
	vms->vmArrayIndex = 0;
3023
	vms->vmArrayIndex = 0;
3024
	mail_search_full (vms->mailstream, NULL, pgm, NIL);
3024
	mail_search_full (vms->mailstream, NULL, pgm, NIL);
3025
	vms->lastmsg = vms->vmArrayIndex - 1;
3025
	vms->lastmsg = vms->vmArrayIndex - 1;
3026
	mail_free_searchpgm(&pgm);
3026
	mail_free_searchpgm(&pgm);
3027
	/* Since IMAP storage actually stores both old and new messages in the same IMAP folder,
3027
	/* Since IMAP storage actually stores both old and new messages in the same IMAP folder,
3028
	 * ensure to allocate enough space to account for all of them. Warn if old messages
3028
	 * ensure to allocate enough space to account for all of them. Warn if old messages
3029
	 * have not been checked first as that is required.
3029
	 * have not been checked first as that is required.
3030
	 */
3030
	 */
3031
	if (box == 0 && !vms->dh_arraysize) {
3031
	if (box == 0 && !vms->dh_arraysize) {
3032
		ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
3032
		ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
3033
	}
3033
	}
3034
	if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
3034
	if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
3035
		ast_mutex_unlock(&vms->lock);
3035
		ast_mutex_unlock(&vms->lock);
3036
		return -1;
3036
		return -1;
3037
	}
3037
	}
3038

    
   
3038

   
3039
	ast_mutex_unlock(&vms->lock);
3039
	ast_mutex_unlock(&vms->lock);
3040
	return 0;
3040
	return 0;
3041
}
3041
}
3042

    
   
3042

   
3043
static void write_file(char *filename, char *buffer, unsigned long len)
3043
static void write_file(char *filename, char *buffer, unsigned long len)
3044
{
3044
{
3045
	FILE *output;
3045
	FILE *output;
3046

    
   
3046

   
3047
	output = fopen (filename, "w");
3047
	output = fopen (filename, "w");
3048
	if (fwrite(buffer, len, 1, output) != 1) {
3048
	if (fwrite(buffer, len, 1, output) != 1) {
3049
		if (ferror(output)) {
3049
		if (ferror(output)) {
3050
			ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
3050
			ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
3051
		}
3051
		}
3052
	}
3052
	}
3053
	fclose (output);
3053
	fclose (output);
3054
}
3054
}
3055

    
   
3055

   
3056
static void update_messages_by_imapuser(const char *user, unsigned long number)
3056
static void update_messages_by_imapuser(const char *user, unsigned long number)
3057
{
3057
{
3058
	struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
3058
	struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
3059

    
   
3059

   
3060
	if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
3060
	if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
3061
		return;
3061
		return;
3062
	}
3062
	}
3063

    
   
3063

   
3064
	ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
3064
	ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
3065
	vms->msgArray[vms->vmArrayIndex++] = number;
3065
	vms->msgArray[vms->vmArrayIndex++] = number;
3066
}
3066
}
3067

    
   
3067

   
3068
void mm_searched(MAILSTREAM *stream, unsigned long number)
3068
void mm_searched(MAILSTREAM *stream, unsigned long number)
3069
{
3069
{
3070
	char *mailbox = stream->mailbox, buf[1024] = "", *user;
3070
	char *mailbox = stream->mailbox, buf[1024] = "", *user;
3071

    
   
3071

   
3072
	if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
3072
	if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
3073
		return;
3073
		return;
3074

    
   
3074

   
3075
	update_messages_by_imapuser(user, number);
3075
	update_messages_by_imapuser(user, number);
3076
}
3076
}
3077

    
   
3077

   
3078
static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
3078
static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
3079
{
3079
{
3080
	struct ast_variable *var;
3080
	struct ast_variable *var;
3081
	struct ast_vm_user *vmu;
3081
	struct ast_vm_user *vmu;
3082

    
   
3082

   
3083
	vmu = ast_calloc(1, sizeof *vmu);
3083
	vmu = ast_calloc(1, sizeof *vmu);
3084
	if (!vmu)
3084
	if (!vmu)
3085
		return NULL;
3085
		return NULL;
3086

    
   
3086

   
3087
	populate_defaults(vmu);
3087
	populate_defaults(vmu);
3088
	ast_set_flag(vmu, VM_ALLOCED);
3088
	ast_set_flag(vmu, VM_ALLOCED);
3089

    
   
3089

   
3090
	var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
3090
	var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
3091
	if (var) {
3091
	if (var) {
3092
		apply_options_full(vmu, var);
3092
		apply_options_full(vmu, var);
3093
		ast_variables_destroy(var);
3093
		ast_variables_destroy(var);
3094
		return vmu;
3094
		return vmu;
3095
	} else {
3095
	} else {
3096
		ast_free(vmu);
3096
		ast_free(vmu);
3097
		return NULL;
3097
		return NULL;
3098
	}
3098
	}
3099
}
3099
}
3100

    
   
3100

   
3101
/* Interfaces to C-client */
3101
/* Interfaces to C-client */
3102

    
   
3102

   
3103
void mm_exists(MAILSTREAM * stream, unsigned long number)
3103
void mm_exists(MAILSTREAM * stream, unsigned long number)
3104
{
3104
{
3105
	/* mail_ping will callback here if new mail! */
3105
	/* mail_ping will callback here if new mail! */
3106
	ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
3106
	ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
3107
	if (number == 0) return;
3107
	if (number == 0) return;
3108
	set_update(stream);
3108
	set_update(stream);
3109
}
3109
}
3110

    
   
3110

   
3111

    
   
3111

   
3112
void mm_expunged(MAILSTREAM * stream, unsigned long number)
3112
void mm_expunged(MAILSTREAM * stream, unsigned long number)
3113
{
3113
{
3114
	/* mail_ping will callback here if expunged mail! */
3114
	/* mail_ping will callback here if expunged mail! */
3115
	ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
3115
	ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
3116
	if (number == 0) return;
3116
	if (number == 0) return;
3117
	set_update(stream);
3117
	set_update(stream);
3118
}
3118
}
3119

    
   
3119

   
3120

    
   
3120

   
3121
void mm_flags(MAILSTREAM * stream, unsigned long number)
3121
void mm_flags(MAILSTREAM * stream, unsigned long number)
3122
{
3122
{
3123
	/* mail_ping will callback here if read mail! */
3123
	/* mail_ping will callback here if read mail! */
3124
	ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
3124
	ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
3125
	if (number == 0) return;
3125
	if (number == 0) return;
3126
	set_update(stream);
3126
	set_update(stream);
3127
}
3127
}
3128

    
   
3128

   
3129

    
   
3129

   
3130
void mm_notify(MAILSTREAM * stream, char *string, long errflg)
3130
void mm_notify(MAILSTREAM * stream, char *string, long errflg)
3131
{
3131
{
3132
	ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
3132
	ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
3133
	mm_log (string, errflg);
3133
	mm_log (string, errflg);
3134
}
3134
}
3135

    
   
3135

   
3136

    
   
3136

   
3137
void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
3137
void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
3138
{
3138
{
3139
	if (delimiter == '\0') {
3139
	if (delimiter == '\0') {
3140
		delimiter = delim;
3140
		delimiter = delim;
3141
	}
3141
	}
3142

    
   
3142

   
3143
	ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
3143
	ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
3144
	if (attributes & LATT_NOINFERIORS)
3144
	if (attributes & LATT_NOINFERIORS)
3145
		ast_debug(5, "no inferiors\n");
3145
		ast_debug(5, "no inferiors\n");
3146
	if (attributes & LATT_NOSELECT)
3146
	if (attributes & LATT_NOSELECT)
3147
		ast_debug(5, "no select\n");
3147
		ast_debug(5, "no select\n");
3148
	if (attributes & LATT_MARKED)
3148
	if (attributes & LATT_MARKED)
3149
		ast_debug(5, "marked\n");
3149
		ast_debug(5, "marked\n");
3150
	if (attributes & LATT_UNMARKED)
3150
	if (attributes & LATT_UNMARKED)
3151
		ast_debug(5, "unmarked\n");
3151
		ast_debug(5, "unmarked\n");
3152
}
3152
}
3153

    
   
3153

   
3154

    
   
3154

   
3155
void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
3155
void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
3156
{
3156
{
3157
	ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
3157
	ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
3158
	if (attributes & LATT_NOINFERIORS)
3158
	if (attributes & LATT_NOINFERIORS)
3159
		ast_debug(5, "no inferiors\n");
3159
		ast_debug(5, "no inferiors\n");
3160
	if (attributes & LATT_NOSELECT)
3160
	if (attributes & LATT_NOSELECT)
3161
		ast_debug(5, "no select\n");
3161
		ast_debug(5, "no select\n");
3162
	if (attributes & LATT_MARKED)
3162
	if (attributes & LATT_MARKED)
3163
		ast_debug(5, "marked\n");
3163
		ast_debug(5, "marked\n");
3164
	if (attributes & LATT_UNMARKED)
3164
	if (attributes & LATT_UNMARKED)
3165
		ast_debug(5, "unmarked\n");
3165
		ast_debug(5, "unmarked\n");
3166
}
3166
}
3167

    
   
3167

   
3168

    
   
3168

   
3169
void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
3169
void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
3170
{
3170
{
3171
	ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
3171
	ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
3172
	if (status->flags & SA_MESSAGES)
3172
	if (status->flags & SA_MESSAGES)
3173
		ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
3173
		ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
3174
	if (status->flags & SA_RECENT)
3174
	if (status->flags & SA_RECENT)
3175
		ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
3175
		ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
3176
	if (status->flags & SA_UNSEEN)
3176
	if (status->flags & SA_UNSEEN)
3177
		ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
3177
		ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
3178
	if (status->flags & SA_UIDVALIDITY)
3178
	if (status->flags & SA_UIDVALIDITY)
3179
		ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
3179
		ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
3180
	if (status->flags & SA_UIDNEXT)
3180
	if (status->flags & SA_UIDNEXT)
3181
		ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
3181
		ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
3182
	ast_log(AST_LOG_NOTICE, "\n");
3182
	ast_log(AST_LOG_NOTICE, "\n");
3183
}
3183
}
3184

    
   
3184

   
3185

    
   
3185

   
3186
void mm_log(char *string, long errflg)
3186
void mm_log(char *string, long errflg)
3187
{
3187
{
3188
	switch ((short) errflg) {
3188
	switch ((short) errflg) {
3189
		case NIL:
3189
		case NIL:
3190
			ast_debug(1, "IMAP Info: %s\n", string);
3190
			ast_debug(1, "IMAP Info: %s\n", string);
3191
			break;
3191
			break;
3192
		case PARSE:
3192
		case PARSE:
3193
		case WARN:
3193
		case WARN:
3194
			ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
3194
			ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
3195
			break;
3195
			break;
3196
		case ERROR:
3196
		case ERROR:
3197
			ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
3197
			ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
3198
			break;
3198
			break;
3199
	}
3199
	}
3200
}
3200
}
3201

    
   
3201

   
3202

    
   
3202

   
3203
void mm_dlog(char *string)
3203
void mm_dlog(char *string)
3204
{
3204
{
3205
	ast_log(AST_LOG_NOTICE, "%s\n", string);
3205
	ast_log(AST_LOG_NOTICE, "%s\n", string);
3206
}
3206
}
3207

    
   
3207

   
3208

    
   
3208

   
3209
void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
3209
void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
3210
{
3210
{
3211
	struct ast_vm_user *vmu;
3211
	struct ast_vm_user *vmu;
3212

    
   
3212

   
3213
	ast_debug(4, "Entering callback mm_login\n");
3213
	ast_debug(4, "Entering callback mm_login\n");
3214

    
   
3214

   
3215
	ast_copy_string(user, mb->user, MAILTMPLEN);
3215
	ast_copy_string(user, mb->user, MAILTMPLEN);
3216

    
   
3216

   
3217
	/* We should only do this when necessary */
3217
	/* We should only do this when necessary */
3218
	if (!ast_strlen_zero(authpassword)) {
3218
	if (!ast_strlen_zero(authpassword)) {
3219
		ast_copy_string(pwd, authpassword, MAILTMPLEN);
3219
		ast_copy_string(pwd, authpassword, MAILTMPLEN);
3220
	} else {
3220
	} else {
3221
		AST_LIST_TRAVERSE(&users, vmu, list) {
3221
		AST_LIST_TRAVERSE(&users, vmu, list) {
3222
			if (!strcasecmp(mb->user, vmu->imapuser)) {
3222
			if (!strcasecmp(mb->user, vmu->imapuser)) {
3223
				ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
3223
				ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
3224
				break;
3224
				break;
3225
			}
3225
			}
3226
		}
3226
		}
3227
		if (!vmu) {
3227
		if (!vmu) {
3228
			if ((vmu = find_user_realtime_imapuser(mb->user))) {
3228
			if ((vmu = find_user_realtime_imapuser(mb->user))) {
3229
				ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
3229
				ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
3230
				free_user(vmu);
3230
				free_user(vmu);
3231
			}
3231
			}
3232
		}
3232
		}
3233
	}
3233
	}
3234
}
3234
}
3235

    
   
3235

   
3236

    
   
3236

   
3237
void mm_critical(MAILSTREAM * stream)
3237
void mm_critical(MAILSTREAM * stream)
3238
{
3238
{
3239
}
3239
}
3240

    
   
3240

   
3241

    
   
3241

   
3242
void mm_nocritical(MAILSTREAM * stream)
3242
void mm_nocritical(MAILSTREAM * stream)
3243
{
3243
{
3244
}
3244
}
3245

    
   
3245

   
3246

    
   
3246

   
3247
long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
3247
long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
3248
{
3248
{
3249
	kill (getpid (), SIGSTOP);
3249
	kill (getpid (), SIGSTOP);
3250
	return NIL;
3250
	return NIL;
3251
}
3251
}
3252

    
   
3252

   
3253

    
   
3253

   
3254
void mm_fatal(char *string)
3254
void mm_fatal(char *string)
3255
{
3255
{
3256
	ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
3256
	ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
3257
}
3257
}
3258

    
   
3258

   
3259
/* C-client callback to handle quota */
3259
/* C-client callback to handle quota */
3260
static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
3260
static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
3261
{
3261
{
3262
	struct vm_state *vms;
3262
	struct vm_state *vms;
3263
	char *mailbox = stream->mailbox, *user;
3263
	char *mailbox = stream->mailbox, *user;
3264
	char buf[1024] = "";
3264
	char buf[1024] = "";
3265
	unsigned long usage = 0, limit = 0;
3265
	unsigned long usage = 0, limit = 0;
3266

    
   
3266

   
3267
	while (pquota) {
3267
	while (pquota) {
3268
		usage = pquota->usage;
3268
		usage = pquota->usage;
3269
		limit = pquota->limit;
3269
		limit = pquota->limit;
3270
		pquota = pquota->next;
3270
		pquota = pquota->next;
3271
	}
3271
	}
3272

    
   
3272

   
3273
	if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
3273
	if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
3274
		ast_log(AST_LOG_ERROR, "No state found.\n");
3274
		ast_log(AST_LOG_ERROR, "No state found.\n");
3275
		return;
3275
		return;
3276
	}
3276
	}
3277

    
   
3277

   
3278
	ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
3278
	ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
3279

    
   
3279

   
3280
	vms->quota_usage = usage;
3280
	vms->quota_usage = usage;
3281
	vms->quota_limit = limit;
3281
	vms->quota_limit = limit;
3282
}
3282
}
3283

    
   
3283

   
3284
static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
3284
static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
3285
{
3285
{
3286
	char *start, *eol_pnt;
3286
	char *start, *eol_pnt;
3287
	int taglen;
3287
	int taglen;
3288

    
   
3288

   
3289
	if (ast_strlen_zero(header) || ast_strlen_zero(tag))
3289
	if (ast_strlen_zero(header) || ast_strlen_zero(tag))
3290
		return NULL;
3290
		return NULL;
3291

    
   
3291

   
3292
	taglen = strlen(tag) + 1;
3292
	taglen = strlen(tag) + 1;
3293
	if (taglen < 1)
3293
	if (taglen < 1)
3294
		return NULL;
3294
		return NULL;
3295

    
   
3295

   
3296
	if (!(start = strstr(header, tag)))
3296
	if (!(start = strstr(header, tag)))
3297
		return NULL;
3297
		return NULL;
3298

    
   
3298

   
3299
	/* Since we can be called multiple times we should clear our buffer */
3299
	/* Since we can be called multiple times we should clear our buffer */
3300
	memset(buf, 0, len);
3300
	memset(buf, 0, len);
3301

    
   
3301

   
3302
	ast_copy_string(buf, start+taglen, len);
3302
	ast_copy_string(buf, start+taglen, len);
3303
	if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
3303
	if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
3304
		*eol_pnt = '\0';
3304
		*eol_pnt = '\0';
3305
	return buf;
3305
	return buf;
3306
}
3306
}
3307

    
   
3307

   
3308
static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
3308
static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
3309
{
3309
{
3310
	char *start, *eol_pnt, *quote;
3310
	char *start, *eol_pnt, *quote;
3311

    
   
3311

   
3312
	if (ast_strlen_zero(mailbox))
3312
	if (ast_strlen_zero(mailbox))
3313
		return NULL;
3313
		return NULL;
3314

    
   
3314

   
3315
	if (!(start = strstr(mailbox, "/user=")))
3315
	if (!(start = strstr(mailbox, "/user=")))
3316
		return NULL;
3316
		return NULL;
3317

    
   
3317

   
3318
	ast_copy_string(buf, start+6, len);
3318
	ast_copy_string(buf, start+6, len);
3319

    
   
3319

   
3320
	if (!(quote = strchr(buf, '"'))) {
3320
	if (!(quote = strchr(buf, '"'))) {
3321
		if ((eol_pnt = strchr(buf, '/')) || (eol_pnt = strchr(buf, '}'))) {
3321
		if ((eol_pnt = strchr(buf, '/')) || (eol_pnt = strchr(buf, '}'))) {
3322
			*eol_pnt = '\0';
3322
			*eol_pnt = '\0';
3323
		}
3323
		}
3324
		return buf;
3324
		return buf;
3325
	} else {
3325
	} else {
3326
		if ((eol_pnt = strchr(quote + 1, '"'))) {
3326
		if ((eol_pnt = strchr(quote + 1, '"'))) {
3327
			*eol_pnt = '\0';
3327
			*eol_pnt = '\0';
3328
		}
3328
		}
3329
		return quote + 1;
3329
		return quote + 1;
3330
	}
3330
	}
3331
}
3331
}
3332

    
   
3332

   
3333
static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
3333
static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
3334
{
3334
{
3335
	struct vm_state *vms_p;
3335
	struct vm_state *vms_p;
3336

    
   
3336

   
3337
	pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3337
	pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3338
	if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
3338
	if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
3339
		return vms_p;
3339
		return vms_p;
3340
	}
3340
	}
3341
	ast_debug(5, "Adding new vmstate for %s\n", vmu->imapuser);
3341
	ast_debug(5, "Adding new vmstate for %s\n", vmu->imapuser);
3342
	if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
3342
	if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
3343
		return NULL;
3343
		return NULL;
3344
	ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
3344
	ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
3345
	ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
3345
	ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
3346
	ast_copy_string(vms_p->imapserver, vmu->imapserver, sizeof(vms_p->imapserver));
3346
	ast_copy_string(vms_p->imapserver, vmu->imapserver, sizeof(vms_p->imapserver));
3347
	ast_copy_string(vms_p->imapport, vmu->imapport, sizeof(vms_p->imapport));
3347
	ast_copy_string(vms_p->imapport, vmu->imapport, sizeof(vms_p->imapport));
3348
	ast_copy_string(vms_p->imapflags, vmu->imapflags, sizeof(vms_p->imapflags));
3348
	ast_copy_string(vms_p->imapflags, vmu->imapflags, sizeof(vms_p->imapflags));
3349
	ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username)); /* save for access from interactive entry point */
3349
	ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username)); /* save for access from interactive entry point */
3350
	ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
3350
	ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
3351
	vms_p->mailstream = NIL; /* save for access from interactive entry point */
3351
	vms_p->mailstream = NIL; /* save for access from interactive entry point */
3352
	vms_p->imapversion = vmu->imapversion;
3352
	vms_p->imapversion = vmu->imapversion;
3353
	ast_debug(5, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
3353
	ast_debug(5, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
3354
	vms_p->updated = 1;
3354
	vms_p->updated = 1;
3355
	/* set mailbox to INBOX! */
3355
	/* set mailbox to INBOX! */
3356
	ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
3356
	ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
3357
	init_vm_state(vms_p);
3357
	init_vm_state(vms_p);
3358
	vmstate_insert(vms_p);
3358
	vmstate_insert(vms_p);
3359
	return vms_p;
3359
	return vms_p;
3360
}
3360
}
3361

    
   
3361

   
3362
static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
3362
static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
3363
{
3363
{
3364
	struct vmstate *vlist = NULL;
3364
	struct vmstate *vlist = NULL;
3365

    
   
3365

   
3366
	if (interactive) {
3366
	if (interactive) {
3367
		struct vm_state *vms;
3367
		struct vm_state *vms;
3368
		pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3368
		pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3369
		vms = pthread_getspecific(ts_vmstate.key);
3369
		vms = pthread_getspecific(ts_vmstate.key);
3370
		return vms;
3370
		return vms;
3371
	}
3371
	}
3372

    
   
3372

   
3373
	AST_LIST_LOCK(&vmstates);
3373
	AST_LIST_LOCK(&vmstates);
3374
	AST_LIST_TRAVERSE(&vmstates, vlist, list) {
3374
	AST_LIST_TRAVERSE(&vmstates, vlist, list) {
3375
		if (!vlist->vms) {
3375
		if (!vlist->vms) {
3376
			ast_debug(3, "error: vms is NULL for %s\n", user);
3376
			ast_debug(3, "error: vms is NULL for %s\n", user);
3377
			continue;
3377
			continue;
3378
		}
3378
		}
3379
		if (vlist->vms->imapversion != imapversion) {
3379
		if (vlist->vms->imapversion != imapversion) {
3380
			continue;
3380
			continue;
3381
		}
3381
		}
3382
		if (!vlist->vms->imapuser) {
3382
		if (!vlist->vms->imapuser) {
3383
			ast_debug(3, "error: imapuser is NULL for %s\n", user);
3383
			ast_debug(3, "error: imapuser is NULL for %s\n", user);
3384
			continue;
3384
			continue;
3385
		}
3385
		}
3386

    
   
3386

   
3387
		if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3387
		if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3388
			AST_LIST_UNLOCK(&vmstates);
3388
			AST_LIST_UNLOCK(&vmstates);
3389
			return vlist->vms;
3389
			return vlist->vms;
3390
		}
3390
		}
3391
	}
3391
	}
3392
	AST_LIST_UNLOCK(&vmstates);
3392
	AST_LIST_UNLOCK(&vmstates);
3393

    
   
3393

   
3394
	ast_debug(3, "%s not found in vmstates\n", user);
3394
	ast_debug(3, "%s not found in vmstates\n", user);
3395

    
   
3395

   
3396
	return NULL;
3396
	return NULL;
3397
}
3397
}
3398

    
   
3398

   
3399
static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
3399
static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
3400
{
3400
{
3401

    
   
3401

   
3402
	struct vmstate *vlist = NULL;
3402
	struct vmstate *vlist = NULL;
3403
	const char *local_context = S_OR(context, "default");
3403
	const char *local_context = S_OR(context, "default");
3404

    
   
3404

   
3405
	if (interactive) {
3405
	if (interactive) {
3406
		struct vm_state *vms;
3406
		struct vm_state *vms;
3407
		pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3407
		pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3408
		vms = pthread_getspecific(ts_vmstate.key);
3408
		vms = pthread_getspecific(ts_vmstate.key);
3409
		return vms;
3409
		return vms;
3410
	}
3410
	}
3411

    
   
3411

   
3412
	AST_LIST_LOCK(&vmstates);
3412
	AST_LIST_LOCK(&vmstates);
3413
	AST_LIST_TRAVERSE(&vmstates, vlist, list) {
3413
	AST_LIST_TRAVERSE(&vmstates, vlist, list) {
3414
		if (!vlist->vms) {
3414
		if (!vlist->vms) {
3415
			ast_debug(3, "error: vms is NULL for %s\n", mailbox);
3415
			ast_debug(3, "error: vms is NULL for %s\n", mailbox);
3416
			continue;
3416
			continue;
3417
		}
3417
		}
3418
		if (vlist->vms->imapversion != imapversion) {
3418
		if (vlist->vms->imapversion != imapversion) {
3419
			continue;
3419
			continue;
3420
		}
3420
		}
3421
		if (!vlist->vms->username || !vlist->vms->context) {
3421
		if (!vlist->vms->username || !vlist->vms->context) {
3422
			ast_debug(3, "error: username is NULL for %s\n", mailbox);
3422
			ast_debug(3, "error: username is NULL for %s\n", mailbox);
3423
			continue;
3423
			continue;
3424
		}
3424
		}
3425

    
   
3425

   
3426
		ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
3426
		ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
3427

    
   
3427

   
3428
		if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3428
		if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3429
			ast_debug(3, "Found it!\n");
3429
			ast_debug(3, "Found it!\n");
3430
			AST_LIST_UNLOCK(&vmstates);
3430
			AST_LIST_UNLOCK(&vmstates);
3431
			return vlist->vms;
3431
			return vlist->vms;
3432
		}
3432
		}
3433
	}
3433
	}
3434
	AST_LIST_UNLOCK(&vmstates);
3434
	AST_LIST_UNLOCK(&vmstates);
3435

    
   
3435

   
3436
	ast_debug(3, "%s not found in vmstates\n", mailbox);
3436
	ast_debug(3, "%s not found in vmstates\n", mailbox);
3437

    
   
3437

   
3438
	return NULL;
3438
	return NULL;
3439
}
3439
}
3440

    
   
3440

   
3441
static void vmstate_insert(struct vm_state *vms)
3441
static void vmstate_insert(struct vm_state *vms)
3442
{
3442
{
3443
	struct vmstate *v;
3443
	struct vmstate *v;
3444
	struct vm_state *altvms;
3444
	struct vm_state *altvms;
3445

    
   
3445

   
3446
	/* If interactive, it probably already exists, and we should
3446
	/* If interactive, it probably already exists, and we should
3447
	   use the one we already have since it is more up to date.
3447
	   use the one we already have since it is more up to date.
3448
	   We can compare the username to find the duplicate */
3448
	   We can compare the username to find the duplicate */
3449
	if (vms->interactive == 1) {
3449
	if (vms->interactive == 1) {
3450
		altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
3450
		altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
3451
		if (altvms) {
3451
		if (altvms) {
3452
			ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
3452
			ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
3453
			vms->newmessages = altvms->newmessages;
3453
			vms->newmessages = altvms->newmessages;
3454
			vms->oldmessages = altvms->oldmessages;
3454
			vms->oldmessages = altvms->oldmessages;
3455
			vms->vmArrayIndex = altvms->vmArrayIndex;
3455
			vms->vmArrayIndex = altvms->vmArrayIndex;
3456
			vms->lastmsg = altvms->lastmsg;
3456
			vms->lastmsg = altvms->lastmsg;
3457
			vms->curmsg = altvms->curmsg;
3457
			vms->curmsg = altvms->curmsg;
3458
			/* get a pointer to the persistent store */
3458
			/* get a pointer to the persistent store */
3459
			vms->persist_vms = altvms;
3459
			vms->persist_vms = altvms;
3460
			/* Reuse the mailstream? */
3460
			/* Reuse the mailstream? */
3461
#ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3461
#ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3462
			vms->mailstream = altvms->mailstream;
3462
			vms->mailstream = altvms->mailstream;
3463
#else
3463
#else
3464
			vms->mailstream = NIL;
3464
			vms->mailstream = NIL;
3465
#endif
3465
#endif
3466
		}
3466
		}
3467
		return;
3467
		return;
3468
	}
3468
	}
3469

    
   
3469

   
3470
	if (!(v = ast_calloc(1, sizeof(*v))))
3470
	if (!(v = ast_calloc(1, sizeof(*v))))
3471
		return;
3471
		return;
3472

    
   
3472

   
3473
	v->vms = vms;
3473
	v->vms = vms;
3474

    
   
3474

   
3475
	ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3475
	ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3476

    
   
3476

   
3477
	AST_LIST_LOCK(&vmstates);
3477
	AST_LIST_LOCK(&vmstates);
3478
	AST_LIST_INSERT_TAIL(&vmstates, v, list);
3478
	AST_LIST_INSERT_TAIL(&vmstates, v, list);
3479
	AST_LIST_UNLOCK(&vmstates);
3479
	AST_LIST_UNLOCK(&vmstates);
3480
}
3480
}
3481

    
   
3481

   
3482
static void vmstate_delete(struct vm_state *vms)
3482
static void vmstate_delete(struct vm_state *vms)
3483
{
3483
{
3484
	struct vmstate *vc = NULL;
3484
	struct vmstate *vc = NULL;
3485
	struct vm_state *altvms = NULL;
3485
	struct vm_state *altvms = NULL;
3486

    
   
3486

   
3487
	/* If interactive, we should copy pertinent info
3487
	/* If interactive, we should copy pertinent info
3488
	   back to the persistent state (to make update immediate) */
3488
	   back to the persistent state (to make update immediate) */
3489
	if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3489
	if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3490
		ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
3490
		ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
3491
		altvms->newmessages = vms->newmessages;
3491
		altvms->newmessages = vms->newmessages;
3492
		altvms->oldmessages = vms->oldmessages;
3492
		altvms->oldmessages = vms->oldmessages;
3493
		altvms->updated = 1;
3493
		altvms->updated = 1;
3494
		vms->mailstream = mail_close(vms->mailstream);
3494
		vms->mailstream = mail_close(vms->mailstream);
3495

    
   
3495

   
3496
		/* Interactive states are not stored within the persistent list */
3496
		/* Interactive states are not stored within the persistent list */
3497
		return;
3497
		return;
3498
	}
3498
	}
3499

    
   
3499

   
3500
	ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3500
	ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3501

    
   
3501

   
3502
	AST_LIST_LOCK(&vmstates);
3502
	AST_LIST_LOCK(&vmstates);
3503
	AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
3503
	AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
3504
		if (vc->vms == vms) {
3504
		if (vc->vms == vms) {
3505
			AST_LIST_REMOVE_CURRENT(list);
3505
			AST_LIST_REMOVE_CURRENT(list);
3506
			break;
3506
			break;
3507
		}
3507
		}
3508
	}
3508
	}
3509
	AST_LIST_TRAVERSE_SAFE_END
3509
	AST_LIST_TRAVERSE_SAFE_END
3510
	AST_LIST_UNLOCK(&vmstates);
3510
	AST_LIST_UNLOCK(&vmstates);
3511
	
3511
	
3512
	if (vc) {
3512
	if (vc) {
3513
		ast_mutex_destroy(&vc->vms->lock);
3513
		ast_mutex_destroy(&vc->vms->lock);
3514
		ast_free(vc);
3514
		ast_free(vc);
3515
	}
3515
	}
3516
	else
3516
	else
3517
		ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3517
		ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3518
}
3518
}
3519

    
   
3519

   
3520
static void set_update(MAILSTREAM * stream)
3520
static void set_update(MAILSTREAM * stream)
3521
{
3521
{
3522
	struct vm_state *vms;
3522
	struct vm_state *vms;
3523
	char *mailbox = stream->mailbox, *user;
3523
	char *mailbox = stream->mailbox, *user;
3524
	char buf[1024] = "";
3524
	char buf[1024] = "";
3525

    
   
3525

   
3526
	if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
3526
	if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
3527
		if (user && option_debug > 2)
3527
		if (user && option_debug > 2)
3528
			ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
3528
			ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
3529
		return;
3529
		return;
3530
	}
3530
	}
3531

    
   
3531

   
3532
	ast_debug(3, "User %s mailbox set for update.\n", user);
3532
	ast_debug(3, "User %s mailbox set for update.\n", user);
3533

    
   
3533

   
3534
	vms->updated = 1; /* Set updated flag since mailbox changed */
3534
	vms->updated = 1; /* Set updated flag since mailbox changed */
3535
}
3535
}
3536

    
   
3536

   
3537
static void init_vm_state(struct vm_state *vms)
3537
static void init_vm_state(struct vm_state *vms)
3538
{
3538
{
3539
	int x;
3539
	int x;
3540
	vms->vmArrayIndex = 0;
3540
	vms->vmArrayIndex = 0;
3541
	for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
3541
	for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
3542
		vms->msgArray[x] = 0;
3542
		vms->msgArray[x] = 0;
3543
	}
3543
	}
3544
	ast_mutex_init(&vms->lock);
3544
	ast_mutex_init(&vms->lock);
3545
}
3545
}
3546

    
   
3546

   
3547
static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
3547
static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
3548
{
3548
{
3549
	char *body_content;
3549
	char *body_content;
3550
	char *body_decoded;
3550
	char *body_decoded;
3551
	char *fn = is_intro ? vms->introfn : vms->fn;
3551
	char *fn = is_intro ? vms->introfn : vms->fn;
3552
	unsigned long len;
3552
	unsigned long len;
3553
	unsigned long newlen;
3553
	unsigned long newlen;
3554
	char filename[256];
3554
	char filename[256];
3555

    
   
3555

   
3556
	if (!body || body == NIL)
3556
	if (!body || body == NIL)
3557
		return -1;
3557
		return -1;
3558

    
   
3558

   
3559
	ast_mutex_lock(&vms->lock);
3559
	ast_mutex_lock(&vms->lock);
3560
	body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
3560
	body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
3561
	ast_mutex_unlock(&vms->lock);
3561
	ast_mutex_unlock(&vms->lock);
3562
	if (body_content != NIL) {
3562
	if (body_content != NIL) {
3563
		snprintf(filename, sizeof(filename), "%s.%s", fn, format);
3563
		snprintf(filename, sizeof(filename), "%s.%s", fn, format);
3564
		/* ast_debug(1, body_content); */
3564
		/* ast_debug(1, body_content); */
3565
		body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
3565
		body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
3566
		/* If the body of the file is empty, return an error */
3566
		/* If the body of the file is empty, return an error */
3567
		if (!newlen) {
3567
		if (!newlen) {
3568
			return -1;
3568
			return -1;
3569
		}
3569
		}
3570
		write_file(filename, (char *) body_decoded, newlen);
3570
		write_file(filename, (char *) body_decoded, newlen);
3571
	} else {
3571
	} else {
3572
		ast_debug(5, "Body of message is NULL.\n");
3572
		ast_debug(5, "Body of message is NULL.\n");
3573
		return -1;
3573
		return -1;
3574
	}
3574
	}
3575
	return 0;
3575
	return 0;
3576
}
3576
}
3577

    
   
3577

   
3578
/*! 
3578
/*! 
3579
 * \brief Get delimiter via mm_list callback 
3579
 * \brief Get delimiter via mm_list callback 
3580
 * \param vms		The voicemail state object
3580
 * \param vms		The voicemail state object
3581
 * \param stream
3581
 * \param stream
3582
 *
3582
 *
3583
 * Determines the delimiter character that is used by the underlying IMAP based mail store.
3583
 * Determines the delimiter character that is used by the underlying IMAP based mail store.
3584
 */
3584
 */
3585
/* MUTEX should already be held */
3585
/* MUTEX should already be held */
3586
static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream) {
3586
static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream) {
3587
	char tmp[50];
3587
	char tmp[50];
3588
	snprintf(tmp, sizeof(tmp), "{%s}", S_OR(vms->imapserver, imapserver));
3588
	snprintf(tmp, sizeof(tmp), "{%s}", S_OR(vms->imapserver, imapserver));
3589
	mail_list(stream, tmp, "*");
3589
	mail_list(stream, tmp, "*");
3590
}
3590
}
3591

    
   
3591

   
3592
/*! 
3592
/*! 
3593
 * \brief Check Quota for user 
3593
 * \brief Check Quota for user 
3594
 * \param vms a pointer to a vm_state struct, will use the mailstream property of this.
3594
 * \param vms a pointer to a vm_state struct, will use the mailstream property of this.
3595
 * \param mailbox the mailbox to check the quota for.
3595
 * \param mailbox the mailbox to check the quota for.
3596
 *
3596
 *
3597
 * Calls imap_getquotaroot, which will populate its results into the vm_state vms input structure.
3597
 * Calls imap_getquotaroot, which will populate its results into the vm_state vms input structure.
3598
 */
3598
 */
3599
static void check_quota(struct vm_state *vms, char *mailbox) {
3599
static void check_quota(struct vm_state *vms, char *mailbox) {
3600
	ast_mutex_lock(&vms->lock);
3600
	ast_mutex_lock(&vms->lock);
3601
	mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
3601
	mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
3602
	ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
3602
	ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
3603
	if (vms && vms->mailstream != NULL) {
3603
	if (vms && vms->mailstream != NULL) {
3604
		imap_getquotaroot(vms->mailstream, mailbox);
3604
		imap_getquotaroot(vms->mailstream, mailbox);
3605
	} else {
3605
	} else {
3606
		ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
3606
		ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
3607
	}
3607
	}
3608
	ast_mutex_unlock(&vms->lock);
3608
	ast_mutex_unlock(&vms->lock);
3609
}
3609
}
3610

    
   
3610

   
3611
#endif /* IMAP_STORAGE */
3611
#endif /* IMAP_STORAGE */
3612

    
   
3612

   
3613
/*! \brief Lock file path
3613
/*! \brief Lock file path
3614
 * only return failure if ast_lock_path returns 'timeout',
3614
 * only return failure if ast_lock_path returns 'timeout',
3615
 * not if the path does not exist or any other reason
3615
 * not if the path does not exist or any other reason
3616
 */
3616
 */
3617
static int vm_lock_path(const char *path)
3617
static int vm_lock_path(const char *path)
3618
{
3618
{
3619
	switch (ast_lock_path(path)) {
3619
	switch (ast_lock_path(path)) {
3620
	case AST_LOCK_TIMEOUT:
3620
	case AST_LOCK_TIMEOUT:
3621
		return -1;
3621
		return -1;
3622
	default:
3622
	default:
3623
		return 0;
3623
		return 0;
3624
	}
3624
	}
3625
}
3625
}
3626

    
   
3626

   
3627
#define MSG_ID_LEN 256
3627
#define MSG_ID_LEN 256
3628

    
   
3628

   
3629
/* Used to attach a unique identifier to an msg_id */
3629
/* Used to attach a unique identifier to an msg_id */
3630
static int msg_id_incrementor;
3630
static int msg_id_incrementor;
3631

    
   
3631

   
3632
/*!
3632
/*!
3633
 * \brief Sets the destination string to a uniquely identifying msg_id string
3633
 * \brief Sets the destination string to a uniquely identifying msg_id string
3634
 * \param dst pointer to a character buffer that should contain MSG_ID_LEN characters.
3634
 * \param dst pointer to a character buffer that should contain MSG_ID_LEN characters.
3635
 */
3635
 */
3636
static void generate_msg_id(char *dst);
3636
static void generate_msg_id(char *dst);
3637

    
   
3637

   
3638
#ifdef ODBC_STORAGE
3638
#ifdef ODBC_STORAGE
3639
struct generic_prepare_struct {
3639
struct generic_prepare_struct {
3640
	char *sql;
3640
	char *sql;
3641
	int argc;
3641
	int argc;
3642
	char **argv;
3642
	char **argv;
3643
};
3643
};
3644

    
   
3644

   
3645
static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
3645
static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
3646
{
3646
{
3647
	struct generic_prepare_struct *gps = data;
3647
	struct generic_prepare_struct *gps = data;
3648
	int res, i;
3648
	int res, i;
3649
	SQLHSTMT stmt;
3649
	SQLHSTMT stmt;
3650

    
   
3650

   
3651
	res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
3651
	res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
3652
	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3652
	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3653
		ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
3653
		ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
3654
		return NULL;
3654
		return NULL;
3655
	}
3655
	}
3656
	res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
3656
	res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
3657
	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3657
	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3658
		ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
3658
		ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
3659
		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3659
		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3660
		return NULL;
3660
		return NULL;
3661
	}
3661
	}
3662
	for (i = 0; i < gps->argc; i++)
3662
	for (i = 0; i < gps->argc; i++)
3663
		SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
3663
		SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
3664

    
   
3664

   
3665
	return stmt;
3665
	return stmt;
3666
}
3666
}
3667

    
   
3667

   
3668
static void odbc_update_msg_id(char *dir, int msg_num, char *msg_id)
3668
static void odbc_update_msg_id(char *dir, int msg_num, char *msg_id)
3669
{
3669
{
3670
	SQLHSTMT stmt;
3670
	SQLHSTMT stmt;
3671
	char sql[PATH_MAX];
3671
	char sql[PATH_MAX];
3672
	struct odbc_obj *obj;
3672
	struct odbc_obj *obj;
3673
	char msg_num_str[20];
3673
	char msg_num_str[20];
3674
	char *argv[] = { msg_id, dir, msg_num_str };
3674
	char *argv[] = { msg_id, dir, msg_num_str };
3675
	struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
3675
	struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
3676

    
   
3676

   
3677
	obj = ast_odbc_request_obj(odbc_database, 0);
3677
	obj = ast_odbc_request_obj(odbc_database, 0);
3678
	if (!obj) {
3678
	if (!obj) {
3679
		ast_log(LOG_WARNING, "Unable to update message ID for message %d in %s\n", msg_num, dir);
3679
		ast_log(LOG_WARNING, "Unable to update message ID for message %d in %s\n", msg_num, dir);
3680
		return;
3680
		return;
3681
	}
3681
	}
3682

    
   
3682

   
3683
	snprintf(msg_num_str, sizeof(msg_num_str), "%d", msg_num);
3683
	snprintf(msg_num_str, sizeof(msg_num_str), "%d", msg_num);
3684
	snprintf(sql, sizeof(sql), "UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?", odbc_table);
3684
	snprintf(sql, sizeof(sql), "UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?", odbc_table);
3685
	stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
3685
	stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
3686
	if (!stmt) {
3686
	if (!stmt) {
3687
		ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
3687
		ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
3688
	} else {
3688
	} else {
3689
		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3689
		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3690
	}
3690
	}
3691
	ast_odbc_release_obj(obj);
3691
	ast_odbc_release_obj(obj);
3692
	return;
3692
	return;
3693
}
3693
}
3694

    
   
3694

   
3695
/*!
3695
/*!
3696
 * \brief Retrieves a file from an ODBC data store.
3696
 * \brief Retrieves a file from an ODBC data store.
3697
 * \param dir the path to the file to be retreived.
3697
 * \param dir the path to the file to be retreived.
3698
 * \param msgnum the message number, such as within a mailbox folder.
3698
 * \param msgnum the message number, such as within a mailbox folder.
3699
 * 
3699
 * 
3700
 * This method is used by the RETRIEVE macro when mailboxes are stored in an ODBC back end.
3700
 * This method is used by the RETRIEVE macro when mailboxes are stored in an ODBC back end.
3701
 * The purpose is to get the message from the database store to the local file system, so that the message may be played, or the information file may be read.
3701
 * The purpose is to get the message from the database store to the local file system, so that the message may be played, or the information file may be read.
3702
 *
3702
 *
3703
 * The file is looked up by invoking a SQL on the odbc_table (default 'voicemessages') using the dir and msgnum input parameters.
3703
 * The file is looked up by invoking a SQL on the odbc_table (default 'voicemessages') using the dir and msgnum input parameters.
3704
 * The output is the message information file with the name msgnum and the extension .txt
3704
 * The output is the message information file with the name msgnum and the extension .txt
3705
 * and the message file with the extension of its format, in the directory with base file name of the msgnum.
3705
 * and the message file with the extension of its format, in the directory with base file name of the msgnum.
3706
 * 
3706
 * 
3707
 * \return 0 on success, -1 on error.
3707
 * \return 0 on success, -1 on error.
3708
 */
3708
 */
3709
static int retrieve_file(char *dir, int msgnum)
3709
static int retrieve_file(char *dir, int msgnum)
3710
{
3710
{
3711
	int x = 0;
3711
	int x = 0;
3712
	int res;
3712
	int res;
3713
	int fd = -1;
3713
	int fd = -1;
3714
	size_t fdlen = 0;
3714
	size_t fdlen = 0;
3715
	void *fdm = MAP_FAILED;
3715
	void *fdm = MAP_FAILED;
3716
	SQLSMALLINT colcount = 0;
3716
	SQLSMALLINT colcount = 0;
3717
	SQLHSTMT stmt;
3717
	SQLHSTMT stmt;
3718
	char sql[PATH_MAX];
3718
	char sql[PATH_MAX];
3719
	char fmt[80]="";
3719
	char fmt[80]="";
3720
	char *c;
3720
	char *c;
3721
	char coltitle[256];
3721
	char coltitle[256];
3722
	SQLSMALLINT collen;
3722
	SQLSMALLINT collen;
3723
	SQLSMALLINT datatype;
3723
	SQLSMALLINT datatype;
3724
	SQLSMALLINT decimaldigits;
3724
	SQLSMALLINT decimaldigits;
3725
	SQLSMALLINT nullable;
3725
	SQLSMALLINT nullable;
3726
	SQLULEN colsize;
3726
	SQLULEN colsize;
3727
	SQLLEN colsize2;
3727
	SQLLEN colsize2;
3728
	FILE *f = NULL;
3728
	FILE *f = NULL;
3729
	char rowdata[80];
3729
	char rowdata[80];
3730
	char fn[PATH_MAX];
3730
	char fn[PATH_MAX];
3731
	char full_fn[PATH_MAX];
3731
	char full_fn[PATH_MAX];
3732
	char msgnums[80];
3732
	char msgnums[80];
3733
	char *argv[] = { dir, msgnums };
3733
	char *argv[] = { dir, msgnums };
3734
	struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
3734
	struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
3735

    
   
3735

   
3736
	struct odbc_obj *obj;
3736
	struct odbc_obj *obj;
3737
	obj = ast_odbc_request_obj(odbc_database, 0);
3737
	obj = ast_odbc_request_obj(odbc_database, 0);
3738
	if (obj) {
3738
	if (obj) {
3739
		ast_copy_string(fmt, vmfmts, sizeof(fmt));
3739
		ast_copy_string(fmt, vmfmts, sizeof(fmt));
3740
		c = strchr(fmt, '|');
3740
		c = strchr(fmt, '|');
3741
		if (c)
3741
		if (c)
3742
			*c = '\0';
3742
			*c = '\0';
3743
		if (!strcasecmp(fmt, "wav49"))
3743
		if (!strcasecmp(fmt, "wav49"))
3744
			strcpy(fmt, "WAV");
3744
			strcpy(fmt, "WAV");
3745
		snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
3745
		snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
3746
		if (msgnum > -1)
3746
		if (msgnum > -1)
3747
			make_file(fn, sizeof(fn), dir, msgnum);
3747
			make_file(fn, sizeof(fn), dir, msgnum);
3748
		else
3748
		else
3749
			ast_copy_string(fn, dir, sizeof(fn));
3749
			ast_copy_string(fn, dir, sizeof(fn));
3750

    
   
3750

   
3751
		/* Create the information file */
3751
		/* Create the information file */
3752
		snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
3752
		snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
3753
		
3753
		
3754
		if (!(f = fopen(full_fn, "w+"))) {
3754
		if (!(f = fopen(full_fn, "w+"))) {
3755
			ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
3755
			ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
3756
			goto yuck;
3756
			goto yuck;
3757
		}
3757
		}
3758
		
3758
		
3759
		snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
3759
		snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
3760
		snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
3760
		snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
3761
		stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
3761
		stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
3762
		if (!stmt) {
3762
		if (!stmt) {
3763
			ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
3763
			ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
3764
			ast_odbc_release_obj(obj);
3764
			ast_odbc_release_obj(obj);
3765
			goto yuck;
3765
			goto yuck;
3766
		}
3766
		}
3767
		res = SQLFetch(stmt);
3767
		res = SQLFetch(stmt);
3768
		if (res == SQL_NO_DATA) {
3768
		if (res == SQL_NO_DATA) {
3769
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3769
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3770
			ast_odbc_release_obj(obj);
3770
			ast_odbc_release_obj(obj);
3771
			goto yuck;
3771
			goto yuck;
3772
		} else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3772
		} else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3773
			ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
3773
			ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
3774
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3774
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3775
			ast_odbc_release_obj(obj);
3775
			ast_odbc_release_obj(obj);
3776
			goto yuck;
3776
			goto yuck;
3777
		}
3777
		}
3778
		fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
3778
		fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
3779
		if (fd < 0) {
3779
		if (fd < 0) {
3780
			ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
3780
			ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
3781
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3781
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3782
			ast_odbc_release_obj(obj);
3782
			ast_odbc_release_obj(obj);
3783
			goto yuck;
3783
			goto yuck;
3784
		}
3784
		}
3785
		res = SQLNumResultCols(stmt, &colcount);
3785
		res = SQLNumResultCols(stmt, &colcount);
3786
		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {	
3786
		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {	
3787
			ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
3787
			ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
3788
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3788
			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3789
			ast_odbc_release_obj(obj);
3789
			ast_odbc_release_obj(obj);
3790
			goto yuck;
3790
			goto yuck;
3791
		}
3791
		}
3792
		if (f) 
3792
		if (f) 
3793
			fprintf(f, "[message]\n");
3793
			fprintf(f, "[message]\n");
3794
		for (x = 0; x < colcount; x++) {
3794
		for (x = 0; x < colcount; x++) {
3795
			rowdata[0] = '\0';
3795
			rowdata[0] = '\0';
3796
			colsize = 0;
3796
			colsize = 0;
3797
			collen = sizeof(coltitle);
3797
			collen = sizeof(coltitle);
3798
			res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen, 
3798
			res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen, 
3799
						&datatype, &colsize, &decimaldigits, &nullable);
3799
						&datatype, &colsize, &decimaldigits, &nullable);
3800
			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3800
			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3801
				ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
3801
				ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
3802
				SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3802
				SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3803
				ast_odbc_release_obj(obj);
3803
				ast_odbc_release_obj(obj);
3804
				goto yuck;
3804
				goto yuck;
3805
			}
3805
			}
3806
			if (!strcasecmp(coltitle, "recording")) {
3806
			if (!strcasecmp(coltitle, "recording")) {
3807
				off_t offset;
3807
				off_t offset;
3808
				res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
3808
				res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
3809
				fdlen = colsize2;
3809
				fdlen = colsize2;
3810
				if (fd > -1) {
3810
				if (fd > -1) {
3811
					char tmp[1]="";
3811