mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
app: Fix for Doxygen.
ASTERISK-29752 Change-Id: If40cbd01d47a6cfd620b18206dedb8460216c8af
This commit is contained in:
committed by
Kevin Harwell
parent
244790e040
commit
14c309a6c5
@@ -42,7 +42,8 @@ AST_THREADSTORAGE_EXTERNAL(ast_str_thread_global_buf);
|
|||||||
/* IVR stuff */
|
/* IVR stuff */
|
||||||
|
|
||||||
/*! \brief Callback function for IVR
|
/*! \brief Callback function for IVR
|
||||||
\return returns 0 on completion, -1 on hangup or digit if interrupted
|
\retval 0 on completion.
|
||||||
|
\retval -1 on hangup or digit if interrupted.
|
||||||
*/
|
*/
|
||||||
typedef int (ast_ivr_callback)(struct ast_channel *chan, char *option, void *cbdata);
|
typedef int (ast_ivr_callback)(struct ast_channel *chan, char *option, void *cbdata);
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ typedef enum {
|
|||||||
AST_ACTION_MENU, /*!< adata is a pointer to an ast_ivr_menu */
|
AST_ACTION_MENU, /*!< adata is a pointer to an ast_ivr_menu */
|
||||||
AST_ACTION_REPEAT, /*!< adata is max # of repeats, cast to a pointer */
|
AST_ACTION_REPEAT, /*!< adata is max # of repeats, cast to a pointer */
|
||||||
AST_ACTION_RESTART, /*!< adata is like repeat, but resets repeats to 0 */
|
AST_ACTION_RESTART, /*!< adata is like repeat, but resets repeats to 0 */
|
||||||
AST_ACTION_TRANSFER, /*!< adata is a string with exten\verbatim[@context]\endverbatim */
|
AST_ACTION_TRANSFER, /*!< adata is a string with exten[\@context] */
|
||||||
AST_ACTION_WAITOPTION, /*!< adata is a timeout, or 0 for defaults */
|
AST_ACTION_WAITOPTION, /*!< adata is a timeout, or 0 for defaults */
|
||||||
AST_ACTION_NOOP, /*!< adata is unused */
|
AST_ACTION_NOOP, /*!< adata is unused */
|
||||||
AST_ACTION_BACKLIST, /*!< adata is list of files separated by ; allows interruption */
|
AST_ACTION_BACKLIST, /*!< adata is list of files separated by ; allows interruption */
|
||||||
@@ -118,7 +119,10 @@ enum ast_timelen {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief Runs an IVR menu
|
/*! \brief Runs an IVR menu
|
||||||
\return returns 0 on successful completion, -1 on hangup, or -2 on user error in menu */
|
\retval 0 on successful completion.
|
||||||
|
\retval -1 on hangup.
|
||||||
|
\retval -2 on user error in menu.
|
||||||
|
*/
|
||||||
int ast_ivr_menu_run(struct ast_channel *c, struct ast_ivr_menu *menu, void *cbdata);
|
int ast_ivr_menu_run(struct ast_channel *c, struct ast_ivr_menu *menu, void *cbdata);
|
||||||
|
|
||||||
/*! \brief Plays a stream and gets DTMF data from a channel
|
/*! \brief Plays a stream and gets DTMF data from a channel
|
||||||
@@ -234,7 +238,7 @@ struct ast_app_stack_funcs {
|
|||||||
* \details
|
* \details
|
||||||
* Fills in the optional context and exten from the given channel.
|
* Fills in the optional context and exten from the given channel.
|
||||||
*
|
*
|
||||||
* \retval New-args Gosub argument string on success. Must be freed.
|
* \return New-args Gosub argument string on success. Must be freed.
|
||||||
* \retval NULL on error.
|
* \retval NULL on error.
|
||||||
*/
|
*/
|
||||||
const char *(*expand_sub_args)(struct ast_channel *chan, const char *args);
|
const char *(*expand_sub_args)(struct ast_channel *chan, const char *args);
|
||||||
@@ -258,7 +262,7 @@ void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs);
|
|||||||
* \details
|
* \details
|
||||||
* Fills in the optional context and exten from the given channel.
|
* Fills in the optional context and exten from the given channel.
|
||||||
*
|
*
|
||||||
* \retval New-args Gosub argument string on success. Must be freed.
|
* \return New-args Gosub argument string on success. Must be freed.
|
||||||
* \retval NULL on error.
|
* \retval NULL on error.
|
||||||
*/
|
*/
|
||||||
const char *ast_app_expand_sub_args(struct ast_channel *chan, const char *args);
|
const char *ast_app_expand_sub_args(struct ast_channel *chan, const char *args);
|
||||||
@@ -351,7 +355,7 @@ typedef void (ast_vm_msg_play_cb)(struct ast_channel *chan, const char *playfile
|
|||||||
/*!
|
/*!
|
||||||
* \brief Determines if the given folder has messages.
|
* \brief Determines if the given folder has messages.
|
||||||
*
|
*
|
||||||
* \param mailboxes Comma or & delimited list of mailboxes (user@context).
|
* \param mailboxes Comma or & delimited list of mailboxes (user\@context).
|
||||||
* If no context is found, uses 'default' for the context.
|
* If no context is found, uses 'default' for the context.
|
||||||
* \param folder The folder to look in. Default is INBOX if not provided.
|
* \param folder The folder to look in. Default is INBOX if not provided.
|
||||||
*
|
*
|
||||||
@@ -363,7 +367,7 @@ typedef int (ast_has_voicemail_fn)(const char *mailboxes, const char *folder);
|
|||||||
/*!
|
/*!
|
||||||
* \brief Gets the number of messages that exist for the mailbox list.
|
* \brief Gets the number of messages that exist for the mailbox list.
|
||||||
*
|
*
|
||||||
* \param mailboxes Comma or space delimited list of mailboxes (user@context).
|
* \param mailboxes Comma or space delimited list of mailboxes (user\@context).
|
||||||
* If no context is found, uses 'default' for the context.
|
* If no context is found, uses 'default' for the context.
|
||||||
* \param newmsgs Where to put the count of new messages. (Can be NULL)
|
* \param newmsgs Where to put the count of new messages. (Can be NULL)
|
||||||
* \param oldmsgs Where to put the count of old messages. (Can be NULL)
|
* \param oldmsgs Where to put the count of old messages. (Can be NULL)
|
||||||
@@ -380,7 +384,7 @@ typedef int (ast_inboxcount_fn)(const char *mailboxes, int *newmsgs, int *oldmsg
|
|||||||
/*!
|
/*!
|
||||||
* \brief Gets the number of messages that exist for the mailbox list.
|
* \brief Gets the number of messages that exist for the mailbox list.
|
||||||
*
|
*
|
||||||
* \param mailboxes Comma or space delimited list of mailboxes (user@context).
|
* \param mailboxes Comma or space delimited list of mailboxes (user\@context).
|
||||||
* If no context is found, uses 'default' for the context.
|
* If no context is found, uses 'default' for the context.
|
||||||
* \param urgentmsgs Where to put the count of urgent messages. (Can be NULL)
|
* \param urgentmsgs Where to put the count of urgent messages. (Can be NULL)
|
||||||
* \param newmsgs Where to put the count of new messages. (Can be NULL)
|
* \param newmsgs Where to put the count of new messages. (Can be NULL)
|
||||||
@@ -415,7 +419,7 @@ typedef int (ast_messagecount_fn)(const char *mailbox_id, const char *folder);
|
|||||||
* \param mailbox_id The mailbox name.
|
* \param mailbox_id The mailbox name.
|
||||||
*
|
*
|
||||||
* \retval 0 Name played without interruption
|
* \retval 0 Name played without interruption
|
||||||
* \retval dtmf ASCII value of the DTMF which interrupted playback.
|
* \return dtmf ASCII value of the DTMF which interrupted playback.
|
||||||
* \retval -1 Unable to locate mailbox or hangup occurred.
|
* \retval -1 Unable to locate mailbox or hangup occurred.
|
||||||
*/
|
*/
|
||||||
typedef int (ast_sayname_fn)(struct ast_channel *chan, const char *mailbox_id);
|
typedef int (ast_sayname_fn)(struct ast_channel *chan, const char *mailbox_id);
|
||||||
@@ -444,8 +448,8 @@ typedef const char *(ast_vm_index_to_foldername_fn)(int id);
|
|||||||
/*!
|
/*!
|
||||||
* \brief Create a snapshot of a mailbox which contains information about every msg.
|
* \brief Create a snapshot of a mailbox which contains information about every msg.
|
||||||
*
|
*
|
||||||
* \param user The user part of user@context.
|
* \param user The user part of user\@context.
|
||||||
* \param context The context part of user@context. Must be explicit.
|
* \param context The context part of user\@context. Must be explicit.
|
||||||
* \param folder When not NULL only msgs from the specified folder will be included.
|
* \param folder When not NULL only msgs from the specified folder will be included.
|
||||||
* \param descending list the msgs in descending order rather than ascending order.
|
* \param descending list the msgs in descending order rather than ascending order.
|
||||||
* \param sort_val What to sort in the snapshot.
|
* \param sort_val What to sort in the snapshot.
|
||||||
@@ -455,7 +459,7 @@ typedef const char *(ast_vm_index_to_foldername_fn)(int id);
|
|||||||
*
|
*
|
||||||
* \note Only used by voicemail unit tests.
|
* \note Only used by voicemail unit tests.
|
||||||
*
|
*
|
||||||
* \retval snapshot on success
|
* \return snapshot on success
|
||||||
* \retval NULL on failure
|
* \retval NULL on failure
|
||||||
*/
|
*/
|
||||||
typedef struct ast_vm_mailbox_snapshot *(ast_vm_mailbox_snapshot_create_fn)(const char *user,
|
typedef struct ast_vm_mailbox_snapshot *(ast_vm_mailbox_snapshot_create_fn)(const char *user,
|
||||||
@@ -607,9 +611,7 @@ int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module
|
|||||||
/*!
|
/*!
|
||||||
* \brief Unregister the specified voicemail provider
|
* \brief Unregister the specified voicemail provider
|
||||||
*
|
*
|
||||||
* \param The module name of the provider to unregister
|
* \param module_name The module name of the provider to unregister
|
||||||
*
|
|
||||||
* \return Nothing
|
|
||||||
*/
|
*/
|
||||||
void ast_vm_unregister(const char *module_name);
|
void ast_vm_unregister(const char *module_name);
|
||||||
|
|
||||||
@@ -677,9 +679,7 @@ int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, s
|
|||||||
* \brief Unregister the specified voicemail greeter provider
|
* \brief Unregister the specified voicemail greeter provider
|
||||||
* \since 13.0.0
|
* \since 13.0.0
|
||||||
*
|
*
|
||||||
* \param The module name of the provider to unregister
|
* \param module_name The module name of the provider to unregister
|
||||||
*
|
|
||||||
* \return Nothing
|
|
||||||
*/
|
*/
|
||||||
void ast_vm_greeter_unregister(const char *module_name);
|
void ast_vm_greeter_unregister(const char *module_name);
|
||||||
|
|
||||||
@@ -732,7 +732,8 @@ int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs);
|
|||||||
* \param[out] urgentmsgs the urgent message count
|
* \param[out] urgentmsgs the urgent message count
|
||||||
* \param[out] newmsgs the new message count
|
* \param[out] newmsgs the new message count
|
||||||
* \param[out] oldmsgs the old message count
|
* \param[out] oldmsgs the old message count
|
||||||
* \return Returns 0 for success, negative upon error
|
* \retval 0 for success
|
||||||
|
* \retval negative upon error
|
||||||
* \since 1.6.1
|
* \since 1.6.1
|
||||||
*/
|
*/
|
||||||
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs);
|
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs);
|
||||||
@@ -771,15 +772,16 @@ const char *ast_vm_index_to_foldername(int id);
|
|||||||
/*!
|
/*!
|
||||||
* \brief Create a snapshot of a mailbox which contains information about every msg.
|
* \brief Create a snapshot of a mailbox which contains information about every msg.
|
||||||
*
|
*
|
||||||
* \param mailbox, the mailbox to look for
|
* \param mailbox the mailbox to look for
|
||||||
* \param context, the context to look for the mailbox in
|
* \param context the context to look for the mailbox in
|
||||||
* \param folder, OPTIONAL. When not NULL only msgs from the specified folder will be included.
|
* \param folder OPTIONAL. When not NULL only msgs from the specified folder will be included.
|
||||||
* \param descending, list the msgs in descending order rather than ascending order.
|
* \param descending list the msgs in descending order rather than ascending order.
|
||||||
* \param combine_INBOX_and_OLD, When this argument is set, The OLD folder will be represented
|
* \param sort_val What to sort in the snapshot.
|
||||||
|
* \param combine_INBOX_and_OLD When this argument is set, The OLD folder will be represented
|
||||||
* in the INBOX folder of the snapshot. This allows the snapshot to represent the
|
* in the INBOX folder of the snapshot. This allows the snapshot to represent the
|
||||||
* OLD and INBOX messages in sorted order merged together.
|
* OLD and INBOX messages in sorted order merged together.
|
||||||
*
|
*
|
||||||
* \retval snapshot on success
|
* \return snapshot on success
|
||||||
* \retval NULL on failure
|
* \retval NULL on failure
|
||||||
*/
|
*/
|
||||||
struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_create(const char *mailbox,
|
struct ast_vm_mailbox_snapshot *ast_vm_mailbox_snapshot_create(const char *mailbox,
|
||||||
@@ -980,8 +982,6 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
|
|||||||
*
|
*
|
||||||
* \pre This must only be called by threads that are not the channel's
|
* \pre This must only be called by threads that are not the channel's
|
||||||
* media handler thread.
|
* media handler thread.
|
||||||
*
|
|
||||||
* \return Nothing
|
|
||||||
*/
|
*/
|
||||||
void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration);
|
void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration);
|
||||||
|
|
||||||
@@ -1405,7 +1405,8 @@ struct ast_app_option {
|
|||||||
\param flags The flag structure to have option flags set
|
\param flags The flag structure to have option flags set
|
||||||
\param args The array of argument pointers to hold arguments found
|
\param args The array of argument pointers to hold arguments found
|
||||||
\param optstr The string containing the options to be parsed
|
\param optstr The string containing the options to be parsed
|
||||||
\return zero for success, non-zero if an error occurs
|
\retval zero for success
|
||||||
|
\retval non-zero if an error occurs
|
||||||
\sa AST_APP_OPTIONS
|
\sa AST_APP_OPTIONS
|
||||||
*/
|
*/
|
||||||
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr);
|
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr);
|
||||||
@@ -1416,7 +1417,8 @@ int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags
|
|||||||
\param flags The 64-bit flag structure to have option flags set
|
\param flags The 64-bit flag structure to have option flags set
|
||||||
\param args The array of argument pointers to hold arguments found
|
\param args The array of argument pointers to hold arguments found
|
||||||
\param optstr The string containing the options to be parsed
|
\param optstr The string containing the options to be parsed
|
||||||
\return zero for success, non-zero if an error occurs
|
\retval zero for success
|
||||||
|
\retval non-zero if an error occurs
|
||||||
\sa AST_APP_OPTIONS
|
\sa AST_APP_OPTIONS
|
||||||
*/
|
*/
|
||||||
int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr);
|
int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr);
|
||||||
@@ -1430,7 +1432,9 @@ int ast_app_parse_options64(const struct ast_app_option *options, struct ast_fla
|
|||||||
void ast_app_options2str64(const struct ast_app_option *options, struct ast_flags64 *flags, char *buf, size_t len);
|
void ast_app_options2str64(const struct ast_app_option *options, struct ast_flags64 *flags, char *buf, size_t len);
|
||||||
|
|
||||||
/*! \brief Present a dialtone and collect a certain length extension.
|
/*! \brief Present a dialtone and collect a certain length extension.
|
||||||
\return Returns 1 on valid extension entered, -1 on hangup, or 0 on invalid extension.
|
\retval 1 if extension exists
|
||||||
|
\retval 0 if extension does not exist
|
||||||
|
\retval -1 on hangup
|
||||||
\note Note that if 'collect' holds digits already, new digits will be appended, so be sure it's initialized properly */
|
\note Note that if 'collect' holds digits already, new digits will be appended, so be sure it's initialized properly */
|
||||||
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout);
|
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout);
|
||||||
|
|
||||||
@@ -1492,7 +1496,7 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Get the \ref stasis topic for queue messages
|
* \brief Get the \ref stasis topic for queue messages
|
||||||
* \retval The topic structure for queue messages
|
* \return The topic structure for queue messages
|
||||||
* \retval NULL if it has not been allocated
|
* \retval NULL if it has not been allocated
|
||||||
* \since 12
|
* \since 12
|
||||||
*/
|
*/
|
||||||
@@ -1501,7 +1505,7 @@ struct stasis_topic *ast_queue_topic_all(void);
|
|||||||
/*!
|
/*!
|
||||||
* \brief Get the \ref stasis topic for queue messages for a particular queue name
|
* \brief Get the \ref stasis topic for queue messages for a particular queue name
|
||||||
* \param queuename The name for which to get the topic
|
* \param queuename The name for which to get the topic
|
||||||
* \retval The topic structure for queue messages for a given name
|
* \return The topic structure for queue messages for a given name
|
||||||
* \retval NULL if it failed to be found or allocated
|
* \retval NULL if it failed to be found or allocated
|
||||||
* \since 12
|
* \since 12
|
||||||
*/
|
*/
|
||||||
|
28
main/app.c
28
main/app.c
@@ -132,8 +132,6 @@ static AST_RWLIST_HEAD_STATIC(groups, ast_group_info);
|
|||||||
* \param size
|
* \param size
|
||||||
* \param maxlen
|
* \param maxlen
|
||||||
* \param timeout timeout in milliseconds
|
* \param timeout timeout in milliseconds
|
||||||
*
|
|
||||||
* \return 0 if extension does not exist, 1 if extension exists
|
|
||||||
*/
|
*/
|
||||||
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
|
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
|
||||||
{
|
{
|
||||||
@@ -185,30 +183,11 @@ int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief ast_app_getdata
|
|
||||||
* \param c The channel to read from
|
|
||||||
* \param prompt The file to stream to the channel
|
|
||||||
* \param s The string to read in to. Must be at least the size of your length
|
|
||||||
* \param maxlen How many digits to read (maximum)
|
|
||||||
* \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
|
|
||||||
* "ludicrous time" (essentially never times out)
|
|
||||||
*/
|
|
||||||
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
|
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
|
||||||
{
|
{
|
||||||
return ast_app_getdata_terminator(c, prompt, s, maxlen, timeout, NULL);
|
return ast_app_getdata_terminator(c, prompt, s, maxlen, timeout, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief ast_app_getdata
|
|
||||||
* \param c The channel to read from
|
|
||||||
* \param prompt The file to stream to the channel
|
|
||||||
* \param s The string to read in to. Must be at least the size of your length
|
|
||||||
* \param maxlen How many digits to read (maximum)
|
|
||||||
* \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
|
|
||||||
* "ludicrous time" (essentially never times out)
|
|
||||||
* \param terminator A string of characters that may be used as terminators to end input. Default if NULL is "#"
|
|
||||||
*/
|
|
||||||
enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s,
|
enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s,
|
||||||
int maxlen, int timeout, char *terminator)
|
int maxlen, int timeout, char *terminator)
|
||||||
{
|
{
|
||||||
@@ -1424,11 +1403,11 @@ int ast_play_and_wait(struct ast_channel *chan, const char *fn)
|
|||||||
/*!
|
/*!
|
||||||
* \brief Construct a silence frame of the same duration as \a orig.
|
* \brief Construct a silence frame of the same duration as \a orig.
|
||||||
*
|
*
|
||||||
* The \a orig frame must be \ref AST_FORMAT_SLINEAR.
|
* The \a orig frame must be \ref ast_format_slin.
|
||||||
*
|
*
|
||||||
* \param orig Frame as basis for silence to generate.
|
* \param orig Frame as basis for silence to generate.
|
||||||
* \return New frame of silence; free with ast_frfree().
|
* \return New frame of silence; free with ast_frfree().
|
||||||
* \return \c NULL on error.
|
* \retval NULL on error.
|
||||||
*/
|
*/
|
||||||
static struct ast_frame *make_silence(const struct ast_frame *orig)
|
static struct ast_frame *make_silence(const struct ast_frame *orig)
|
||||||
{
|
{
|
||||||
@@ -1473,7 +1452,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets a channel's read format to \ref AST_FORMAT_SLINEAR, recording
|
* \brief Sets a channel's read format to \ref ast_format_slin, recording
|
||||||
* its original format.
|
* its original format.
|
||||||
*
|
*
|
||||||
* \param chan Channel to modify.
|
* \param chan Channel to modify.
|
||||||
@@ -1510,6 +1489,7 @@ static int global_maxsilence = 0;
|
|||||||
* \param acceptdtmf DTMF digits that will end the recording.
|
* \param acceptdtmf DTMF digits that will end the recording.
|
||||||
* \param canceldtmf DTMF digits that will cancel the recording.
|
* \param canceldtmf DTMF digits that will cancel the recording.
|
||||||
* \param skip_confirmation_sound If true, don't play auth-thankyou at end. Nice for custom recording prompts in apps.
|
* \param skip_confirmation_sound If true, don't play auth-thankyou at end. Nice for custom recording prompts in apps.
|
||||||
|
* \param if_exists
|
||||||
*
|
*
|
||||||
* \retval -1 failure or hangup
|
* \retval -1 failure or hangup
|
||||||
* \retval 'S' Recording ended from silence timeout
|
* \retval 'S' Recording ended from silence timeout
|
||||||
|
Reference in New Issue
Block a user