/* Mutt's extensions.
   Copyright (C) 2003  Ludovic Courtès

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* Extension language support */

#ifndef __EXTENSION_H__
#define __EXTENSION_H__

/* So far, only Guile is supported.  */
/* #define GUILE 1 */

#include "mutt_menu.h"
#include "buffy.h"

/* Initialize the extention language system.  This function is expected to not
   return and call mutt_main () afterwards.  */
extern void mutt_init_extension (int argc, char *argv[]);

/* Load the user's configuration file FILE (which has to be written using the
   proper extension language).  If FILE is zero, then load a standard file
   from a standard location (which is extension-dependent).  */
extern int mutt_load_rc_file (const char *file);



/* Exported commands that should be bound by the extension language system
   (see extension.c).  */

/* Maximum size for an error message as returned by one of these functions */
#define ERRMSG_SIZE_MAX  (350)

/* Some built-in functions that need to be made available to the extension
   language.  */

/* Reads the specified initialization `muttrc-like' file.
   Returns -1 if errors were found so that we can pause to let the
   user know...  */
extern int builtin_source_rc_file (const char *rcfile, BUFFER *err);

/* Displays MESSAGE on the user-interface.  */
extern void builtin_ui_message (const char *message);

/* Displays MESSAGE on the user-interface.  */
extern void builtin_ui_error_message (const char *message);


/* The following hooks are called by C code instead of free () when the
   object's `extdata' field (extension language data) is not NULL.
   The extension language can in turn decide either to free () the
   object right now or delay its deletion until it is garbage
   collected.  */

extern void (*extension_free_body) (BODY *body);
extern void (*extension_free_header) (HEADER *header);
extern void (*extension_free_envelope) (ENVELOPE *envelope);
extern void (*extension_free_alias) (ALIAS *alias);
extern void (*extension_free_address) (ADDRESS *address);

/* Hook that gets called every time a timeout of $timeout seconds
   waiting for a keypress expires.  */
extern void (*extension_idle_hook) (void);


/* When GCC is being used, try to inline commands.  */
#ifdef __GNUC__
# define INLINE __inline__
#else
# define INLINE
#endif

/* Each Mutt command should have a `builtin' version (the one that really does
   the thing and that should be named "builtin-something" in the extension
   language) and an `command function' whose name starts with `cmd_'.  The
   command function is the only one which should be called directly is
   actually a wrapper of the extension language's version of the command.
   All it does is invoke the extension language's version of the command, which
   may in turn invoke the builtin function.  This whole thing is to oblige
   Mutt code to go through extension language code, which allows the user to
   customize any Mutt command.  */
#define MUTT_DECLARE_COMMAND(name, args) \
  extern INLINE int cmd_ ## name args ; \
  extern INLINE int builtin_ ## name args ; \
  extern INLINE int smutt_cmd_ ## name args

/* Convention: All these functions should return non-zero on failure,
   zero on success.  If an error message buffer has to be provided, it should
   be at least ERRMSG_SIZE_MAX long.  */

/* Parse muttrc line LINE (which is assumed to contained no newline
   character).  On success, return zero; otherwise, return -1 and fill
   ERRMSG with an appropriate error message.  */
MUTT_DECLARE_COMMAND (parse_rc_line,
		      (const char *line, char *errmsg));

/* Execute command FUNCTION with arguments ARGS that need to be further
   parsed.  On success, return zero.  If the command does not exist, return -1
   and fill ERRMSG with an appropriate error message.  */
MUTT_DECLARE_COMMAND (execute_command,
		      (const char *command, const char *args, char *errmsg));

/* Execute built-in function FUNCTION.  On success, return zero.
   If the function does not exist, return -1 and fill ERRMSG with an
   appropriate error message.  */
MUTT_DECLARE_COMMAND (execute_function,
		      (const char *function, char *errmsg));

/* Sets built-in variable VARIABLE to VALUE, a string describing its value.
   HINT may be one of M_SET_UNSET, M_SET_INV, M_SET_RESET, and VALUE may be an
   empty string if VARIABLE is a boolean variable.  On error, non-zero is
   returned and ERRMSG is filled with an error message.  */
