/** BEGIN COPYRIGHT BLOCK
 * Copyright (C) 2001 Sun Microsystems, Inc.  Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 *
 * 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; version 2
 * of the License.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * END COPYRIGHT BLOCK **/
/* 
 * libadmin.h - All functions contained in libadmin.a
 *
 * All blame goes to Mike McCool
 */

#ifndef	libadmin_h
#define	libadmin_h

#include <stdio.h>

#include "base/systems.h"
#include "base/util.h"
 
#ifdef XP_UNIX
#include <unistd.h>
#else /* XP_WIN32 */
#include <winsock.h>
#endif /* XP_WIN32 */

#include "prinit.h"
#include "prthread.h"
#include "prlong.h"

#define NSPR_INIT(Program) (PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 8))

#undef howmany

NSPR_BEGIN_EXTERN_C

#ifdef XP_UNIX
#define FILE_PATHSEP '/'
#define OPEN_MODE "r"
#define QUOTE ""
#define CONVERT_TO_NATIVE_FS(Filename)
#define CONVERT_TO_HTTP_FORMAT(Filename)
#define WSACleanup()

#define GET_QUERY_STRING() (getenv("QUERY_STRING"))
#define NOT_ABSOLUTE_PATH(str) (str[0] != '/')
#define CREATE_DIRECTORY(Directory)

#else /* XP_WIN32 */
#define verify_adm_dbm
#define add_user_dbm
#define find_user_dbm
#define list_users_dbm
#define modify_user_dbm
#define remove_user_dbm
#define dbm_open
#define dbm_close
#define dbm_store
#define lstat stat
#define popen _popen
#define pclose _pclose

#define CONVERT_TO_NATIVE_FS(Filename) 	   \
{									   	   \
	register char *s;				   	   \
	if (Filename)						   \
		for (s = Filename; *s; s++) 	   \
			if ( *s	== '/')				   \
				*s = '\\';				   \
}									 
#define CONVERT_TO_HTTP_FORMAT(Filename) 	\
{									   		\
	register char *s;					   	\
	if (Filename)				   			\
	for (s = Filename; *s; s++) 	   		\
		if ( *s	== '\\')				   	\
			*s = '/';				   		\
}									 
#define FILE_PATHSEP '/'
#define OPEN_MODE "r+b"
#define QUOTE "\""

#ifdef GET_QUERY_STRING
#undef GET_QUERY_STRING
#endif
#define GET_QUERY_STRING() (GetQueryNT())

/* Defined in util.c */
NSAPI_PUBLIC char *GetQueryNT(void);
#define NOT_ABSOLUTE_PATH(str) \
  ((str[0] != '/') && (str[0] != '\\') && (str[2] != '/') && (str[2] != '\\'))

#define CREATE_DIRECTORY(Directory) CreateDirectory(Directory, NULL)

#endif /* XP_WIN32 */


/* error types */
#define FILE_ERROR 0
#define MEMORY_ERROR 1
#define SYSTEM_ERROR 2
#define INCORRECT_USAGE 3
#define ELEM_MISSING 4
#define REGISTRY_DATABASE_ERROR 5
#define NETWORK_ERROR 6
#define GENERAL_FAILURE 7
#define WARNING 8

/* The upper bound on error types */
#define MAX_ERROR 9

/* The default error type (in case something goes wrong */
#define DEFAULT_ERROR 3

/* The change types for admin logging */
#define TO_STATUS "status"
#define TO_ADMIN "admserv"
#define TO_USERDB "userdb"
#define TO_SEC "security"
#define TO_BACKUP "backup"
#define TO_CACHE "cache"
#define TO_BUCONF "bu.conf"
#define TO_LDAP "ldap"

/* The indexes for conf file backup purposes */ 
#define BK_MAGNUS 0
#define BK_OBJ 1
#define BK_MIMETYPES 2
#define BK_BU 3
#define BK_ACLFILE 4     

/* The extension for backup files to use.  Emacs weenies like "%s.~%d~" */
/* But real vi men like this one */
#define BACKUP_EXT "%s.v%d"
/* Need also a way to identify the backup files when we're doing an ls */
#define BACKUP_SHORT ".v"

/* Frame window names. */
#define INDEX_NAME "index"
#define MESSAGE_NAME "msgs"
#define TOP_NAME "tabs"
#define BOTTOM_NAME "category"
#define OPTIONS_NAME "options"
#define CONTENT_NAME "content"
#define COPY_NAME "copy"

