Commit 6e33ec06 authored by Per Cederqvist's avatar Per Cederqvist
Browse files

Checked into RCS.

parent 18b5cd74
/*
* admin.c
*
* Administrative calls.
*/
#include <stdlib.h>
#include "lyskomd.h"
#include <kom-types.h>
#include <services.h>
#include "manipulate.h"
#include "smalloc.h"
#include "cache.h"
#include "log.h"
#include "admin.h"
#include <kom-errno.h>
#include "com.h"
#include "connections.h"
#include "send-async.h"
#include "config.h"
Info kom_info =
{
#include "version.incl"
, /* version */
1, /* conf_pres_conf */
2, /* pers_pres_conf */
3, /* motd_conf */
4, /* kom_news_conf */
0 /* motd_of_lyskom */
};
/*
* Return info about this server. This can (and should) be done
* before logging in. modt_of_lyskom should be displayed before
* prompting for username if it isn't 0.
*/
extern Success
get_info( Info *result )
{
*result = kom_info;
return OK;
}
/* /// */
extern Success
set_motd_of_lyskom (Text_no motd)
{
Text_stat *old_motd = NULL;
Text_stat *new_motd = NULL;
CHK_LOGIN(FAILURE);
if ( !ENA(admin, 1) )
{
kom_errno = KOM_PERM;
return FAILURE;
}
/* Check that the new motd exists before deleting the old*/
if ( motd != 0 )
{
GET_T_STAT(new_motd, motd, FAILURE);
if ( new_motd->no_of_marks >= MAX_MARKS_TEXT )
{
log(
"LIMIT: set_motd_of_lyskom(): New motd very marked.\n");
return FAILURE;
}
}
/* Unmark the previous motd if it exists. */
if ( kom_info.motd_of_lyskom != 0
&& (old_motd = cached_get_text_stat(kom_info.motd_of_lyskom)) != NULL)
{
if ( old_motd->no_of_marks > 0 )
{
--old_motd->no_of_marks;
mark_text_as_changed( kom_info.motd_of_lyskom );
}
else
{
log("ERROR: do_set_motd(): Old motd not marked\n");
}
}
/* Mark the new motd */
if ( motd != 0 )
{
++new_motd->no_of_marks;
mark_text_as_changed( motd );
}
kom_info.motd_of_lyskom = motd;
return OK;
}
/*
* Force all clients to read a message.
* Sends an asynchronous message. This is obsoleted by send_message.
*/
extern Success
broadcast (String message)
{
CHK_LOGIN(FAILURE);
async_broadcast(ACTPERS, message);
return OK;
}
/*
* Send a message
*/
extern Success
send_message (Pers_no recipient,
const String message)
{
CHK_LOGIN(FAILURE);
return async_send_message(recipient, ACTPERS, message);
}
/*
* Make LysKOM sync its files.
*/
extern Success
sync (void)
{
cache_sync_all();
dump_statistics();
return OK;
}
/*
* Close LysKOM. exit_val is (currently) not used. The database is synced.
*/
extern Success
shutdown (int exit_val)
{
CHK_LOGIN(FAILURE);
if ( !ENA(admin, 1) )
{
kom_errno = KOM_PERM;
return FAILURE;
}
go_and_die = TRUE;
return OK;
}
/*
* admin.h
*/
extern Info kom_info;
/*
* This file contains the cached data that the server stores.
* .h file created by ceder 1990-04-18
*/
/* cache_sync_all only returns when everything is written to disk. */
extern void
cache_sync_all(void);
/* First, some things which I want here. /ceder */
extern struct matching_info *match_table;
extern void
cached_lock_conf(Conf_no conf_no);
extern Success
init_cache(void);
extern void
cached_unlock_conf(Conf_no conf);
extern void
cached_lock_person(Pers_no pers);
extern void
cached_unlock_person(Pers_no pers);
extern Success
cached_delete_person(Pers_no pres);
extern Success
cached_delete_text(Text_no text);
extern Success
build_matching_info(void);
extern void /* Write out everything. */
cache_sync(void);
/* S}d{r ja. Tack f|r mig. /ceder */
#define MAX_CACHED_PERSONS 5 /* To be increased after debugging */
#define MAX_CACHED_WHATEVER /* To be added */
/*
* Name caching routines
*/
/*
* change_name changes the cached conference name. It is only called when
* a conference name is changed or a conference is deleted.
*
* cached_change_name(foo, EMPTY_STRING); should be used when a conference
* is deleted. (Eller ska det vara annorlunda? S} g|r jag nu... /ceder)
*/
extern void
cached_change_name(Conf_no name_num,
String new_name );
/* add_name adds a name to the list of cached conference names. It is only
* used when a new conference is created.
*/
extern void
cached_add_name( char * new_name );
/* load all the conference names from disk and store them in memory */
extern void
cached_load_names( void );
#if 0
/* get one name (I want this call! /ceder) */
/* I no longer want it. */
extern String
cached_get_name( Conf_no conf_no ); /* Returns NULL if the conference */
/* doesn't exist. */
#endif
extern Bool
cached_conf_exists( Conf_no conf_no );
/*
* Calls for the cacheing of conf_type:
* cached_get_conf_type() returns the type, and
* cached_set_conf_type() sets the type.
*/
/* Get conference type */
/* Undefined result if the conf doesn't exist. */
extern Conf_type
cached_get_conf_type (Conf_no conf_no);
/*
* Set the type. This call is used whenever a conference is created or the
* conf_type is changed.
*/
extern void
cached_set_conf_type (Conf_no conf_no,
Conf_type type);
/*
* Get/set garb_nice for a certain conference.
*/
extern Garb_nice
cached_get_garb_nice (Conf_no conf_no);
extern void
cached_set_garb_nice (Conf_no conf_no,
Garb_nice nice);
extern Local_text_no
cached_get_highest_local_no (Conf_no conf_no);
/*
* Person caching routines
*/
#if 0
extern Person *
cached_read_person( Pers_no pers_no );
#endif
/*
* Various function calls to tell the cache that something is changed.
*/
void
mark_person_as_changed(Pers_no pers_no);
void
mark_conference_as_changed(Conf_no conf_no);
void
mark_text_as_changed(Text_no text_no);
/*
* Person-related calls
*/
extern Success
cached_create_person( Pers_no person );
extern Person *
cached_get_person_stat( Pers_no person ); /* Returns NULL if person
doesn't exist */
/*
* Conference-related calls
*/
extern Conf_no
cached_create_conf( String name );
extern Success
cached_delete_conf( Conf_no conf );
extern Success
cached_lookup_name(const String name,
Conf_list_old *result);
extern Conference *
cached_get_conf_stat( Conf_no conf_no );
/*
* Calls to handle texts
*/
extern String
cached_get_text( Text_no text );/* The string should be free'd by the caller */
extern Text_stat *
cached_get_text_stat( Text_no text );
extern Text_no
cached_create_text( String message);
/*
* traverse_text can be used to cycle through all existing texts. 0 will
* be returned once in the "cycle".
*/
extern Text_no
traverse_text(Text_no seed);
/*
* traverse_person can be used to cycle through all existing persons. 0 will
* be returned once in the "cycle".
*/
extern Pers_no
traverse_person(Pers_no seed);
/*
* traverse_conference can be used to cycle through all existing conferences.
* 0 will be returned once in the "cycle".
*/
extern Conf_no
traverse_conference(Conf_no seed);
/*
* conference.c
*
* All atomic calls that deals with conferences.
*/
#include <time.h>
#include <ctype.h>
#include <stdlib.h>
#include "lyskomd.h"
#include <kom-types.h>
#include <services.h>
#include "manipulate.h"
#include <kom-errno.h>
#include "smalloc.h"
#include "cache.h"
#include "log.h"
#include <config.h>
#include "com.h"
#include "connections.h"
#include "send-async.h"
#include <debug.h>
#include "parser.h"
#include "internal-connections.h"
/* From ram-cache.h. This will go away when we use regexp-matching. This is
* only temporary. +++***
*/
extern Conf_no *conf_table;
/*
* Static functions
*/
/*
* Delete a conference. Delete all references to this conf.
*/
static void
do_delete_conf (Conf_no conf_no,
Conference * conf_c) /* Not NULL */
{
int i;
if ( do_set_presentation(conf_no, conf_c, 0) != OK )
{
log("ERROR: do_delete_conf() - couldn't unmark presentation.\n");
}
if ( do_set_etc_motd(conf_no, conf_c, 0) != OK )
{
log("ERROR: do_delete_conf() - couldn't unmark motd.\n");
}
/* Delete all members */
/* Note that because of the way do_sub_member is written it is important */
/* that the loop is executed this way. */
for ( i = conf_c->members.no_of_members - 1; i >= 0; i-- )
{
do_sub_member( conf_no, conf_c, conf_c->members.members + i,
conf_c->members.members[ i ].member, NULL, NULL);
}
sfree( conf_c->members.members );
conf_c->members.members = NULL;
/* Delete the name */
s_clear( &conf_c->name );
cached_change_name( conf_no, EMPTY_STRING);
/* texts */
/*
* The texts are not deleted at once, but since they now have no recipient
* they will not live long.
*/
/* ??? Note that there will still be a recipient in the texts, but it
will not exist in reality. This might cause problems. A do_sub_recpt()
should maybe be used. */
/* Yes, do! Also, send out asynchronous message about deleted conf. */
sfree( conf_c->texts.texts );
conf_c->texts.texts = NULL;
cached_delete_conf( conf_no );
return;
}
/*
* Functions that are exported to the server.
*/
/*
* Return TRUE if NAME is not already used.
*/
Bool
legal_name( String name )
{
if (name.len == 0 || name.len > CONF_NAME_LEN )
{
return FALSE;
}
while( name.len-- )
{
if ( !isascii( *name.string ) || !isprint( *name.string )
/*???|| *name.string == '"'*/ )
{
return FALSE;
}
name.string++;
}
return TRUE;
}
/*
* Return TRUE if name is unique, or if the only match is conf_no. Use 0
* as conf_no if it should not be allowed to be changed.
*/
Bool
unique_name( const String name, Conf_no conf_no )
{
Parse_info parse_info;
Parse_token *name_token;
Parse_token *existing_token;
Bool exact_match_found;
Bool diff_found;
int i;
int n;
parse_info = parse(name, match_table, FALSE, TRUE,
s_fcrea_str(" \t"), DEFAULT_COLLAT_TAB);
if ( parse_info.no_of_matches == 0 ) /* Doesn't match any name. */
{
sfree(parse_info.indexes);
return TRUE;
}
if ( parse_info.no_of_matches == -1 ) /* Error. */
{
log("unique_name(): parse returned error.\n");
sfree(parse_info.indexes);
return FALSE;
}
if ( parse_info.no_of_matches == 1 && parse_info.indexes[ 0 ] == -1 )
{
/* Empty name is not allowed. */
sfree(parse_info.indexes);
return FALSE;
}
/* The name matches some conference. Check if they are equal. */
name_token = tokenize(name, s_fcrea_str(" \t"));
exact_match_found = FALSE;
for ( i = 0; !exact_match_found && i < parse_info.no_of_matches; i++ )
{
existing_token = match_table[ parse_info.indexes[ i ] ].tokens;
diff_found = FALSE;
for ( n = 0;
(!diff_found && !s_empty(existing_token[ n ].word)
&& !s_empty(name_token[ n ].word));
++n)
{
if ( !s_usr_streq(existing_token[ n ].word,
name_token[ n ].word,
DEFAULT_COLLAT_TAB) )
{
diff_found = TRUE;
}
}
if (! s_empty(existing_token[ n ].word)
|| ! s_empty(name_token[ n ].word) )
{
/* The length (number of words) differed. */
diff_found = TRUE;
}
if ( !diff_found && conf_no != 0
&& conf_table[ parse_info.indexes[ i ] ] != conf_no )
exact_match_found = TRUE;
}
sfree(parse_info.indexes);
free_tokens(name_token);
return exact_match_found ? FALSE : TRUE;
}
/*
* Create a conference.
*/
Conf_no
do_create_conf(String name,
Pers_no creator,
Conf_no supervisor,
Conf_no super_conf,
Conf_type type)
{
Conf_no conf_no;
Conference * conf_c;
/* Allocate memory for conf_c */
conf_no = cached_create_conf( name );
if ( (conf_c = cached_get_conf_stat( conf_no ) ) == NULL)
{
restart_kom("create_conf() - can't get conf_stat");
}
conf_c->creator = creator;
conf_c->creation_time = time(NULL);
conf_c->presentation= 0; /* No presentation yet */
conf_c->supervisor = supervisor;
conf_c->permitted_submitters = 0;
conf_c->super_conf = super_conf;
conf_c->type = type;
conf_c->last_written= conf_c->creation_time;
conf_c->msg_of_day = 0;
conf_c->nice = DEFAULT_NICE;
conf_c->members = EMPTY_MEMBER_LIST;
conf_c->texts = EMPTY_TEXT_LIST;
mark_conference_as_changed( conf_no );
cached_set_conf_type( conf_no, type );
return conf_no;
}
/*
* Return TRUE if ACTPERS is a supervisor to CONF.
*/
Bool
is_supervisor(Conf_no conf,
Conference * conf_c)/* Conference status for CONF, can be NULL */
{
if (!ACTPERS)
return FALSE;
if (ENA(wheel, 8))
return TRUE;
if (ACTPERS == conf) /* A person is ALWAYS supervisor to */
return TRUE; /* his/her own mailbox! */