/*
  Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.

  Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions: The above copyright notice and this
  permission notice shall be included in all copies or substantial
  portions of the Software.


  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
  THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
  ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


  Except as contained in this notice, the names of The Open Group and/or
  Sun Microsystems, Inc. shall not be used in advertising or otherwise to
  promote the sale, use or other dealings in this Software without prior
  written authorization from The Open Group and/or Sun Microsystems,
  Inc., as applicable.


  X Window System is a trademark of The Open Group

  OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
  logo, LBX, X Window System, and Xinerama are trademarks of the Open
  Group. All other trademarks and registered trademarks mentioned herein
  are the property of their respective owners. No right, title or
  interest in or to any trademark, service mark, logo or trade name of
  Sun Microsystems, Inc. or its licensors is granted.

*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/param.h>
#include <errno.h>
#ifdef  sun
#include <unistd.h>
#endif

#include "SunIM.h"
#include "SunIMLock.h"

Public iml_inst *iml_execute_iml_wrapper(iml_session_t *, iml_inst **);
int update_supported_langlist_for_le(iml_desktop_t *, IMLEName *, IMLocale *, int);
Public void close_le_module(void *);
Public iml_if_t *if_OpenIF(const char *if_path,
			   const char *if_name,
			   const char *locale, Bool);
Public void if_CloseIF(iml_if_t *, Bool);
Public Bool if_GetIFValues(iml_if_t *, IMArgList, int);
Public Bool if_SetIFValues(iml_if_t *, IMArgList, int);
Public iml_session_t *if_CreateSC(iml_if_t *, IMArgList, int);
Public Bool if_DestroySC(iml_session_t *);
Public Bool if_GetSCValues(iml_session_t *, IMArgList, int);
Public Bool if_SetSCValues(iml_session_t *, IMArgList, int);
Public void if_SendEvent(iml_session_t *, IMInputEvent *);
Public void if_SendEvent_AuxGet(iml_session_t *, IMInputEvent *);
Public IMText *if_ResetSC(iml_session_t *);
Public void if_SetSCFocus(iml_session_t *);
Public void if_UnsetSCFocus(iml_session_t *);

Public Bool if_configure(iml_if_t * If,
			 const char *if_path,
			 const char *if_name,
			 const char *if_locale,
			 Bool);
Public iml_session_t *iml_construct_session(iml_desktop_t *, IMArgList, int);

iml_desktop_t *new_user(iml_if_t * If,
			const char *user_name,
			const char *host_name,
			const char *display_id);
iml_desktop_t *find_user(iml_if_t * If, char *user_name, char *host_name, char *display_id);
void del_user(iml_desktop_t * desktop);
Private void *nsc_GetFunction(const char *name);
Private void *hkc_GetFunction(const char *name);

void add_session_to_desktop(iml_session_t *);
void remove_session_from_desktop(iml_session_t *);

static listener_id_t add_listener_to_desktop(iml_session_t *, void *, void *);
iml_listener_t *lookup_listener_from_desktop(iml_session_t *, int);
void delete_listener_from_desktop(iml_session_t *, int);
iml_file_status_t *get_fs_by_id(iml_nsc *, int);

Public char* secure_pathname(char *p); 

int ns_open(iml_nsc *, const char *, int, ...);
size_t ns_read(iml_nsc *, int, void *, size_t);
int ns_stat(iml_nsc *, const char *, struct stat *);
size_t ns_write(iml_nsc *, int, void *, size_t);
int ns_close(iml_nsc *, int);
int ns_mkdir(iml_nsc *, const char *, mode_t);
int ns_rmdir(iml_nsc *, const char *);
int ns_symlink(iml_nsc *, const char *, const char *);
int ns_lstat(iml_nsc *, const char *, struct stat *);
int ns_fstat(iml_nsc *, int filedes, struct stat *);
int ns_creat(iml_nsc *, const char *, mode_t);
off_t ns_lseek(iml_nsc *, int, off_t, int);
int ns_unlink(iml_nsc *, const char *);
int ns_rename(iml_nsc *, const char *, const char *);
int ns_fcntl(iml_nsc *, int, int, int);
int ns_truncate(iml_nsc *, const char *, off_t);
int ns_ftruncate(iml_nsc *, int, off_t);
DIR *ns_opendir(iml_nsc *, const char *);
struct dirent *ns_readdir(iml_nsc *, DIR *);
int ns_closedir(iml_nsc *, DIR *);

/*    TODO!! Need to implement the following NS API calls 
 *
 * int ns_access(iml_nsc *, const char *pathname, int mode);
 * int ns_chmod(iml_nsc *, const char *path, mode_t mode);
 * int ns_chown(iml_nsc *, const char *path, uid_t owner, gid_t group);
 * long ns_fpathconf(iml_nsc *, int filedes, int name);
 * int ns_link(iml_nsc *, const char *oldpath, const char *newpath);
 * long ns_pathconf(iml_nsc *, char *path, int name);
 * ssize_t ns_readv(iml_nsc *, int fd, const struct iovec *vector, int count);
 * ssize_t ns_writev(iml_nsc *, int fd, const struct iovec *vector, int count);
 * long ns_ulimit(iml_nsc *, int cmd, long newlimit);
 * mode_t ns_umask(iml_nsc *, mode_t mask);
 * int ns_utime(iml_nsc *, const char *filename, const struct utimbuf *buf);
 * int ns_utimes(iml_nsc *, char *filename, struct timeval *tvp);
 */