#define INFO_IDX_NAME "infowin"
#define INFO_TOPIC_NAME "infotopic"
#define HELP_WIN_OPTIONS "'scrollbars=yes,resizable=1,width=500,height=500'"

/* Resource types */
#define NAME "name"
#define FILE_OR_DIR "path"
#define TEMPLATE "tmpl"
#define WILDCARD "wild"

/* A really big form line */
#define BIG_LINE 1024

/* Max size for a pathname */
#ifndef PATH_MAX
#define PATH_MAX 256
#endif


/* Boundary string for uploading / downloading config files. */
#define CF_BOUNDARY  "--Config_File_Boundary--"
#define CF_NEWCONFIG "--NewConfigFile:"
#define CF_MTIME "--LastMod:"
#define CF_ERRSTR "--Error: "
#define CFTRANS_BIN "bin/cftrans"
#define CF_REMOTE_URL "#RemoteUrl "
 
#define HTML_ERRCOLOR "#AA0000"

#define MOCHA_NAME "javascript"

/* Internationalization stuffs.  If we define MSG_RETURN, then create a 
 * function which will return a string of the given identifier.  If we 
 * define MSG_DBM, it creates a function you can call to create the DBM
 * properly.  Finally, if nothing else, it will create a mapping from 
 * the string's name to its proper ID number. */
/* store_msg is in mkdbm.c, in the admin stuff */
/* get_msg.c */
NSAPI_PUBLIC char *get_msg(int msgid);
NSAPI_PUBLIC void store_msg(int msgid, char *msg);
 
#if defined(MSG_RETURN)
#define BGN_MSG(arg) static char *(arg)(int i)  { switch(i)  {
#define STR(name, id, msg) case (id): return(msg);
#define END_MSG(arg) } return 0; }
 
#elif defined(MSG_DBM)
#define BGN_MSG(arg) void (arg)()  {
#define STR(name, id, msg)  store_msg(id, msg);
#define END_MSG(arg) }
 
#else
#define BGN_MSG(arg) enum {
#define STR(name, id, msg)    name=id,
#define END_MSG(arg) arg=0 };
#endif
 
/* The files where the messages are kept. */
#define LA_BASE 1000
#define LA_BASE_END 1999
#define LA_DBM_LOC "./la_msgs"
 
#define HADM_BASE 2000
#define HADM_BASE_END 5999
#define HADM_DBM_LOC "./hadm_msgs"
 
#include "la_msgs.i"
#include "hadm_msgs.i"
 
/* Open a .html file to parse it.  Returns a file ptr (simple fn, really) */
/* error one doesn't call report_error so we lose the infinite loop prob */
/* form_get.c */
NSAPI_PUBLIC FILE *open_html_file(char *filename);
NSAPI_PUBLIC FILE *open_error_file(char *filename);

/* Same as open_html_file, but opens the html file from the specified */
/* language subdirectory, if available, else from the default language */
/* subdirectory. */
/* form_get.c */
NSAPI_PUBLIC FILE* open_html_file_lang(char* filename,char* language);

/* Parse an HTML file and return it to the client.  */
/* form_get.c */
NSAPI_PUBLIC void return_html_file(char *filename);

/* Parse an HTML file, return it to the client, but don't set the referer */
/* form_get.c */
NSAPI_PUBLIC void return_html_noref(char *filename);

/* Output an input of an arbitrary type.  Not really that flexible. */
/* form_get.c */
NSAPI_PUBLIC void output_input(char *type, char *name, char *value, char *other);

/* Get the next line from the file.  Returns 0 when EOF is encountered. */
/* form_get.c */
NSAPI_PUBLIC int next_html_line(FILE *f, char *line);



/* Get the referer from the config file */
/* referer.c */
NSAPI_PUBLIC char *get_referer(char **config);

/* Redirect the person to the Referer, or give a short error message */
/* referer.c */
NSAPI_PUBLIC void redirect_to_referer(char *addition);

/* Opens the referer in the content window using JavaScript */
/* referer.c */
NSAPI_PUBLIC void js_open_referer(void);

/* Redirect to the given script. Assumes that SCRIPT_NAME is set to a script */
/* referer.c */
NSAPI_PUBLIC void redirect_to_script(char *script);


/* Filter a line using templates, and spit the results to stdout */
/* template.c */
NSAPI_PUBLIC int parse_line(char *line, char **input);

