/*
 * $Id: ram-parse.c,v 0.9 1991/10/29 14:52:07 linus Exp $
 * Copyright (C) 1991  Lysator Academic Computer Association.
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM 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 1, or (at your option) 
 * any later version.
 * 
 * LysKOM 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 LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
 * Please mail bug reports to bug-lyskom@lysator.liu.se. 
 */
/*#define DISKERR*/			/* Some corrections
				   that are needed by diskomd 0.29.
				   */
/*
 * ram-parse.c -- parse objects from disk file.
 */

static char *rcsid = "$Id: ram-parse.c,v 0.9 1991/10/29 14:52:07 linus Exp $";


/*
 * BUGS: Not all functions are needed.
 *	 The method for checking errors in fparse_long is ugly.
 *	 Errors in fparse_long are not always checked for.
 */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lyskomd.h"
#include "s-string.h"
#include <kom-types.h>
#include <kom-errno.h>
#include <services.h>
#include "ram-parse.h"
#include "log.h"
#include <server/smalloc.h>
#include "com.h"
#include "connections.h"
#ifdef DISKERR
#include "string-malloc.h"
#endif

#define REALLOC(ptr, size)  srealloc(ptr, size)

static int fparse_long_errors = 0;

void
fskipwhite(FILE *fp)
{
    int c;

    while ( (c = getc(fp)) != EOF && /* isascii(c) && */ isspace(c) )
	;

    ungetc(c, fp);
}

extern u_long
fparse_long(FILE *fp)
{
    u_long res = 0;
    int foo = 0;
    int c;

    fskipwhite(fp);
    while ( (c = getc(fp)) != EOF && /* isascii(c) && */ isdigit(c))
    {
	foo = 1;
	res = 10 * res + c - '0';
    }

    if ( foo == 0 )
    {
	log("fparse_long() failed at pos %d.\n", ftell(fp));
	++fparse_long_errors;
    }
    
    ungetc(c, fp);

    return res;
}

extern time_t
fparse_time(FILE *fp)
{
    return fparse_long(fp);
}

    

extern Success
fparse_conference(FILE *fp,
		 Conference *result)
{
    if ( fparse_long_errors != 0 )
    {
	log("fparse_conference(): fparse_long_errors == %d on entry. Reset.\n",
	    fparse_long_errors);
	fparse_long_errors = 0;
    }

    if ( fparse_string(fp, &result->name) != OK )
    {
	log("fparse_conference(): Can't parse name.\n");
	return FAILURE;
    }

    if ( fparse_member_list(fp, &result->members) != OK
	|| fparse_text_list(fp, &result->texts) != OK
	|| fparse_conf_type(fp, &result->type) != OK )
    {
	log("fparse_conference: file is corrupt.\n");
	return FAILURE;
    }
    
    result->creation_time = fparse_time(fp);
    result->last_written = fparse_time(fp);

    result->creator = fparse_long(fp);
    result->presentation = fparse_long(fp);
    result->supervisor = fparse_long(fp);
    result->permitted_submitters = fparse_long(fp);
    result->super_conf = fparse_long(fp);
    result->msg_of_day = fparse_long(fp);

    if ( fparse_long_errors != 0 )
    {
	log("fparse_conference(): %d fparse_long_errors before 'nice'. "
	    "Reset.\n",
	    fparse_long_errors);
	fparse_long_errors = 0;
	return FAILURE;
    }

    result->nice = fparse_long(fp);

#ifdef DISKERR
    if ( fparse_long_errors != 0 )
    {
	log("fparse_conference(): Error parsing 'nice' at pos %d. "
	    "nice set to 77 and error ignored.\n", ftell(fp));
	fparse_long_errors = 0;
	result->nice = 77;
    }

    if ( result->nice < 10 )
    {
	char *name;
	int new_nice;

	name = s_crea_c_str(result->name);
	new_nice = 10 * result->nice + 7;

	if ( name == NULL )
	{
	    log("fparse_conference(): nice in (null) was %d, set to %d.\n",
		result->nice, new_nice);
	}
	else
	{
	    log("fparse_conference(): nice in %s was %d, set to %d.\n",
		name, result->nice, new_nice);
	    string_free(name);
	}

	result->nice = new_nice;
    }
#endif

    fskipwhite(fp);

    return OK;
}