Private int updateSupportedLocales(iml_desktop_t *, IMLEName *, IMLocale *, int);
Private void *ns_create(const char *, int, void *);
Private void ns_free(iml_nsc_t);

/* Methods for Hotkey Context */
Private int switchLEProfile(iml_desktop_t *,int, IMLEName *);

Private int lookup_config(iml_nsc *, const char *, char **);

typedef struct _name_fn_map {
    char *name;
    void *fn_ptr;
} name_fn_map;

Private name_fn_map iof_map_list[] = {
	{"_nsc_create", (void *)ns_create},
	{"_nsc_free", (void *)ns_free},
	{"open", (void *)ns_open},
	{"read", (void *)ns_read},
	{"stat", (void *)ns_stat},
	{"write", (void *)ns_write},
	{"close", (void *)ns_close},
	{"mkdir", (void *)ns_mkdir},
	{"rmdir", (void *)ns_rmdir},
	{"symlink", (void *)ns_symlink},
	{"lstat", (void *)ns_lstat},
	{"creat", (void *)ns_creat},
	{"lseek", (void *)ns_lseek},
	{"unlink", (void *)ns_unlink},
	{"rename", (void *)ns_rename},
	{"fcntl", (void *)ns_fcntl},
	{"truncate", (void *)ns_truncate},
	{"ftruncate", (void *)ns_ftruncate},
	{"opendir", (void *)ns_opendir},
	{"readdir", (void *)ns_readdir},
	{"closedir", (void *)ns_closedir},
	{"fstat", (void *)ns_fstat},
	{"access", (void *)0},
	{"chmod", (void *)0},
	{"chown", (void *)0},
	{"pathconf", (void *)0},
	{"fpathconf", (void *)0},
	{"readv", (void *)0},
	{"writev", (void *)0},
	{"ulimit", (void *)0},
	{"umask", (void *)0},
	{"utime", (void *)0},
	{"utimes", (void *)0},
	{"link", (void *)0},
};

Private void *hk_create(const char *, int, void *);
Private void hk_free(iml_hkc_t);

Private name_fn_map hkf_map_list[] = {
	{"_hkc_create", (void *)hk_create},
	{"_hkc_free", (void *)hk_free},
};

static int unique_ns_id = 0;
static int dirID;

Public iml_if_t *
if_OpenIF(
    const char *if_path,
    const char *if_name,
    const char *if_locale,
    Bool call_openif
)
{
    iml_if_t *If;
    If = (iml_if_t *) calloc(1, sizeof(iml_if_t));
    If->hkm = (IMHotkeyManagerStruct *) 0;
    if (NULL == getenv("IIIMD_NSFIO_ALT")) {
	If->nsc_get_function = nsc_GetFunction;
    } else {
	extern void * fop_get_function(const char *);
	If->nsc_get_function = fop_get_function;
    }
    If->hkc_get_function = hkc_GetFunction;
    If->updateSupportedLocales = updateSupportedLocales;
    If->switchLEProfile = switchLEProfile;

    if (if_configure(If, if_path, if_name, if_locale, call_openif) == False) {
        if (If->locale) {
            free(If->locale);
        }
        if (If->if_name) {
            free(If->if_name);
        }
        if (If->ifpath_name) {
            free(If->ifpath_name);
        }
        free(If);
        If = NULL;
    }
    return If;
}

Public void
if_CloseIF(
    iml_if_t * If,
    Bool call_openif
)
{
    if(call_openif == True) {
        If->ifm->if_CloseIF(If);
    }

    if (If->m) {
        free(If->m);
    }
    if (If->locale) {
        free(If->locale);
    }
    if (If->if_name) {
        free(If->if_name);
    }
    if (If->ifpath_name) {
        free(If->ifpath_name);
    }

    close_le_module(If->dl_module);

    free(If);
}

Public Bool
if_GetIFValues(
    iml_if_t * If,
    IMArgList args,
    int n_args
)
{
    if (If) {
        return If->ifm->if_GetIFValues(If, args, n_args);
    }
    return False;
}

Public Bool
if_SetIFValues(
    iml_if_t * If,
    IMArgList args,
    int n_args
)
{
    if (If) {
        return If->ifm->if_SetIFValues(If, args, n_args);
    }
    return False;
}

#ifdef	sun
mutex_t		desktop_mutex;
#elif	WIN32
HANDLE		desktop_mutex;
#else	/* Linux */
pthread_mutex_t	desktop_mutex;
#endif