/* Since everyone seems to be doing this independently, at least centralize
   the code.  Useful for onClicks and automatic help */
NSAPI_PUBLIC char *helpJavaScript();
NSAPI_PUBLIC char *helpJavaScriptForTopic( char *topic );

/* Check to see if a directive the parser didn't know about is a given 
 * directive */
/* template.c */
NSAPI_PUBLIC int directive_is(char *target, char *directive);

/* Export the pageheader because sec-icrt uses it --MLM */
/* template.c */
NSAPI_PUBLIC void pageheader(char **vars, char **config);


/* Report an error.  Takes 3 args: 1. Category of error 
 *                                 2. Some more specific category info (opt)
 *                                 3. A short explanation of the error. 
 * 
 * report_warning: same thing except doesn't exit when done whining
 */
/* error.c */
NSAPI_PUBLIC void output_alert(int type, char *info, char *details, int wait);
NSAPI_PUBLIC void report_error(int type, char *info, char *details);
NSAPI_PUBLIC void report_warning(int type, char *info, char *details);
 

/* Some simple buffering tools */
/* Keeps a buffer for network info, and a buffer for returning lines */
/* httpcon.c */
typedef struct bufstruct {
    char *buf;
    int bufsize;
    int curpos;
    int inbuf;
    char *hbuf;
    int hbufsize;
    int hbufpos;
} bufstruct;
 
/* Make a new buffer.  Flush the rest of a buffer (leaving the contents
 * unread.  Delete a buffer structure. */
/* httpcon.c */
NSAPI_PUBLIC bufstruct *new_buffer(int bufsize);
NSAPI_PUBLIC void flush_buffer(bufstruct *buf);
NSAPI_PUBLIC void delete_buffer(bufstruct *buf);

/* stdio replacement for a network connection (so shoot me) */
/* httpcon.c */
NSAPI_PUBLIC char *get_line_from_fd(PRFileDesc *fd, bufstruct *buf);

/* send a line to a remote server (equivalent to write()) */
/* httpcon.c */
NSAPI_PUBLIC int send_line_to_fd(PRFileDesc *fd, char *line, int linesize);

/* Decompose a URL into protocol, server, port, and URI.  You needn't allocate
 * the strings you're passing, will be done for you. */
/* httpcon.c */
NSAPI_PUBLIC int decompose_url(char *url, char **protocol, char **server, unsigned int *port, char **uri);

/* Take a status line "HTTP/1.0 200 OK" or some such and produce a protocol
 * status number. */
/* httpcon.c */
NSAPI_PUBLIC int parse_status_line(char *statusline);

/* Returns whether the headers have now ended (with the line you give it) */
/* httpcon.c */
NSAPI_PUBLIC int is_end_of_headers(char *hline);

/* Make an HTTP request to a given server, running on a given port, 
 * with the given initial request.  Returns a FD that can be used 
 * to read / write to the connection. */
/* Note: Reports status to stdout in HTML form.  Bad?  Perhaps... */
/* httpcon.c */
NSAPI_PUBLIC PRFileDesc *make_http_request(char *protocol, char *server, unsigned int port, char *request, int timeout, int *errcode);

/* Terminate an HTTP request session (see above) */
/* httpcon.c */
NSAPI_PUBLIC void end_http_request(PRFileDesc *req_socket);

/* Verify that given server is an admin server. */
NSAPI_PUBLIC int verify_is_admin(char *protocol, char *server, int port);


/* Log a change in the verbose admin log.  kind is a string representing
 * what kind of change it was (see #defines at top of file, such as MAGNUS_LOG)
 * Change is the text of the change, in printf format (so you can give args). */
/* admlog.c */
NSAPI_PUBLIC void log_change(char *kind, char *change, ...);

/* Performs the request rq, for server (in list) whichsrv, using auth as
 * auth info.
 * 
 * successmsg is the prefix on lines that are returned from the remote
 * server that indicate success. */
/* pcontrol.c */
NSAPI_PUBLIC int perform_request(char *req, int whichsrv, char *auth, char *successmsg);

/* Escapes a shell command for system() calls.  NOTE: This string should
 * be large enough to handle expansion!!!! */
/* util.c */
NSAPI_PUBLIC void escape_for_shell(char *cmd);