MUTT_DECLARE_COMMAND (set_option,
		      (char *variable, char *value,
		       int hint, char *errmsg));

/* Fill in VALUE with a string representing the value of VARIABLE.  On error,
   non-zero is returned and ERRMSG contains an error message.  */
MUTT_DECLARE_COMMAND (query_option,
		      (char *value, char *variable, char *errmsg));

/* Create an alias called ALIAS_NAME for ADDRESS.  On success, set *ALIAS to
   point to the newly created alias.  Otherwise return -1 and fill ERRMSG with
   an error message.  */
MUTT_DECLARE_COMMAND (define_alias,
		      (const char *alias_name, ADDRESS *address,
		       ALIAS **alias, char *errmsg));

/* Append alias definition ALIAS to file FILENAME.  */
MUTT_DECLARE_COMMAND (save_alias,
		      (const ALIAS *alias, const char *filename,
		       char *errmsg));

/* On success, return zero and set *MESSAGEID to a newly allocated
   string containing a message ID.  */
MUTT_DECLARE_COMMAND (generate_message_id,
		      (char **messageid));

/* Display the message whose header is HEADER.  */
MUTT_DECLARE_COMMAND (display_message,
		      (HEADER *header));

/* As HEADER is being forwarded in context CONTEXT, set ENVELOPE's subject
   accordingly.  */
MUTT_DECLARE_COMMAND (make_forward_subject,
		      (ENVELOPE *envelope, CONTEXT *context, HEADER *header));

/* Computes HEADER's score and update it.  If UPDATE_CONTEXT is non-null, then
   CONTEXT should also be updated.  */
MUTT_DECLARE_COMMAND (score_message,
		      (CONTEXT *context, HEADER *header, int update_context));

/* Add a message scoring rule: messages matching PATTERN should be added
   VALUE.  On success, return zero and set NEWRULE to the new rule.  */
MUTT_DECLARE_COMMAND (add_scoring_rule,
		      (char *pattern, char *value,
		       SCORE **newrule, char *errmsg));

/* Compile STRING, a pattern description.  On success, *PATTERN points to the
   newly created pattern and zero is returned.  On failure, -1 is returned and
   ERRMSG is filled with an appropriate error message.  Optionnally, FLAGS may
   be equal to M_FULL_MSG, which means that PATTERN may apply to a whole
   header instead of just its "visible" fields (ie. to, from, subject).  */
MUTT_DECLARE_COMMAND (compile_pattern,
		      (pattern_t **pattern, char *string,
		       int flags, char *errmsg));

/* Execute PATTERN on HEADER.  If FLAGS equals to M_MATCH_FULL_ADDRESS, then
   both personal and machine addresses should match.  Returns a positive
   integer if HEADER matches.  */
MUTT_DECLARE_COMMAND (execute_pattern,
		      (pattern_t *pattern, HEADER *header,
		       CONTEXT *context, pattern_exec_flag flags));

/* If HEADER is non-null, save HEADER to mailbox (or file) MAILBOX.
   If HEADER is null, save all tagged messages to MAILBOX.
   If DELETE is non-zero, then delete HEADER afterwards; if DECODE is
   non-zero, the decode (what?); if DECRYPT is non-zero, then decrypt HEADER
   before saving it.  */
MUTT_DECLARE_COMMAND (save_message,
		      (HEADER *header, const char *mailbox,
		       int delete, int decode, int decrypt));

/* Return non-zero if ADDRESS is the address of a known mailing-list.  */
MUTT_DECLARE_COMMAND (is_mailing_list,
		      (ADDRESS *address));

/* Return non-zero if ADDRESS is the address of a subscribed mailing-list.  */
MUTT_DECLARE_COMMAND (is_subscribed_list,
		      (ADDRESS *address));

/* Return non-zero if ADDRESS is the user address.  */
MUTT_DECLARE_COMMAND (addr_is_user,
		      (ADDRESS *address));