Public iml_session_t *
if_CreateSC(
    iml_if_t * If,
    IMArgList args,
    int n_args
)
{
    iml_session_t *s = NULL;
    Bool ret;
    IMArg *p = args;
    int i;
    
    iml_desktop_t *desktop = (iml_desktop_t *) 0;
    
    char *user_name = (char *) 0;
    char *host_name = (char *) 0;
    char *display_id = (char *) 0;
    
    for (i = 0; i < n_args; i++, p++) {
        if (p->id == UI_USER_NAME) {
            user_name = p->value;
        } else if (p->id == UI_HOST_NAME) {
            host_name = p->value;
        } else if (p->id == UI_DISPLAY_ID) {
            display_id = p->value;
        }
    }
    
    if (!user_name || !host_name || !display_id) {
        return NULL;
    }
    SUNIM_LOCK(desktop_mutex);
    desktop = find_user(If, user_name, host_name, display_id);
    if (!desktop) {
        desktop = new_user(If, user_name, host_name, display_id);
        ret = If->ifm->if_OpenDesktop(desktop, args, n_args);
        if (ret == False) {
            del_user(desktop);
	    SUNIM_UNLOCK(desktop_mutex);
            return NULL;
        }
        /* Initialize the listener_id and listener_count */
        desktop->listener_id = 0;
        desktop->listener_count = 0;
    }
    /*
     * All LE specific remote file loading and hotkey registration 
     * has to be completed before unlocking desktop, if each connection
     * is assigned to one thread. If each user is assigned to one thread
     * locking is not needed.
     */
    SUNIM_UNLOCK(desktop_mutex);
    s = iml_construct_session(desktop, args, n_args);
    
    if (s) {
        add_session_to_desktop(s);
    }
    return s;
}

Public Bool
if_DestroySC_WithoutDesktopDestruction(
    iml_session_t * s
)
{
    if (s) {
	int i;
        Bool ret;
	IMFeedbackList *flist;
        
        ret = s->If->ifm->if_DestroySC(s);
        
        s->If->m->iml_delete(s);
        s->If->m->iml_delete2(s);
        
        remove_session_from_desktop(s);
        
        if (s->status_cache.text && s->status_cache.text->text.utf_chars) {
            free((char *) s->status_cache.text->text.utf_chars);
	}
        if (s->status_cache.text && s->status_cache.text->feedback) {
	    for(i=0;i<DEFAULTStatusCacheSize;i++){
		flist=&s->status_cache.text->feedback[i];
		if(flist){
		    free(flist->feedbacks);
		}
	    }
	    free(s->status_cache.text->feedback);
	}

        if (s->status_cache.text) {
            free((char *) s->status_cache.text);
	}

        if (s->PreEditTextInfo.text && s->PreEditTextInfo.text->text.utf_chars) {
            free((char *) s->PreEditTextInfo.text->text.utf_chars);
	}
        if (s->PreEditTextInfo.text && s->PreEditTextInfo.text->feedback) {
	    for(i=0;i<s->PreEditTextBufferSize;i++){
		flist=&s->PreEditTextInfo.text->feedback[i];
		if(flist){
		    free(flist->feedbacks);
		}
	    }
	    free(s->PreEditTextInfo.text->feedback);
        }

        if (s->PreEditTextInfo.text) {
            free((char *) s->PreEditTextInfo.text);
	}
        
        free(s);
        
        return ret;
    }
    return False;
}

Public Bool
if_DestroySC(
    iml_session_t * s
)
{
    if (s) {
        Bool ret;
        iml_desktop_t *desktop = s->desktop;
	iml_if_t *iml_if = s->If;

        ret = if_DestroySC_WithoutDesktopDestruction(s);
        if (!desktop->session_list) {
            iml_if->ifm->if_CloseDesktop(desktop);
            del_user(desktop);
        }
        return ret;
    }
    return False;
}

Public Bool
if_SetSCValues(
    iml_session_t * s,
    IMArgList args,
    int n_args
)
{
    if (s) {
        Bool ret = s->If->ifm->if_SetSCValues(s, args, n_args);
        s->If->m->iml_delete(s);
        return ret;
    }
    return False;
}

Public Bool
if_GetSCValues(
    iml_session_t * s,
    IMArgList args,
    int n_args
)
{
    if (s) {
	Bool ret=s->If->ifm->if_GetSCValues(s, args, n_args);
        s->If->m->iml_delete(s);
        return ret;
    }
    return False;
}

Public IMText *
if_ResetSC(
    iml_session_t * s
)
{
    IMText *prs = NULL;
    if (s) {
        s->If->m->iml_delete(s);
        prs = s->If->ifm->if_ResetSC(s);
	if(!prs){
	    s->If->m->iml_delete(s);
	}
    }
    return prs;
}

Public void
if_SetSCFocus(
    iml_session_t * s
)
{
    iml_inst *rv = NULL;
    iml_inst *lp;
    if (s) {
        if (s->status_cache.text->char_length) {
            lp = s->If->m->iml_make_status_start_inst(s);
            s->If->m->iml_link_inst_tail(&rv, lp);
            lp = s->If->m->iml_make_status_draw_inst(s, s->status_cache.text);
            s->If->m->iml_link_inst_tail(&rv, lp);
            lp = s->If->m->iml_execute(s, &rv);
        }
        s->If->ifm->if_SetSCFocus(s);
        s->If->m->iml_delete(s);
    }
    return;
}

Public void
if_UnsetSCFocus(
    iml_session_t * s
)
{
    iml_inst *lp;

    if (s) {
        lp = s->If->m->iml_make_status_done_inst(s);
        s->If->m->iml_execute(s, &lp);
        s->If->ifm->if_UnsetSCFocus(s);
        s->If->m->iml_delete(s);
    }
    return;
}