/*
 * Escape src DN string (RFC 4514)
 * Result
 * Success:
 *     return value:  0
 *     src includes dn special characters 
 *             --> *dist returns escaped string; caller needs to free it.
 *     src does not include dn special characters --> *dist == NULL
 * Failure
 *     return value: -1
 */
int escape_for_dn(char *src, char **dist);

/* Lists all files in a directory.  If dashA list .files except . and .. */
/* util.c */
NSAPI_PUBLIC char **list_directory(char *path, int dashA);

/* Does a given file exist? */
/* util.c */
NSAPI_PUBLIC int file_exists(char *filename);

/* What's the size of a given file? */
/* util.c */
NSAPI_PUBLIC int get_file_size(char *path);

/* Return: LastModificationTime(f1) < LastModificationTime(f2) ? */
/* util.c */
NSAPI_PUBLIC int mtime_is_earlier(char *file1, char *file2);

/* Return: the last mod time of fn */
/* util.c */
NSAPI_PUBLIC time_t get_mtime(char *fn);

/* Does this string have all numbers? */
/* util.c */
NSAPI_PUBLIC int all_numbers(char *target);
/* Valid floating point number? */
NSAPI_PUBLIC int all_numbers_float(char *target);


/* Get the server's URL. */
/* util.c */
NSAPI_PUBLIC char *get_serv_url(void);

/* This is basically copy_file from the install section, with the error
 * reporting changed to match the admin stuff.  Since some stuff depends
 * on copy_file being the install version, I'll cheat and call this one
 * cp_file. */
/* util.c */
NSAPI_PUBLIC void cp_file(char *sfile, char *dfile, int mode);

/* Delete the file with the given path.  Returns positive value on failure.*/
/* util.c */
NSAPI_PUBLIC int delete_file(char *path);

/* Simply creates a directory that you give it.  Checks for errors and 
 * all that. (Not to be confused with create_subdirs in install, since
 * it relies on some installation stuff.) */
/* util.c */
NSAPI_PUBLIC void create_dir(char *dir, int mode);

/* uuencode a given buffer.  both src and dst need to be allocated.  dst
 * should be 1 1/4 as big as src (i saved some math and just made it twice
 * as big when I called it) */
/* util.c */
NSAPI_PUBLIC int do_uuencode(unsigned char *src, unsigned char *dst, int srclen);

/* Word wrap a string to fit into a JavaScript alert box. */
/* str is the string, width is the width to wrap to, linefeed is the string 
 * to use as a linefeed. */
/* util.c */
#define WORD_WRAP_WIDTH 80
NSAPI_PUBLIC char *alert_word_wrap(char *str, int width, char *linefeed);


/* Scans a file and puts all of its lines into a char * array. Strips 
 * trailing whitespace */
/* ns-util.c */
NSAPI_PUBLIC char **scan_tech(char *fn);

/* Writes the lines to the given file */
/* ns-util.c */
NSAPI_PUBLIC int write_tech(char *fn, char **lines);

/**************************************************************************
 * This is should really be in base/file.h, but we don't want to tread on
 * toes.
 * Implement fgets without the error complaints the util_getline has.  The
 * calling function is smart enough to deal with partial lines.
 * Also include a sleep that has the same functionality as Unix for NT.
 *************************************************************************/

NSAPI_PUBLIC char *system_gets( char *, int, filebuffer * );

#ifdef XP_UNIX
NSAPI_PUBLIC int system_zero( SYS_FILE );
#else /* XP_WIN32 */
#define system_zero( f ) \
	SetFilePointer( PR_FileDesc2NativeHandle( f ), 0, NULL, FILE_BEGIN );\
	SetEndOfFile( PR_FileDesc2NativeHandle( f ) )
#define sleep( t )	Sleep( (t) * 1000 )
#endif /* XP_WIN32 */

NSAPI_PUBLIC char *cookieValue( char *, char * );

NSAPI_PUBLIC void jsPWDialogSrc( int inScript, char *otherJS );

NSAPI_PUBLIC int IsCurrentTemplateNSPlugin(char* templateName);

/************************** Miscellaneous *************************/
NSAPI_PUBLIC char * jsEscape(char *src);

NSAPI_PUBLIC void htmladmin_strcat_escaped( char *s1, char *s2 );
NSAPI_PUBLIC char *htmladmin_strdup_escaped( char *s );

/* returns true if the given path is a valid directory, false otherwise */
NSAPI_PUBLIC int
util_is_dir_ok(const char *path);