/* Set ADDRESS to point to the default `from' address.  */
MUTT_DECLARE_COMMAND (default_from_address, (ADDRESS **address));

/* Jump to entry ENTRY in menu MENU.  On failure, return non-zero and fill
   ERRMSG with an appropriate error message.  */
MUTT_DECLARE_COMMAND (menu_jump,
		      (MUTTMENU *menu, unsigned int entry,
		       char *errmsg));

/* If HEADER is non-null, try to pipe message HEADER through COMMAND.
   If HEADER is null, try to pipe all tagged messages through COMMAND.
   If PRINT is set, consider that we are printing the message.  If DECODE is
   set, then PGP/Mime decode the message before piping it.  If SPLIT is set
   and HEADER is null, then messages should be piped one by one.  SEPARATOR is
   the string that should be inserted in between messages.  */
MUTT_DECLARE_COMMAND (pipe_message,
		      (HEADER *header, const char *command,
		       int print,
		       int decode, int split, const char *separator));

/* Send message HEADER.  */
MUTT_DECLARE_COMMAND (send_message,
		      (HEADER *header));

/* Fill REPLYENV, the envelope of a reply message to CURRENT and CURRENTENV
   (most of the time, CURRENTENV == CURRENT->ENV), with the appropriate
   subject.  */
MUTT_DECLARE_COMMAND (make_reply_header,
		      (ENVELOPE *replyenv, HEADER *current,
		       ENVELOPE *currentenv, CONTEXT *context));

/* Append a signature to open file FILE which represents MESSAGE.  */
MUTT_DECLARE_COMMAND (append_signature,
                      (FILE *file, HEADER *message));

/* Based on FOWARDED, a message to be fowarded, write to FILE an
   introduction to the fowarded email.  */
MUTT_DECLARE_COMMAND (append_forward_intro,
		      (FILE *file, HEADER *forwarded));

/* Based on FOWARDED, a message being forwarded, write to FILE the
   trailer of the fowarded email.  */
MUTT_DECLARE_COMMAND (append_forward_trailer,
		      (FILE *file, HEADER *forwarded));

/* Append to FILE email attribution for REPLIED.  */
MUTT_DECLARE_COMMAND (append_message_attribution,
		      (FILE *file, HEADER *replied, CONTEXT *context));

/* Append to FILE a body for MESSAGE which replies to REPLIED.  */
MUTT_DECLARE_COMMAND (generate_reply_body,
		      (FILE *file, HEADER *message,
		       CONTEXT *context, HEADER *replied));

/* Append to FILE a body for MESSAGE which forwards FORWARDED.  */
MUTT_DECLARE_COMMAND (generate_forward_body,
		      (FILE *file, HEADER *message,
		       CONTEXT *context, HEADER *forwarded));

/* Append to FILE the (quoted) body of REPLIED (including message
   attribution), a message being replied.  */
MUTT_DECLARE_COMMAND (include_reply_body,
		      (FILE *file, HEADER *replied,
		       CONTEXT *context));

/* Append to FILE a body representing a forward of FORWARDED
   (including forward intro and trailer).  */
MUTT_DECLARE_COMMAND (include_forward_body,
		      (FILE *file, HEADER *forwarded,
		       CONTEXT *context));

/* Add mailbox named NAME to the list of incoming mailboxes.  On success, zero
   is returned and MAILBOX points to the newly added mailbox.  */
MUTT_DECLARE_COMMAND (add_mailbox,
		      (BUFFY **mailbox, const char *name));

/* Remove MAILBOX from the list of incoming mailboxes.  On sucess, MAILBOX is
   not a valid pointer anymore once the function returned.  */
MUTT_DECLARE_COMMAND (remove_mailbox,
		      (BUFFY *mailbox));

/* Expand mailbox path PATH, a buffer of PATHLEN bytes.  */
MUTT_DECLARE_COMMAND (expand_path,
		      (char *path, size_t pathlen));

/* Quit the MUA.  This command gets executed everytime the user presses `q' or
   `ctrl-C'.  */
MUTT_DECLARE_COMMAND (query_exit, (void));

#endif