Public void
if_SendEvent(
    iml_session_t * s,
    IMInputEvent * e
)
{
    if (s) {
        s->If->ifm->if_SendEvent(s, e);
        s->If->m->iml_delete(s);
    }
    return;
}

Public void
if_SendEvent_AuxGet(
    iml_session_t * s,
    IMInputEvent * e
)
{
    if (s) {
        s->If->ifm->if_SendEvent(s, e);
        /* DON'T CALL s->If->m->iml_delete(s) HERE! */
    }
    return;
}

/*
 * generic constructor of imlogic session struct
 */

Public iml_session_t *
iml_construct_session(
    iml_desktop_t * desktop,
    IMArgList args,
    int num_args
)
{
    iml_if_t *If = desktop->If;
    iml_session_t *s;
    int i;
    Bool ret;
    
    s = (iml_session_t *) calloc(1, sizeof(iml_session_t));
    s->desktop = desktop;
    s->If = If;
    s->next = NULL;

#ifdef ENABLE_EIMIL
    if (If->eh != EIMIL_VOID_HANDLE)
	EIMIL_duplicate_handle(&s->eh, If->eh);
#endif

    if ((ret=If->ifm->if_CreateSC(s, args, num_args)) == False){
        free(s);
        return NULL;
    }

    s->status_cache.text = (IMText *) calloc(1, sizeof(IMText));
    s->status_cache.text->encoding = UTF16_CODESET;
    s->status_cache.text->feedback = (IMFeedbackList *) calloc(1, sizeof(IMFeedbackList) * DEFAULTStatusCacheSize);
    s->status_cache.text->text.utf_chars = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * DEFAULTStatusCacheSize);
    s->status_cache.text->char_length = 0;
    s->status_cache.text->count_annotations = 0;
    s->status_cache.text->annotations = NULL;
    for (i = 0; i < DEFAULTStatusCacheSize; i++) {
        IMFeedbackList *fbl = &s->status_cache.text->feedback[i];
        fbl->feedbacks = (IMFeedback *) calloc(1, sizeof(IMFeedback)*DEFAULTFeedbackSize);
    }

    s->PreEditTextInfo.text = (IMText *) calloc(1, sizeof(IMText));
    s->PreEditTextInfo.text->encoding = UTF16_CODESET;
    s->PreEditTextInfo.text->text.utf_chars = (UTFCHAR *) calloc(1, sizeof(UTFCHAR) * DEFAULTPreEditTextBufferSize);
    s->PreEditTextInfo.text->feedback = (IMFeedbackList *) calloc(1, sizeof(IMFeedbackList) * DEFAULTPreEditAttrBufferSize);
    for (i = 0; i < DEFAULTPreEditTextBufferSize; i++) {
        IMFeedbackList *fbl = &s->PreEditTextInfo.text->feedback[i];
        fbl->feedbacks = (IMFeedback *) calloc(1, sizeof(IMFeedback)*DEFAULTFeedbackSize);
    }

    s->PreEditTextBufferSize = DEFAULTPreEditTextBufferSize;
    s->PreEditAttrBufferSize = DEFAULTPreEditAttrBufferSize;

    return (iml_session_t *) s;
}

iml_desktop_t *
find_user(
    iml_if_t * If,
    char *user_name,
    char *host_name,
    char *display_id
)
{
    iml_desktop_list p, *prev;
    if (If->desktop_list == NULL) {
	return (iml_desktop_t *) NULL;
    }
    for (prev = &If->desktop_list; (p = *prev) != 0; prev = &p->next) {
        if (strcmp(p->user_name, user_name) == 0 &&
	    strcmp(p->host_name, host_name) == 0 &&
	    strcmp(p->display_id, display_id) == 0) {
            return p;
        }
    }
    return (iml_desktop_t *) NULL;
}

void
del_user(
    iml_desktop_t * desktop
)
{
    iml_if_t *If = desktop->If;
    iml_desktop_list p, *prev;
    for (prev = &If->desktop_list; (p = *prev) != 0; prev = &p->next) {
        if (strcmp(p->user_name, desktop->user_name) == 0 &&
	    strcmp(p->host_name, desktop->host_name) == 0 &&
	    strcmp(p->display_id, desktop->display_id) == 0) {
#ifdef DEBUG
            printf("LE %s: %s@%s is deleted\n", If->if_name, p->user_name, p->host_name);
#endif
            *prev = p->next;
            free(p->user_name);
            free(p->host_name);
            free(p->display_id);
            free(p);
            If->desktop_count--;
            break;
        }
        if (p->next == NULL) {
            break;
        }
    }
}

static listener_id_t 
add_listener_to_desktop(
    iml_session_t *s,
    void *listener,
    void *value
)
{
    iml_desktop_t *desktop = s->desktop;

    // Create a Listener and return the unique ID

    iml_listener_t *l = (iml_listener_t *) calloc(1, sizeof(iml_listener_t));
    l->s = s;
    l->listener_name = "";
    desktop->listener_id++;
    l->listener_id = desktop->listener_id;
    l->listener = listener; /* Callback function that needs to be called */
    l->private_data = value;
    l->next = desktop->l_list;
    desktop->l_list = l;
    desktop->listener_count++;
    return l->listener_id;
}