/* returns true if the given path is a valid file, false otherwise */
NSAPI_PUBLIC int
util_is_file_ok(const char *path);

/* returns true if the file was found somewhere, false otherwise */
NSAPI_PUBLIC int
util_find_file_in_paths(
	char *filebuf, /* this will be filled in with the full path/filename if found, '\0' otherwise */
	size_t bufsize, /* size of filebuf e.g. sizeof(filebuf) */
	const char *filename, /* the base filename to look for */
	const char *path, /* path given by caller */
	const char *arpath, /* path relative to ADMSERV_ROOT */
	const char *nrpath /* path relative to NETSITE_ROOT */
);

/* Get the path to the directory containing config files */
NSAPI_PUBLIC char*
util_get_conf_dir(void);

/* Get the path to the directory containing security files */
NSAPI_PUBLIC char*
util_get_security_dir(void);

/* Get the path to the directory containing log files */
NSAPI_PUBLIC char*
util_get_log_dir(void);

/* Get the path to the directory containing pid file */
NSAPI_PUBLIC char*
util_get_pid_dir(void);

/* Get the path to the directory containing html files */
NSAPI_PUBLIC const char*
util_get_html_dir(void);

/* Get the path to the directory containing icon/image files */
NSAPI_PUBLIC const char*
util_get_icon_dir(void);

/* make sure the given name looks like a good file name */
NSAPI_PUBLIC int
util_is_valid_path_string(const char *);

/* Make sure the given file/dir exists.  Optionally check
   to see if the other given file/dir exists and is a child
   of the given file/dir
*/
NSAPI_PUBLIC int
util_verify_file_or_dir(const char *path, PRFileType, const char *child, size_t, PRFileType);

NSAPI_PUBLIC int
util_psetHasObjectClass(PsetHndl pset, const char *ocname);

NSAPI_PUBLIC const char *
util_urlparse_err2string(int err);

/* there are various differences among url parsers - directory server
   needs the ability to parse partial URLs - those with no dn - and
   needs to be able to tell if it is a secure url (ldaps) or not */
NSAPI_PUBLIC int
util_ldap_url_parse(const char *url, LDAPURLDesc **ludpp, int require_dn, int *secure);

NSAPI_PUBLIC int
util_ldap_get_lderrno(LDAP *ld, char **m, char **s);

/*
  Perform LDAP init and return an LDAP* handle.  If ldapurl is given,
  that is used as the basis for the protocol, host, port, and whether
  to use starttls (given on the end as ldap://..../?????starttlsOID
  If hostname is given, LDAP or LDAPS is assumed, and this will override
  the hostname from the ldapurl, if any.  If port is > 0, this is the
  port number to use.  It will override the port in the ldapurl, if any.
  If no port is given in port or ldapurl, the default will be used based
  on the secure setting (389 for ldap, 636 for ldaps)
  secure takes 1 of 2 values - 0 means regular ldap, 1 means ldaps
  filename is the ldapi file name - if this is given, and no other options
  are given, ldapi is assumed.
 */
LDAP *
util_ldap_init(
    const char *certdir, /* contains the key/cert dbs */
    const char *ldapurl, /* full ldap url */
    const char *hostname, /* can also use this to override
                             host in url */
    int port, /* can also use this to override port in url */
    int secure, /* 0 for ldap, 1 for ldaps */
    int shared, /* if true, LDAP* will be shared among multiple threads */
    const char *filename /* for ldapi */
);

/*
 * Does the correct bind operation simple/sasl/cert depending
 * on the arguments passed in.
 */
NSAPI_PUBLIC int
util_ldap_bind(
    LDAP *ld, /* ldap connection */
    const char *bindid, /* usually a bind DN for simple bind */
    const char *creds, /* usually a password for simple bind */
    const char *mech, /* name of mechanism */
    LDAPControl **serverctrls, /* additional controls to send */
    LDAPControl ***returnedctrls, /* returned controls */
    struct timeval *timeout, /* timeout */
    int *msgidp /* pass in non-NULL for async handling */
);

NSAPI_PUBLIC void
util_ldap_perror(LDAP *ld, const char *fmt, ...);

NSAPI_PUBLIC char **
util_ldap_get_values(LDAP *ld, LDAPMessage *entry, const char *attrtype);

NSAPI_PUBLIC void
util_ldap_value_free(char **vals);

NSPR_END_EXTERN_C

#endif	/* libadmin_h */
