/* dynload.c - load cipher extensions
 *	Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
 *
 * This file is part of GnuPG.
 *
 * GnuPG 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 3 of the License, or
 * (at your option) any later version.
 *
 * GnuPG 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, see <http://www.gnu.org/licenses/>.
 */

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "util.h"
#include "cipher.h"
#include "algorithms.h"
#ifdef __OS2__
	#include "i18n.h"
	#include "../g10/options.h"

	#define INCL_DOSERRORS
	#define INCL_DOSPROCESS
	#define INCL_DOSMODULEMGR
	#include <os2.h>
#endif


typedef struct ext_list {
    struct ext_list *next;
    char name[1];
} *EXTLIST;

static EXTLIST extensions;

/* This is actually not used anymore but we keep a list of already 
 * set extensions modules here.   
 *
 * Here is the ancient comment:
 * Register an extension module.  The last registered module will
 * be loaded first.  A name may have a list of classes
 * appended; e.g:
 *	mymodule.so(1:17,3:20,3:109)
 * means that this module provides digest algorithm 17 and public key
 * algorithms 20 and 109.  This is only a hint but if it is there the
 * loader may decide to only load a module which claims to have a
 * requested algorithm.
 *
 * mainpgm is the path to the program which wants to load a module
 * it is only used in some environments.
 */
void
register_cipher_extension( const char *mainpgm, const char *fname )
{
    EXTLIST r, el, intex;
    char *p, *pe;

#ifdef __OS2__
	APIRET		rc = NO_ERROR;
	HMODULE		my_handle = NULLHANDLE;
	char		load_error[__CCHMAXPATH + 1];
	char		my_path[__CCHMAXPATH + 1];
	unsigned int	str_len;
	int		i;
	char		my_fname[__CCHMAXPATH + 1];
	char		*my_fname_ptr = (char*)&my_fname;

	memset((char*)&load_error, 0, sizeof(load_error));
	memset((char*)&my_fname, 0, sizeof(my_fname));
	strncpy((char*)&my_fname, fname, __CCHMAXPATH);
	str_len = strlen((char*)&my_fname);

	/*
	 * Check if the filename has an ".dll" extension and
	 * append one in case it does not.
	 */

	if (str_len >= 4)
		if (stricmp((char*)&my_fname[str_len - 4], ".dll") != 0)
			if (str_len + 4 < __CCHMAXPATH)
				strcat((char*)&my_fname, ".dll");

	/*
	 * Redefine fname to point to our string that is guaranteed
	 * to have a ".dll" extension.
	 */
	#define fname	my_fname_ptr

	/* Quick'n'dirty check if fname is not an absolute path */
	if ((*fname != '/') && (*fname !='\\') && (fname[1] != ':')) {
		/*
		 * Search in the following directories in the following
		 * order:
		 * (1) GNUPG_LIBDIR
		 * (2) The directory where gpg.exe resides
		 * (3) LIBPATH
		 */
		memset((char*)&my_path, 0, sizeof(my_path));
		strcat(my_path, GNUPG_LIBDIR);
		if (strlen(my_fname) + strlen(my_path) + 1 < __CCHMAXPATH) {
			strcat(my_path, "\\");
			strcat(my_path, my_fname);
			rc = DosLoadModule(load_error, sizeof(load_error),
				my_path, &my_handle);
			if (rc == NO_ERROR)
				goto done;
		}

		memset((char*)&my_path, 0, sizeof(my_path));
		strcat(my_path, __OS2_PROGDIR);
		if (strlen(my_fname) + strlen(my_path) + 1 < __CCHMAXPATH) {
			strcat(my_path, "\\");
			strcat(my_path, my_fname);
			rc = DosLoadModule(load_error, sizeof(load_error),
				my_path, &my_handle);
			if (rc == NO_ERROR)
				goto done;
		}

		memset((char*)&my_path, 0, sizeof(my_path));
		if (strlen(my_fname) < __CCHMAXPATH) {
			strcat(my_path, my_fname);
			rc = DosLoadModule(load_error, sizeof(load_error),
				my_path, &my_handle);
			if (rc != NO_ERROR) {
				if (opt.verbose)
					log_info(_("loading %s failed\n"), my_path);
				return;
			} else
				goto done;
		}

done:
		rc = DosFreeModule(my_handle);
		/* Make the path use only forward slashes */
		for (i = strlen(my_path); i > 0; i--)
			if (my_path[i] == '\\')
				my_path[i] = '/';
		el = xmalloc_clear(sizeof(*el) + strlen(my_path));
		strcpy(el->name, my_path);
	}
#else
    if( *fname != DIRSEP_C ) { /* do tilde expansion etc */
	char *tmp;

	if( strchr(fname, DIRSEP_C) )
	    tmp = make_filename(fname, NULL);
	else
	    tmp = make_filename(GNUPG_LIBDIR, fname, NULL);
	el = xmalloc_clear( sizeof *el + strlen(tmp) );
	strcpy(el->name, tmp );
	xfree(tmp);
    }
#endif
    else {
	el = xmalloc_clear( sizeof *el + strlen(fname) );
	strcpy(el->name, fname );
    }
    /* check whether we have a class hint */
    if( (p=strchr(el->name,'(')) && (pe=strchr(p+1,')')) && !pe[1] )
	*p = *pe = 0;

    /* check that it is not already registered */
    intex = NULL;
    for(r = extensions; r; r = r->next ) {
	if( !compare_filenames(r->name, el->name) ) {
	    log_info("extension `%s' already registered\n", el->name );
	    xfree(el);
	    return;
	}
    }
    /* and register */
    el->next = extensions;
    extensions = el;
#ifdef __OS2__
	#undef fname
#endif
}

/* Return the module name with index SEQ, return NULL as as indication
   for end of list. */
const char *
dynload_enum_module_names (int seq)
{
  EXTLIST el = extensions;

  for (; el && el->name && seq; el = el->next, seq--)
    ;
  return el? el->name:NULL;
}