iml_listener_t *
lookup_listener_from_desktop(
    iml_session_t *s,
    int id
)
{
    iml_desktop_t *desktop = s->desktop;
    iml_listener_list p, *prev;

    for (prev = &desktop->l_list; (p = *prev) != 0; prev = &p->next) {
        if (p->listener_id == id) {
            return p;
        }
    }

    return (iml_listener_t *)NULL;
}

void 
delete_listener_from_desktop(
    iml_session_t *s,
    int id
)
{
    iml_desktop_t *desktop = s->desktop;
    iml_listener_list p, *prev;

    for (prev = &desktop->l_list; (p = *prev) != 0; prev = &p->next) {
        if (p->listener_id == id) {
            *prev = p->next;
            free(p->listener_name);
            free(p);
            desktop->listener_count--;
            break;
        }
        if (p->next == NULL) {
	    break;
        }
    }
    return;
}

Public char*
secure_pathname(
    char *p
)
{
    char *q ;
    int index = 0;

    while (*p) {
        if ((q = (strstr(p, "../")))) {
            index = p - q;
            if (index < 0)
                index = -index;
            strcpy(p+index, p+index+3);
        } else if ((q = (strstr(p, "//")))) {
            index = p - q;
            if (index < 0)
                index = -index;
            strcpy(p+index, p+index+1);
        } else if ((q = (strstr(p, "./")))) {
            index = p - q;
            if (index < 0)
                index = -index;
            strcpy(p+index, p+index+2);
        } else {
            break ;
        }
    }
    return p;
}

iml_file_status_t *
get_fs_by_id(
    iml_nsc *nsc,
    int ns_id
)
{
    file_status_list fsl, *prev;
    iml_nsc_private *imlp = nsc->value;

    for (prev = &imlp->fslist; (fsl = *prev) != 0; prev = &fsl->next) {
	if (fsl->ns_id == ns_id) {
	    return fsl;
	}
    }
    return (iml_file_status_t *) NULL;
}

void
del_fs_by_id(
    iml_nsc *nsc,
    int ns_id
)
{
    iml_file_status_t *temp, *prev;

    if (nsc->value->fslist) {
	temp = get_fs_by_id(nsc, ns_id);
	prev = nsc->value->fslist;
	if (temp == prev) {
	    if (temp->next == NULL)
		free(temp);
	    else {
		prev = temp->next;
		free(temp);
		nsc->value->fslist = prev;
	    }
	} else {
	    while ((prev->next != temp) && (prev->next != NULL)) {
		prev = prev->next;
	    }
	    prev->next = temp->next;
	    if (temp->next == NULL)
		temp->next = prev;
	    free(temp);
	}
    }
}

int
ns_open(
    iml_nsc *nsc,
    const char *defRepository,
    int oflag,
    ...
)
{
    va_list ap;
    int fd, ns_errno;
    iml_file_status_t *fs;
    mode_t mode;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    if (0 != (O_CREAT & oflag)) {
	va_start(ap, oflag);
	mode = va_arg(ap, mode_t);
	va_end(ap);
    } else {
	mode = 0;
    }
    nsc->value->location = lookup_config(nsc, defRepository, &realRepository );

    fs = (iml_file_status_t *) calloc(1, sizeof(iml_file_status_t));
    unique_ns_id++;
    fs->ns_id = unique_ns_id;
    fs->nitems = 0;
    fs->d_name = (char **)NULL;
    fs->d_reclen = 0;
    fs->next = nsc->value->fslist;
    fs->path_name = (char *) calloc(strlen(realRepository), sizeof(char));
    fs->path_name = secure_pathname(realRepository);
    nsc->value->fslist = fs;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
      {
        if ((fs->fd = open(fs->path_name, oflag, mode)) < 0) {
          return fs->fd;
        } else return fs->ns_id;
      }

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       fd = open_ns(desktop, fs->ns_id, fs->path_name, oflag, mode, &ns_errno);
       errno = ns_errno;
       return fd;

      default:
      {
        if ((fs->fd = open(fs->path_name, oflag, mode)) < 0) {
          return fs->fd;
        } else return fs->ns_id;
      }
    }
}

size_t
ns_read(
    iml_nsc *nsc,
    int ns_id,
    void *ptr,
    size_t size
)
{
    int ret, ns_errno;
    iml_file_status_t *fs = get_fs_by_id(nsc, ns_id);
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return read(fs->fd, ptr, size);

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = read_ns(desktop, ns_id, ptr, size, &ns_errno);
       errno = ns_errno;
       break;

      default:
       return read(fs->fd, ptr, size);
    }
    return ret;
}