Success
fparse_person(FILE *fp,
	      Person *person)
{
    String pwd = EMPTY_STRING;

    if ( fparse_long_errors != 0 )
    {
	log("fparse_person(): fparse_long_errors == %d on entry. Reset.\n",
	    fparse_long_errors);
	fparse_long_errors = 0;
    }

    if ( fparse_string(fp, &pwd) != OK )
    {
	log("fparse_person(): Failed to parse password.\n");
	return FAILURE;
    }

    memcpy(person->pwd, pwd.string, PASSWD_LEN);
    s_clear(&pwd);
    	
    if ( fparse_string(fp, &person->username) != OK
	|| fparse_priv_bits(fp, &person->privileges) != OK
	|| fparse_personal_flags(fp, &person->flags) != OK
	|| fparse_text_list(fp, &person->created_texts) != OK
	|| fparse_mark_list(fp, &person->marks) != OK 
	|| fparse_membership_list(fp, &person->conferences) != OK )
    {
	log("fparse_person(): parse error.\n");
	return FAILURE;
    }

    person->last_login = fparse_time(fp);

    person->user_area = fparse_long(fp);
    person->total_time_present = fparse_long(fp);
    person->sessions = fparse_long(fp);
    person->created_lines = fparse_long(fp);
    person->created_bytes = fparse_long(fp);
    person->read_texts = fparse_long(fp);
    person->no_of_text_fetches = fparse_long(fp);
    person->created_persons = fparse_long(fp);

    if ( fparse_long_errors != 0 )
    {
	log("fparse_person(): %d fparse_long_errors before 'created_"
	    "confs'. Reset.\n",
	    fparse_long_errors);
	fparse_long_errors = 0;
	return FAILURE;
    }

    person->created_confs = fparse_long(fp);

#ifdef DISKERR
    if ( fparse_long_errors != 0 )
    {
	log("fparse_person(): Error parsing 'created_confs' at pos %d. "
	    "created_confs set to 0 and error ignored.\n", ftell(fp));
	fparse_long_errors = 0;
	person->created_confs = 0;
    }
#endif

    fskipwhite(fp);

    return OK;
}

Success
fparse_membership(FILE *fp,
		 Membership *mship)
{
    int i;
    
    mship->last_time_read = fparse_time(fp);

    mship->conf_no = fparse_long(fp);
    mship->priority = fparse_long(fp);
    mship->last_text_read = fparse_long(fp);
    mship->no_of_read = fparse_long(fp);

    if ( mship->no_of_read > 0)
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    mship->read_texts
		= REALLOC(mship->read_texts, (mship->no_of_read
					      * sizeof(Local_text_no)));
	    if ( mship->read_texts == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }

	    for ( i = 0; i < mship->no_of_read; i++)
		mship->read_texts[ i ] = fparse_long(fp);

	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		kom_errno = KOM_SERVER_IS_CRAZY;
		log("fparse_membership(): expected '}' at pos %d.\n",
		    ftell(fp));
		return FAILURE;
	    }
	    break;
	    
	case '*':
	    if ( mship->read_texts != NULL )
	    {
		sfree(mship->read_texts);
		mship->read_texts = NULL;
	    }
	    log("fparse_membership(): empty read_texts "
		"with %lu elements (corrected)\n",
		mship->no_of_read);
	    mship->no_of_read = 0;
	    break;
	default:
	    log("fparse_membership(): expected '*' or '{' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_membership(): expected '*' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}

	if ( mship->read_texts != NULL )
	{
	    sfree(mship->read_texts);
	    mship->read_texts = NULL;
	}
    }

    return OK;
}

	
extern Success
fparse_membership_list(FILE *fp,
		       Membership_list *result)
{
    int i;
    
    /* First free all the read_texts. */

    if ( result->confs != NULL )
    {
	for ( i = 0; i < result->no_of_confs; i++)
	    sfree(result->confs[ i ].read_texts);
    }
    
    result->no_of_confs = fparse_long(fp);

    if ( result->no_of_confs > 0 )
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    result->confs = REALLOC(result->confs,
					  (result->no_of_confs
					   * sizeof(Membership)));
	    if ( result->confs == NULL && result->no_of_confs > 0 )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }

	    for ( i = 0; i < result->no_of_confs; i++)
	    {
		result->confs[ i ] = EMPTY_MEMBERSHIP;
		if ( fparse_membership(fp, &result->confs[i]) != OK )
		    return FAILURE;
	    }
	    
	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		log("fparse_membership_list(): expected '}' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	    
	    break;
	case '*':
	    if ( result->confs != NULL )
	    {
		sfree(result->confs);
		result->confs = NULL;
	    }
	    log("fparse_membership_list(): empty list with %lu "
		"elements (corrected).\n",
		(u_long)result->no_of_confs);
	    
	    result->no_of_confs = 0;
	    break;
	default:
	    log("fparse_membership_list(): expected '*' or '{' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_membership_list(): expected '*' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
	if ( result->confs != NULL )
	{
	    sfree(result->confs);
	    result->confs = NULL;
	}
    }
    return OK;
}


