Citadel/UX Server Extension API Documentation --------------------------------------------- This is a VERY INCOMPLETE documentation of the API for extending the Citadel server using dynamically loaded modules. It really isn't an API at all, but rather a list of some of the functions available in the server which are likely to be of use to module writers. Expect this document to become more complete over time, as both the API and the person documenting it have a chance to mature a bit. :) USER RELATED FUNCTIONS ---------------------- The fundamental user data is stored in "struct usersupp" which is defined in citadel.h. The following functions are available: int getuser(struct usersupp *usbuf, char name[]) Given the name of a requested user and a buffer to store the usersupp record in, getuser() will search the userlog for the named user and load its data into the buffer. getuser() returns 0 upon success or a nonzero error code if the requested operation could not be performed. void putuser(struct usersupp *usbuf, char *name) After reading in a user record with getuser() and perhaps modifying the data in some way, a program may use putuser() to write it back to disk. int lgetuser(struct usersupp *usbuf, char *name) void lputuser(struct usersupp *usbuf, char *name) If critical-section operation is required, this pair of calls may be used. They function the same as getuser() and putuser(), except that lgetuser() locks the user file immediately after retrieving the record and lputuser() unlocks it. This will guarantee that no other threads manipulate the same user record at the same time. NOTE: do NOT attempt to combine the locking lgetuser/lputuser calls with any other locking calls in this API. Attempting to obtain concurrent locks on multiple files may result in a deadlock condition which would freeze the entire server. void ForEachUser(void (*CallBack)(struct usersupp *EachUser)) This allows a user-supplied function to be called once for each user on the system. The user-supplied function will be called with a pointer to a usersupp structure as its only argument. int getuserbynumber(struct usersupp *usbuf, long int number) getuserbynumber() functions similarly to getuser(), except that it is supplied with a user number rather than a name. Calling this function results in a sequential search of the user file, so use it sparingly if at all. int purge_user(char *pname) This function deletes the named user off the system and erases all related objects: bio, photo, etc. It returns 0 upon success or a nonzero error code if the requested operation could not be performed. HOW TO REGISTER FUNCTION HOOKS ------------------------------ The truly powerful part of the Citadel API is the ability for extensions to register "hooks" -- user-supplied functions will be called while the server is performing various tasks. Here are the API calls to register hooks: void CtdlRegisterProtoHook(void (*handler)(char *), char *cmd, char *desc) Adds a new server command to the system. The handler function should accept a single string parameter, which will be set to a string containing any parameters the client software sent along with the server command. "cmd" should be the four-character mnemonic the server command is known by, and "desc" is a description of the new command. void CtdlRegisterCleanupHook(void *fcn_ptr) Registers a new function to be called whenever the server is shutting down. Cleanup functions accept no parameters. void CtdlRegisterSessionHook(void *fcn_ptr, int EventType) Registers a session hook. Session hooks accept no parameters. There are multiple types of session hooks; the server extension registers which one it is interested in by setting the value of EventType. The available session hook types are: #define EVT_STOP 0 /* Session is terminating */ #define EVT_START 1 /* Session is starting */ #define EVT_LOGIN 2 /* A user is logging in */ #define EVT_NEWROOM 3 /* Changing rooms */ #define EVT_LOGOUT 4 /* A user is logging out */ #define EVT_SETPASS 5 /* Setting or changing password */ void CtdlRegisterUserHook(void *fcn_ptr, int EventType) Registers a user hook. User hooks accept two parameters: a string pointer containing the user name, and a long which *may* contain a user number (only applicable for certain types of hooks). The available user hook types are: #define EVT_PURGEUSER 100 /* Deleting a user */ #define EVT_OUTPUTMSG 101 /* Outputting a message */ FUNCTIONS WHICH MANIPULATE USER/ROOM RELATIONSHIPS void CtdlGetRelationship(struct visit *vbuf, struct usersupp *rel_user, struct quickroom *rel_room); void CtdlSetRelationship(struct visit *newvisit, struct usersupp *rel_user, struct quickroom *rel_room); These functions get/set a "struct visit" structure which may contain information about the relationship between a user and a room. Specifically: struct visit { char v_roomname[20]; long v_generation; long v_lastseen; unsigned int v_flags; }; #define V_FORGET 1 /* User has zapped this room */ #define V_LOCKOUT 2 /* User is locked out of this room */ #define V_ACCESS 4 /* Access is granted to this room */ Don't change v_roomname or v_generation; they're used to identify the room being referred to. A room is unique to the system by its combination of room name and generation number. If a new room is created with the same name as a recently deleted room, it will have a new generation number, and therefore stale "visit" records will not be applied (and will eventually be purged). v_lastseen contains the number of the newest message the user has read in this room. Any existing messages higher than this number can be considered as "new messages." v_flags contains information regarding access to the room. int CtdlRoomAccess(struct quickroom *roombuf, struct usersupp *userbuf) This is a convenience function which uses CtdlGetRelationship() to determine whether a user has access to a room. It returns a bucket of bits which may contain: #define UA_INUSE 1 /* Room exists */ #define UA_KNOWN 2 /* Room is in user's Known list */ #define UA_GOTOALLOWED 4 /* User may <.G>oto this room */ #define UA_HASNEWMSGS 8 /* Room contains new messages */ #define UA_ZAPPED 16 /* User has forgotten this room */ ROOM RELATED FUNCTIONS ---------------------- unsigned create_room(char *new_room_name, int new_room_type, char *new_room_pass, int new_room_floor, int really_create) This function is used to create a new room. new_room_name should be set to the desired name for the new room. new_room_type should be set to 0 for a public room, 1 for a guessname room, 2 for a passworded room, 3 for an invitation-only room, or 4 for a personal room (a mailbox). If the room is a type 2 (passworded) room, new_room_pass should be set to the desired password. new_room_floor should be set to the number of the floor upon which the new room should reside. If the room is really to be created, set really_create to 1. Otherwise, the caller may merely check to see if it's possible to create the room without actually creating it by setting really_create to 0. create_room() returns the flags associated with the new room (as in the data structure item quickroom.QRflags). If the room cannot be created (for example, a room with the name already exists), it returns 0.