int
ns_stat(
    iml_nsc *nsc,
    const char *file_name,
    struct stat *buf
)
{
    int ret, ns_errno, ns_id, location;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    location = lookup_config(nsc, file_name, &realRepository );

    switch (location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return stat(secure_pathname(realRepository), buf);

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = stat_ns(desktop, ns_id, realRepository, buf, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return stat(secure_pathname(realRepository), buf);
    }
}

int
ns_lstat(
    iml_nsc *nsc,
    const char *file_name,
    struct stat *buf
)
{
    int ret, ns_errno, ns_id, location;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    location = lookup_config(nsc, file_name, &realRepository );

    switch (location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return lstat(secure_pathname(realRepository), buf);

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = lstat_ns(desktop, ns_id, realRepository, buf, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return lstat(secure_pathname(realRepository), buf);
    }
}

size_t
ns_write(
    iml_nsc *nsc,
    int ns_id,
    void *ptr,
    size_t size
)
{
    int ret, ns_errno;
    iml_file_status_t *fs = get_fs_by_id(nsc, ns_id);
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return write(fs->fd, ptr, size);

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = write_ns(desktop, ns_id, ptr, size, &ns_errno);
       errno = ns_errno;
       break;

      default:
       return write(fs->fd, ptr, size);
    }
    return ret;
}

int
ns_close(
    iml_nsc *nsc,
    int ns_id
)
{
    int ret, ns_errno;
    iml_file_status_t *fs = get_fs_by_id(nsc, ns_id);
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       ret = close(fs->fd);
       break;

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = close_ns(desktop, ns_id, &ns_errno);
       errno = ns_errno;
       break;

      default:
       ret = close(fs->fd);
       break;
    }

    del_fs_by_id (nsc, ns_id);

    return ret;
}

DIR * 
ns_opendir(
    iml_nsc *nsc,
    const char *defRepository
)
{
    int pns_id, ns_errno;
    iml_file_status_t *fs;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    dirID=0;

    nsc->value->location = lookup_config(nsc, defRepository, &realRepository );

    fs = (iml_file_status_t *) calloc(1, sizeof(iml_file_status_t));
    unique_ns_id++;
    fs->ns_id = unique_ns_id;
    fs->nitems = 0;
    fs->d_name = (char **)NULL;
    fs->d_reclen = 0;
    fs->path_name = (char *) calloc(strlen(realRepository), sizeof(char));
    fs->path_name = secure_pathname(realRepository);
    fs->next = nsc->value->fslist;
    nsc->value->fslist = fs;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
      {
        if ((fs->dirp = opendir(fs->path_name)) == NULL) {
          return fs->dirp;
        } else 
            return (DIR *)fs->ns_id;
      }

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       fs->d_name = opendir_ns(desktop, fs->ns_id, fs->path_name, &fs->nitems, &pns_id, &fs->d_reclen, &ns_errno);
       errno = ns_errno;
       return (DIR *)pns_id;

      default:
      {
        if ((fs->dirp = opendir(fs->path_name)) == NULL) {
          return fs->dirp;
        } else 
            return (DIR *)fs->ns_id;
      }
    }
}

struct dirent * 
ns_readdir(
    iml_nsc *nsc,
    DIR *dirp
)
{
    struct dirent *p;
    int ns_id = (int) dirp;
    iml_file_status_t *fs = get_fs_by_id(nsc, ns_id);

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return readdir(fs->dirp);

      case NS_REMOTE:
       /* TODO!! Need to get the errno for readdir() */
       errno = 0;
       if (dirID < fs->nitems) {
	   p = (struct dirent *) calloc(1, sizeof(struct dirent));
	   p->d_reclen = (int)fs->d_reclen[dirID];
	   strncpy(p->d_name, fs->d_name[dirID], p->d_reclen);
	   dirID++;
	   return p;
       }
       dirID = 0;
       return (struct dirent *)NULL;

      default:
       return readdir(fs->dirp);
    }
}

int 
ns_closedir(
    iml_nsc *nsc,
    DIR *dirp
)
{
    int ns_id, ret, ns_errno;
    ns_id = (int) dirp;
    iml_file_status_t *fs = get_fs_by_id(nsc, ns_id);
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       ret = closedir(fs->dirp);
       break;

      case NS_REMOTE:
       ns_id = (int) dirp;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = closedir_ns(desktop, ns_id, &ns_errno);
       errno = ns_errno;
       break;

      default:
       ret = closedir(fs->dirp);
       break;
    }
    del_fs_by_id (nsc, ns_id);
    return ret;
}