extern Success
fparse_conf_list(FILE *fp,
		Conf_list_old *result)
{
    int i;

    result->no_of_conf_nos = fparse_long(fp);
    if ( result->no_of_conf_nos > 0 )
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    result->conf_nos = REALLOC(result->conf_nos,
				       (result->no_of_conf_nos
					* sizeof(Conf_no)));
	    if ( result->conf_nos == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }
	    
	    for ( i = 0; i < result->no_of_conf_nos; i++)
		result->conf_nos[ i ] = fparse_long(fp);
	    
	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		log("fparse_conf_list(): expected '}' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	    
	    break;
	case '*':
	    if ( result->conf_nos != NULL )
	    {
		sfree(result->conf_nos);
		result->conf_nos = NULL;
	    }
	    break;
	default:
	    log("fparse_conf_list(): expected '*' or '{' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_conf_list(): expected '*' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
	if ( result->conf_nos != NULL )
	{
	    sfree(result->conf_nos);
	    result->conf_nos = NULL;
	}
    }

    if ( result->no_of_conf_nos > 0 )
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    result->type_of_conf = REALLOC(result->type_of_conf,
					   (result->no_of_conf_nos
					    * sizeof(Conf_type)));

	    if ( result->type_of_conf == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }
	    
	    for ( i = 0; i < result->no_of_conf_nos; i++)
		if ( fparse_conf_type(fp, &result->type_of_conf[i]) != OK )
		{
		    return FAILURE;
		}
	    
	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		log("fparse_conf_list(): expected '}' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	    
	    break;
	case '*':
	    if ( result->type_of_conf != NULL )
	    {
		sfree(result->type_of_conf);
		result->type_of_conf = NULL;
	    }
	    break;
	default:
	    log("fparse_conf_list(): expected '*' or '+' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_conf_list(): expected '*' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}

	if ( result->type_of_conf != NULL )
	{
	    sfree(result->type_of_conf);
	    result->type_of_conf = NULL;
	}
    }
    return OK;
}


extern Success
fparse_mark_list(FILE *fp,
		Mark_list *result)
{
    int i;

    result->no_of_marks = fparse_long(fp);

    if ( result->no_of_marks > 0 )
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    result->marks = REALLOC(result->marks,
				    (result->no_of_marks
				     * sizeof(Mark)));

	    if ( result->marks == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }
	    
	    for ( i = 0; i < result->no_of_marks; i++)
		if ( fparse_mark(fp, &result->marks[ i ] ) != OK )
		{
		    return FAILURE;
		}
	    
	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		log("fparse_mark_list(): expected '}' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	    
	    break;

	case '*':
	    if ( result->marks != NULL )
	    {
		sfree(result->marks);
		result->marks = NULL;
	    }
	    break;

	default:
	    log("fparse_mark_list(): expected '*' or '{' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_mark_list(): expected '*' at pos %d.\n", ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
	if ( result->marks != NULL )
	{
	    sfree(result->marks);
	    result->marks = NULL;
	}
    }
    return OK;
}


extern Success
fparse_text_stat(FILE *fp,
		 Text_stat *result)
{
    int i;
    int c;

    if ( fparse_long_errors != 0 )
    {
	log("fparse_text_stat(): fparse_long_errors == %d on entry. Reset.\n",
	    fparse_long_errors);
	fparse_long_errors = 0;
    }

    result->creation_time = fparse_time(fp);

    result->author = fparse_long(fp);
    result->file_pos = fparse_long(fp);
    result->no_of_lines = fparse_long(fp);
    result->no_of_chars = fparse_long(fp);
    result->no_of_marks = fparse_long(fp);
    result->no_of_misc = fparse_long(fp);

    if ( fparse_long_errors != 0 )
    {
	log("fparse_text_stat(): %d fparse_long_errors before 'misc_items'. "
	    "Reset.\n",
	    fparse_long_errors);
	fparse_long_errors = 0;
	return FAILURE;
    }

    if ( result->no_of_misc > 0 )
    {
	fskipwhite(fp);
	switch( c = getc(fp) )
	{
	case '{':
	    result->misc_items = REALLOC(result->misc_items,
					 (result->no_of_misc
					  * sizeof(Misc_info)));

	    if ( result->misc_items == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }
	    
	    for ( i = 0; i < result->no_of_misc; i++)
		if ( fparse_misc_info(fp, &result->misc_items[ i ]) != OK )
		    return FAILURE;
	    
	    fskipwhite(fp);
	    if ( (c = getc(fp)) != '}' )
	    {
#ifdef DISKERR
		if ( c == '@' || c == '+' )
		{
		    ungetc(c, fp);
		    log("fparse_text_stat(): got '%c' when expecting '}'.\n."
			"Character ungetc'd and interpreted as a '}'."
			" (pos %d).\n", c, ftell(fp));
		}
		else
#endif
		{
		    log("fparse_text_stat(): expected '}' at pos %d.\n",
			ftell(fp));
		    kom_errno = KOM_SERVER_IS_CRAZY;
		    return FAILURE;
		}
	    }

	    break;

	case '@':
	case '+':
	    ungetc(c, fp);
	    log("fparse_text_stat(): got '%c' when expecting '{' or '*'\n."
		"Character ungetc'd and interpreted as a '*'. (pos %d).\n",
		c, ftell(fp));
	    /* Fall through */
	case '*':
	    if ( result->misc_items != NULL )
	    {
		sfree(result->misc_items);
		result->misc_items = NULL;
	    }
	    break;

	default:
	    log("fparse_text_stat(): expected '*' or '}' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( (c = getc(fp)) != '*' ) 
	{
#ifdef DISKERR
	    if ( c == '@' || c == '+' )
	    {
		ungetc(c, fp);
		log("fparse_text_stat(): got '%c' when expecting '*'.\n."
		    "Character ungetc'd and interpreted as a '*'."
		    " (pos %d).\n", c, ftell(fp));
	    }
	    else
#endif
	    {
		log("fparse_text_stat(): expected '*' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	}

	if ( result->misc_items != NULL )
	{
	    sfree(result->misc_items);
	    result->misc_items = NULL;
	}
    }

    fskipwhite(fp);

    return OK;
}	


extern Success
fparse_text_list(FILE *fp,
		Text_list *result)
{
    int i;

    result->first_local_no = fparse_long(fp);
    result->no_of_texts = fparse_long(fp);

    if ( result->no_of_texts > 0 )
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    result->texts = REALLOC(result->texts,
				    (result->no_of_texts
				     * sizeof(Text_no)));

	    if ( result->texts == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }
	    
	    for ( i = 0; i < result->no_of_texts; i++)
		result->texts[ i ] = fparse_long(fp);
	    
	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		log("fparse_text_list(): expected '}' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	    
	    break;

	case '*':
	    if ( result->texts != NULL )
	    {
		sfree(result->texts);
		result->texts = NULL;
	    }
	    break;

	default:
	    log("fparse_text_list(): expected '*' or '{' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_text_list(): expected '*' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
	if ( result->texts != NULL )
	{
	    sfree(result->texts);
	    result->texts = NULL;
	}
    }
    return OK;
}
    

extern Success
fparse_info(FILE *fp,
	   Info *result)
{
    result->version = fparse_long(fp);
    result->conf_pres_conf = fparse_long(fp);
    result->pers_pres_conf = fparse_long(fp);
    result->motd_conf = fparse_long(fp);
    result->kom_news_conf = fparse_long(fp);
    result->motd_of_lyskom = fparse_long(fp);
    return OK;
}


extern Success
fparse_string(FILE *fp,
	     String *result)
{
    String_size length;
   
    length = fparse_long(fp);

    if ( getc(fp) != 'H' )
    {
	log("fparse_string(): expected 'H' at pos %d.\n",
	    ftell(fp));
	kom_errno = KOM_SERVER_IS_CRAZY;
	return FAILURE;
    }

    s_size_crea_str(result, length);
    
    if ( result->string == NULL )
    {
	kom_errno = KOM_OUT_OF_MEMORY;
	return FAILURE;
    }
    
    if ( fread(result->string, sizeof(char), result->len, fp)
	!= result->len )
    {
	log("fparse_string(): unexpected eof at pos %d.\n", ftell(fp));
	kom_errno = KOM_SERVER_IS_CRAZY;
	return FAILURE;
    }
    
    return OK;
}

extern Success
fparse_member_list(FILE *fp,
		  Member_list *result)
{
    int i;

    result->no_of_members = fparse_long(fp);
    if ( result->no_of_members > 0 )
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    result->members = REALLOC(result->members,
				      (result->no_of_members
				       * sizeof(Member)));

	    if ( result->members == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }
	    
	    for ( i = 0; i < result->no_of_members; i++)
		if ( fparse_member(fp, &result->members[ i ]) != OK )
		{
		    return FAILURE;
		}
	    
	    
	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		log("fparse_member_list(): expected '}' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	    
	    break;

	case '*':
	    if ( result->members != NULL )
	    {
		sfree(result->members);
		result->members = NULL;
	    }
	    break;

	default:
	    log("fparse_member_list(): expected '*' or '{' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_member_list(): expected '*' at pos %d.\n", ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
	if ( result->members != NULL )
	{
	    sfree(result->members);
	    result->members = NULL;
	}
    }
    return OK;
}


extern Success
fparse_member(FILE *fp,
	     Member *result)
{
    result->member = fparse_long(fp);
    return OK;
}

extern Success
fparse_mark(FILE *fp,
	   Mark *result)
{
    result->text_no = fparse_long(fp);
    result->mark_type = fparse_long(fp);
    return OK;
}


extern Success
fparse_priv_bits(FILE *fp,
		Priv_bits *result)
{
    fskipwhite(fp);

    result->wheel = getc(fp) != '0';
    result->admin = getc(fp) != '0';
    result->statistic = getc(fp) != '0';
    result->create_pers = getc(fp) != '0';
    result->create_conf = getc(fp) != '0';
    result->change_name = getc(fp) != '0';
    result->extern_gw = getc(fp) != '0';
    result->flg8 = getc(fp) != '0';
    result->flg9 = getc(fp) != '0';
    result->flg10 = getc(fp) != '0';
    result->flg11 = getc(fp) != '0';
    result->flg12 = getc(fp) != '0';
    result->flg13 = getc(fp) != '0';
    result->flg14 = getc(fp) != '0';
    result->flg15 = getc(fp) != '0';
    result->flg16 = getc(fp) != '0';

    return OK;
}


extern Success
fparse_personal_flags(FILE *fp,
		     Personal_flags *result)
{
    fskipwhite(fp);
    
    result->unread_is_secret = getc(fp) != '0';
    result->flg2 = getc(fp) != '0';
    result->flg3 = getc(fp) != '0';
    result->flg4 = getc(fp) != '0';
    result->flg5 = getc(fp) != '0';
    result->flg6 = getc(fp) != '0';
    result->flg7 = getc(fp) != '0';
    result->flg8 = getc(fp) != '0';

    return OK;
}	

extern Success
fparse_conf_type(FILE *fp,
		Conf_type *result)
{
    fskipwhite(fp);
    
    result->rd_prot = getc(fp) != '0';
    result->original = getc(fp) != '0';
    result->secret = getc(fp) != '0';
    result->letter_box = getc(fp) != '0';

    return OK;
}


extern Success
fparse_who_info(FILE *fp,
	       Who_info *result)
{
    result->person = fparse_long(fp);
    result->working_conference = fparse_long(fp);
    if ( fparse_string(fp, &result->what_am_i_doing) != OK )
    {
	log("fparse_who_info(): parse error.\n");
	kom_errno = KOM_SERVER_IS_CRAZY;
	return FAILURE;
    }

    return OK;
}

    
extern Success
fparse_who_info_list(FILE *fp,
		     Who_info_list *result)
{
    int i;
    
    fskipwhite(fp);

    result->no_of_persons = fparse_long(fp);
    
    if ( result->no_of_persons > 0 )
    {
	fskipwhite(fp);
	switch(getc(fp))
	{
	case '{':
	    result->info = REALLOC(result->info,
				   (result->no_of_persons
				    * sizeof(Who_info)));

	    if ( result->info == NULL )
	    {
		kom_errno = KOM_OUT_OF_MEMORY;
		return FAILURE;
	    }
	    
	    for ( i = 0; i < result->no_of_persons; i++)
	    {
		result->info[ i ] = EMPTY_WHO_INFO;
		if ( fparse_who_info(fp, &result->info[ i ]) != OK )
		    return FAILURE;
	    }
	    
	    
	    fskipwhite(fp);
	    if ( getc(fp) != '}' )
	    {
		log("fparse_who_info_list(): expected '}' at pos %d.\n",
		    ftell(fp));
		kom_errno = KOM_SERVER_IS_CRAZY;
		return FAILURE;
	    }
	    
	    break;

	case '*':
	    if ( result->info != NULL )
	    {
		sfree(result->info);
		result->info = NULL;
	    }
	    break;

	default:
	    log("fparse_who_info_list(): expected '*' or '{' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
    }
    else
    {
	fskipwhite(fp);
	if ( getc(fp) != '*' ) 
	{
	    log("fparse_who_info_list(): expected '*' at pos %d.\n",
		ftell(fp));
	    kom_errno = KOM_SERVER_IS_CRAZY;
	    return FAILURE;
	}
	if ( result->info != NULL )
	{
	    sfree(result->info);
	    result->info = NULL;
	}
    }
    return OK;
}

extern Success
fparse_misc_info(FILE *fp, 
		 Misc_info *result)
{
    result->type = fparse_long(fp);
    
    switch(result->type)
    {
    case recpt:
	result->datum.recipient = fparse_long(fp);
	break;
	
    case cc_recpt:
	result->datum.cc_recipient = fparse_long(fp);
	break;
	
    case loc_no:
	result->datum.local_no = fparse_long(fp);
	break;
	
    case rec_time:
	result->datum.received_at = fparse_time(fp);
	break;
	
    case comm_to:
	result->datum.comment_to = fparse_long(fp);
	break;
	
    case comm_in:
	result->datum.commented_in = fparse_long(fp);
	break;
	
    case footn_to:
	result->datum.footnote_to = fparse_long(fp);
	break;
	
    case footn_in:
	result->datum.footnoted_in = fparse_long(fp);
	break;
	
    case sent_by:
	result->datum.sender = fparse_long(fp);
	break;
	
    case sent_at:
	result->datum.sent_at = fparse_time(fp);
	break;

    default:
	log("fparse_misc_info(): illegal info_type %d at pos %d.\n",
	    result->type, ftell(fp));
	kom_errno = KOM_SERVER_IS_CRAZY;
	return FAILURE;
    }

    return OK;
}