int 
ns_mkdir(
    iml_nsc *nsc,
    const char *path,
    mode_t mode
)
{
    int ret, ns_errno, ns_id, location;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    location = lookup_config(nsc, path, &realRepository );

    switch (location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return mkdir(secure_pathname(realRepository), mode);

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = mkdir_ns(desktop, ns_id, realRepository, mode, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return mkdir(secure_pathname(realRepository), mode);
    }
}

int
ns_rmdir(
    iml_nsc *nsc,
    const char *path
)
{
    int ret, ns_id, ns_errno, location;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    location = lookup_config(nsc, path, &realRepository );

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return rmdir(secure_pathname(realRepository));

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = rmdir_ns(desktop, ns_id, realRepository, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return rmdir(secure_pathname(realRepository));
    }
}

int 
ns_symlink(
    iml_nsc *nsc,
    const char *dest_path,
    const char *src_path
)
{
    int ret, ns_errno, ns_id, destL, srcL;
    char *destRepository, *srcRepository;
    iml_desktop_t *desktop = NULL;

    destL = lookup_config(nsc, dest_path, &destRepository );
    srcL = lookup_config(nsc, dest_path, &srcRepository );

    if ((destL == NS_REMOTE) || (srcL == NS_REMOTE)) {
	destL = NS_REMOTE;
    }

    switch (destL) {
      case NS_LOCAL:
      case NS_DATABASE:
       return symlink(secure_pathname(destRepository), secure_pathname(srcRepository));

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = symlink_ns(desktop, ns_id, destRepository, srcRepository, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return symlink(secure_pathname(destRepository), secure_pathname(srcRepository));
    }
}

int
ns_fstat(
    iml_nsc *nsc,
    int ns_id,
    struct stat *buf
)
{
    int ns_errno, ret;
    iml_file_status_t *fs = get_fs_by_id(nsc, ns_id);
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return fstat(fs->fd, buf);

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = fstat_ns(desktop, ns_id, buf, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return fstat(fs->fd, buf);
    }
}

int 
ns_creat(
    iml_nsc *nsc,
    const char *defRepository,
    mode_t mode
)
{
    int fd;
    iml_file_status_t *fs = (iml_file_status_t *) calloc(1, sizeof(iml_file_status_t));
    int ns_errno;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    unique_ns_id++;
    fs->ns_id = unique_ns_id;
    fs->nitems = 0;
    fs->d_name = (char **)NULL;
    fs->d_reclen = 0;
    fs->next = nsc->value->fslist;
    nsc->value->location = lookup_config(nsc, defRepository, &realRepository );
    fs->path_name = (char *) calloc(strlen(realRepository), sizeof(char));
    fs->path_name = secure_pathname(realRepository);
    nsc->value->fslist = fs;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
      {
        if ((fs->fd = creat(fs->path_name, mode)) < 0) {
          return fs->fd;
        } else return fs->ns_id;
      }

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       fd = creat_ns(desktop, fs->ns_id, fs->path_name, mode, &ns_errno);
       errno = ns_errno;
       return fd;

      default:
      {
        if ((fs->fd = creat(fs->path_name, mode)) < 0) {
          return fs->fd;
        } else return fs->ns_id;
      }
    }
}

off_t 
ns_lseek(
    iml_nsc *nsc,
    int ns_id,
    off_t offset,
    int whence
)
{
    int ret, ns_errno;
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return lseek(ns_id, offset, whence);

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = lseek_ns(desktop, ns_id, offset, whence, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return lseek(ns_id, offset, whence);
    }
}

int 
ns_unlink(
    iml_nsc *nsc,
    const char *path
)
{
    int ret, ns_errno, ns_id, location;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    location = lookup_config(nsc, path, &realRepository );

    switch (location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return unlink(secure_pathname(realRepository));

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = unlink_ns(desktop, ns_id, realRepository, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return unlink(secure_pathname(realRepository));
    }
}

int 
ns_rename(
    iml_nsc *nsc,
    const char *old_name,
    const char *new_name
)
{
    int ns_id, ret, ns_errno, oldL, newL;
    char *oldRepository, *newRepository;
    iml_desktop_t *desktop = NULL;

    oldL = lookup_config(nsc, old_name, &oldRepository );
    newL = lookup_config(nsc, new_name, &newRepository );

    if ((oldL == NS_REMOTE) || (newL == NS_REMOTE)) {
	oldL = NS_REMOTE;
    }

    switch (oldL) {
      case NS_LOCAL:
      case NS_DATABASE:
       return rename(secure_pathname(oldRepository), secure_pathname(newRepository));

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = rename_ns(desktop, ns_id, oldRepository, newRepository, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return rename(secure_pathname(oldRepository), secure_pathname(newRepository));
    }
}

int 
ns_fcntl(
    iml_nsc *nsc,
    int ns_id,
    int cmd,
    int arg
)
{
    int ret, ns_errno;
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return fcntl(ns_id, cmd, arg);

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = fcntl_ns(desktop, ns_id, cmd, arg, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return fcntl(ns_id, cmd, arg);
    }
}

int 
ns_truncate(
    iml_nsc *nsc,
    const char *path,
    off_t length
)
{
    int ns_id, ret, ns_errno, location;
    char *realRepository;
    iml_desktop_t *desktop = NULL;

    location = lookup_config(nsc, path, &realRepository );

    switch (location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return truncate(secure_pathname(realRepository), length);

      case NS_REMOTE:
       unique_ns_id++;
       ns_id = unique_ns_id;
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = truncate_ns(desktop, ns_id, realRepository, length, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return truncate(secure_pathname(realRepository), length);
    }
}

int 
ns_ftruncate(
    iml_nsc *nsc,
    int ns_id,
    off_t length
)
{
    int ret, ns_errno;
    iml_file_status_t *fs = get_fs_by_id(nsc, ns_id);
    iml_desktop_t *desktop = NULL;

    switch (nsc->value->location) {
      case NS_LOCAL:
      case NS_DATABASE:
       return ftruncate(fs->fd, length);

      case NS_REMOTE:
       if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
         desktop = nsc->value->ns_owner;
       }
       ret = ftruncate_ns(desktop, ns_id, length, &ns_errno);
       errno = ns_errno;
       return ret;

      default:
       return ftruncate(fs->fd, length);
    }
}

Private int
lookup_config(
    iml_nsc *nsc,
    const char *default_path,
    char **real_path
)
{
    int i;
    iml_if_t *If = 0;

    if (nsc->value->ns_type == IML_NSC_TYPE_LE) {
	If = nsc->value->ns_owner;
    } else if (nsc->value->ns_type == IML_NSC_TYPE_DESKTOP) {
	iml_desktop_t *desktop = nsc->value->ns_owner;
	If = desktop->If;
    }
    
    if (!If->num_nsm_entries) {
	*real_path = (char *) default_path;
	return NS_LOCAL;
    }

    for (i=0; i<If->num_nsm_entries; i++) {
	if (!strcmp(If->ns_map[i].src_entry, default_path)) {
	    *real_path = If->ns_map[i].dest_entry;
	    if (!strcmp(If->ns_map[i].location, "REMOTE")) {
		return NS_REMOTE;
	    } 
	}
    }

    *real_path = (char *)default_path;

    return NS_LOCAL;

}

Private int 
updateSupportedLocales(
    iml_desktop_t *desktop,
    IMLEName *lename,
    IMLocale *locales,
    int nlocale
)
{ 
    return update_supported_langlist_for_le(desktop, lename, locales, nlocale);
}

Private int 
switchLEProfile(
    iml_desktop_t *desktop,
    int le_profile_id,
    IMLEName *lename
)
{
    return switch_le_profile(desktop, le_profile_id, lename);
}

Private void *
ns_create(
    const char *le_name,
    int ns_type, 
    void *ns_owner
)
{
    iml_nsc *nsc;

    nsc = (iml_nsc *) calloc(1, sizeof(iml_nsc));
    nsc->value = (iml_nsc_private *) calloc(1, sizeof(iml_nsc_private));
    nsc->value->ns_type = ns_type;
    nsc->value->ns_owner = ns_owner;
    nsc->value->fslist = 0;

    return nsc;
}

Private void *
hk_create(
    const char *le_name,
    int hk_type, 
    void *hk_owner
)
{
    iml_hkc *hkc;

    hkc = (iml_hkc *) calloc(1, sizeof(iml_hkc));
    hkc->value = (iml_hkc_private *) calloc(1, sizeof(iml_hkc_private));
    hkc->value->hk_type = hk_type;
    hkc->value->hk_owner = hk_owner;

    return hkc;
}

Private void 
ns_free(
    iml_nsc *nsc
)
{
    if (nsc) free(nsc);
    return;
}

Private void 
hk_free(
    iml_hkc *hkc
)
{
    if (hkc) free(hkc);
    return;
}

Private void * 
nsc_GetFunction(
    const char *name
)
{
    name_fn_map *p;
    
    if (!strcmp(name, "_nsc_basicfioset")) {
	iml_nsc_basic_fioset_t *bfioset;
	bfioset = (iml_nsc_basic_fioset_t *) calloc(1, sizeof(iml_nsc_basic_fioset_t));
	bfioset->open = ns_open;
	bfioset->read = ns_read;
	bfioset->stat = ns_stat;
	bfioset->write = ns_write;
	bfioset->close = ns_close;
	bfioset->mkdir = ns_mkdir;
	bfioset->rmdir = ns_rmdir;
	bfioset->symlink = ns_symlink;
	bfioset->lstat = ns_lstat;
	bfioset->creat = ns_creat;
	bfioset->lseek = ns_lseek;
	bfioset->unlink = ns_unlink;
	bfioset->rename = ns_rename;
	bfioset->fcntl = ns_fcntl;
	bfioset->truncate = ns_truncate;
	bfioset->opendir = ns_opendir;
	bfioset->readdir = ns_readdir;
	bfioset->closedir = ns_closedir;
	bfioset->fstat = ns_fstat;
	bfioset->ftruncate = ns_ftruncate;
	return bfioset;
    }

    for (p = iof_map_list; p != 0; p++) {
	if (!strcmp(p->name, name)) {
	    return p->fn_ptr;
	}
    }
    return (void *)NULL;
}

Private void * 
hkc_GetFunction(
    const char *name
)
{
    name_fn_map *p;
    
    for (p = hkf_map_list; p != 0; p++) {
	if (!strcmp(p->name, name)) {
	    return p->fn_ptr;
	}
    }
    return (void *)NULL;
}

iml_desktop_t *
new_user(
    iml_if_t * If,
    const char *user_name,
    const char *host_name,
    const char *display_id
)
{
    iml_desktop_t *p = (iml_desktop_t *) calloc(1, sizeof(iml_desktop_t));

    p->addListenerToDesktop = add_listener_to_desktop;
    p->lookupListenerFromDesktop = lookup_listener_from_desktop;
    p->deleteListenerFromDesktop = delete_listener_from_desktop;

    p->user_name = strdup(user_name);
    p->host_name = strdup(host_name);
    p->display_id = strdup(display_id);
    p->next = If->desktop_list;
    p->If = If;
    If->desktop_list = p;
    If->desktop_count++;
#ifdef DEBUG
    printf("LE %s: %s@%s is entered\n", If->if_name, user_name, host_name);
#endif
    return (iml_desktop_t *) p;
}

void
remove_session_from_desktop(
    iml_session_t * s
)
{
    iml_session_list p, *prev;
    for (prev = &s->desktop->session_list; (p = *prev) != 0; prev = &p->next) {
        if (p == s) {
            *prev = p->next;
            s->desktop->session_count--;
            break;
        }
        if (p->next == NULL) {
            break;
        }
    }
}

void
add_session_to_desktop(
    iml_session_t * s
)
{
    s->next = s->desktop->session_list;
    s->desktop->session_list = s;
    s->desktop->session_count++;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
