Пример #1
0
/*
 * smtp_queue_thread()
 *
 * Run through the queue sending out messages.
 */
void smtp_do_queue(void) {
	int num_processed = 0;
	int num_activated = 0;

	pthread_setspecific(MyConKey, (void *)&smtp_queue_CC);
	SMTPCM_syslog(LOG_DEBUG, "processing outbound queue");

	if (CtdlGetRoom(&CC->room, SMTP_SPOOLOUT_ROOM) != 0) {
		SMTPC_syslog(LOG_ERR, "Cannot find room <%s>", SMTP_SPOOLOUT_ROOM);
	}
	else {
		num_processed = CtdlForEachMessage(MSGS_ALL,
						   0L,
						   NULL,
						   SPOOLMIME,
						   NULL,
						   smtp_do_procmsg,
						   &num_activated);
	}
	if (num_activated > 0) {
		SMTPC_syslog(LOG_INFO,
			     "queue run completed; %d messages processed %d activated",
			     num_processed, num_activated);
	}

}
Пример #2
0
/*
 * get room parameters (admin or room admin command)
 */
void cmd_getr(char *cmdbuf)
{
	if (CtdlAccessCheck(ac_room_aide)) return;

	CtdlGetRoom(&CC->room, CC->room.QRname);
	cprintf("%d%c%s|%s|%s|%d|%d|%d|%d|%d|\n",
		CIT_OK,
		CtdlCheckExpress(),

		((CC->room.QRflags & QR_MAILBOX) ?
			&CC->room.QRname[11] : CC->room.QRname),

		((CC->room.QRflags & QR_PASSWORDED) ?
			CC->room.QRpasswd : ""),

		((CC->room.QRflags & QR_DIRECTORY) ?
			CC->room.QRdirname : ""),

		CC->room.QRflags,
		(int) CC->room.QRfloor,
		(int) CC->room.QRorder,

		CC->room.QRdefaultview,
		CC->room.QRflags2
		);
}
Пример #3
0
/*
 * Scan a room for messages to index.
 */
void ft_index_room(struct ctdlroom *qrbuf, void *data)
{
	if (server_shutting_down)
		return;
		
	CtdlGetRoom(&CC->room, qrbuf->QRname);
	CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, ft_index_msg, NULL);
}
Пример #4
0
/*
 * Fetch the "mortuary" - a list of dead buddies which we keep around forever
 * so we can remove them from any client's roster that still has them listed
 */
HashList *xmpp_fetch_mortuary(void) {
	HashList *mortuary = NewHash(1, NULL);
	if (!mortuary) {
		syslog(LOG_ALERT, "NewHash() failed!\n");
		return(NULL);
	}

        if (CtdlGetRoom(&CC->room, USERCONFIGROOM) != 0) {
		/* no config room exists - no further processing is required. */
                return(mortuary);
        }
        CtdlForEachMessage(MSGS_LAST, 1, NULL, XMPPMORTUARY, NULL,
                xmpp_fetch_mortuary_backend, (void *)mortuary );

	return(mortuary);
}
Пример #5
0
int PurgeRooms(void) {
	struct PurgeList *pptr;
	int num_rooms_purged = 0;
	struct ctdlroom qrbuf;
	struct ValidUser *vuptr;
	char *transcript = NULL;

	syslog(LOG_DEBUG, "PurgeRooms() called");


	/* Load up a table full of valid user numbers so we can delete
	 * user-owned rooms for users who no longer exist */
	ForEachUser(AddValidUser, NULL);

	/* Then cycle through the room file */
	CtdlForEachRoom(DoPurgeRooms, NULL);

	/* Free the valid user list */
	while (ValidUserList != NULL) {
		vuptr = ValidUserList->next;
		free(ValidUserList);
		ValidUserList = vuptr;
	}


	transcript = malloc(SIZ);
	strcpy(transcript, "The following rooms have been auto-purged:\n");

	while (RoomPurgeList != NULL) {
		if (CtdlGetRoom(&qrbuf, RoomPurgeList->name) == 0) {
			transcript=realloc(transcript, strlen(transcript)+SIZ);
			snprintf(&transcript[strlen(transcript)], SIZ, " %s\n",
				qrbuf.QRname);
			CtdlDeleteRoom(&qrbuf);
		}
		pptr = RoomPurgeList->next;
		free(RoomPurgeList);
		RoomPurgeList = pptr;
		++num_rooms_purged;
	}

	if (num_rooms_purged > 0) CtdlAideMessage(transcript, "Room Autopurger Message");
	free(transcript);

	syslog(LOG_DEBUG, "Purged %d rooms.", num_rooms_purged);
	return(num_rooms_purged);
}
Пример #6
0
/*
 * callback to get highest room number when rebuilding control file
 */
void control_find_highest(struct ctdlroom *qrbuf, void *data)
{
	struct ctdlroom room;
	struct cdbdata *cdbfr;
	long *msglist;
	int num_msgs=0;
	int c;
	int room_fixed = 0;
	int message_fixed = 0;
	
	if (qrbuf->QRnumber > CitControl.MMnextroom)
	{
		CitControl.MMnextroom = qrbuf->QRnumber;
		room_fixed = 1;
	}
		
	CtdlGetRoom (&room, qrbuf->QRname);
	
	/* Load the message list */
	cdbfr = cdb_fetch(CDB_MSGLISTS, &room.QRnumber, sizeof(long));
	if (cdbfr != NULL) {
		msglist = (long *) cdbfr->ptr;
		num_msgs = cdbfr->len / sizeof(long);
	} else {
		return;	/* No messages at all?  No further action. */
	}

	if (num_msgs>0)
	{
		for (c=0; c<num_msgs; c++)
		{
			if (msglist[c] > CitControl.MMhighest)
			{
				CitControl.MMhighest = msglist[c];
				message_fixed = 1;
			}
		}
	}
	cdb_free(cdbfr);
	if (room_fixed)
		syslog(LOG_INFO, "Control record checking....Fixed room counter\n");
	if (message_fixed)
		syslog(LOG_INFO, "Control record checking....Fixed message count\n");
	return;
}
Пример #7
0
/*
 * set room parameters (admin or room admin command)
 */
void cmd_setr(char *args)
{
	char buf[256];
	int new_order = 0;
	int r;
	int new_floor;
	char new_name[ROOMNAMELEN];

	if (CtdlAccessCheck(ac_logged_in)) return;

	if (num_parms(args) >= 6) {
		new_floor = extract_int(args, 5);
	} else {
		new_floor = (-1);	/* don't change the floor */
	}

	/* When is a new name more than just a new name?  When the old name
	 * has a namespace prefix.
	 */
	if (CC->room.QRflags & QR_MAILBOX) {
		sprintf(new_name, "%010ld.", atol(CC->room.QRname) );
	} else {
		safestrncpy(new_name, "", sizeof new_name);
	}
	extract_token(&new_name[strlen(new_name)], args, 0, '|', (sizeof new_name - strlen(new_name)));

	r = CtdlRenameRoom(CC->room.QRname, new_name, new_floor);

	if (r == crr_room_not_found) {
		cprintf("%d Internal error - room not found?\n", ERROR + INTERNAL_ERROR);
	} else if (r == crr_already_exists) {
		cprintf("%d '%s' already exists.\n",
			ERROR + ALREADY_EXISTS, new_name);
	} else if (r == crr_noneditable) {
		cprintf("%d Cannot edit this room.\n", ERROR + NOT_HERE);
	} else if (r == crr_invalid_floor) {
		cprintf("%d Target floor does not exist.\n",
			ERROR + INVALID_FLOOR_OPERATION);
	} else if (r == crr_access_denied) {
		cprintf("%d You do not have permission to edit '%s'\n",
			ERROR + HIGHER_ACCESS_REQUIRED,
			CC->room.QRname);
	} else if (r != crr_ok) {
		cprintf("%d Error: CtdlRenameRoom() returned %d\n",
			ERROR + INTERNAL_ERROR, r);
	}

	if (r != crr_ok) {
		return;
	}

	CtdlGetRoom(&CC->room, new_name);

	/* Now we have to do a bunch of other stuff */

	if (num_parms(args) >= 7) {
		new_order = extract_int(args, 6);
		if (new_order < 1)
			new_order = 1;
		if (new_order > 127)
			new_order = 127;
	}

	CtdlGetRoomLock(&CC->room, CC->room.QRname);

	/* Directory room */
	extract_token(buf, args, 2, '|', sizeof buf);
	buf[15] = 0;
	safestrncpy(CC->room.QRdirname, buf,
		sizeof CC->room.QRdirname);

	/* Default view */
	if (num_parms(args) >= 8) {
		CC->room.QRdefaultview = extract_int(args, 7);
	}

	/* Second set of flags */
	if (num_parms(args) >= 9) {
		CC->room.QRflags2 = extract_int(args, 8);
	}

	/* Misc. flags */
	CC->room.QRflags = (extract_int(args, 3) | QR_INUSE);
	/* Clean up a client boo-boo: if the client set the room to
	 * guess-name or passworded, ensure that the private flag is
	 * also set.
	 */
	if ((CC->room.QRflags & QR_GUESSNAME)
	    || (CC->room.QRflags & QR_PASSWORDED))
		CC->room.QRflags |= QR_PRIVATE;

	/* Some changes can't apply to BASEROOM */
	if (!strncasecmp(CC->room.QRname, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)) {
		CC->room.QRorder = 0;
		CC->room.QRpasswd[0] = '\0';
		CC->room.QRflags &= ~(QR_PRIVATE & QR_PASSWORDED &
			QR_GUESSNAME & QR_PREFONLY & QR_MAILBOX);
		CC->room.QRflags |= QR_PERMANENT;
	} else {	
		/* March order (doesn't apply to AIDEROOM) */
		if (num_parms(args) >= 7)
			CC->room.QRorder = (char) new_order;
		/* Room password */
		extract_token(buf, args, 1, '|', sizeof buf);
		buf[10] = 0;
		safestrncpy(CC->room.QRpasswd, buf,
			    sizeof CC->room.QRpasswd);
		/* Kick everyone out if the client requested it
		 * (by changing the room's generation number)
		 */
		if (extract_int(args, 4)) {
			time(&CC->room.QRgen);
		}
	}
	/* Some changes can't apply to AIDEROOM */
	if (!strncasecmp(CC->room.QRname, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)) {
		CC->room.QRorder = 0;
		CC->room.QRflags &= ~QR_MAILBOX;
		CC->room.QRflags |= QR_PERMANENT;
	}

	/* Write the room record back to disk */
	CtdlPutRoomLock(&CC->room);

	/* Create a room directory if necessary */
	if (CC->room.QRflags & QR_DIRECTORY) {
		snprintf(buf, sizeof buf,"%s/%s",
				 ctdl_file_dir,
				 CC->room.QRdirname);
		mkdir(buf, 0755);
	}
	snprintf(buf, sizeof buf, "The room \"%s\" has been edited by %s.\n",
		CC->room.QRname,
		(CC->logged_in ? CC->curr_user : "******")
	);
	CtdlAideMessage(buf, "Room modification Message");
	cprintf("%d Ok\n", CIT_OK);
}
Пример #8
0
/*
 * RDIR command for room directory
 */
void cmd_rdir(char *cmdbuf)
{
	char buf[256];
	char comment[256];
	FILE *fd;
	struct stat statbuf;
	DIR *filedir = NULL;
	struct dirent *filedir_entry;
	int d_namelen;
	char buf2[SIZ];
	char mimebuf[64];
	long len;
	
	if (CtdlAccessCheck(ac_logged_in)) return;
	
	CtdlGetRoom(&CC->room, CC->room.QRname);
	CtdlGetUser(&CC->user, CC->curr_user);

	if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
		cprintf("%d not here.\n", ERROR + NOT_HERE);
		return;
	}
	if (((CC->room.QRflags & QR_VISDIR) == 0)
	    && (CC->user.axlevel < AxAideU)
	    && (CC->user.usernum != CC->room.QRroomaide)) {
		cprintf("%d not here.\n", ERROR + HIGHER_ACCESS_REQUIRED);
		return;
	}

	snprintf(buf, sizeof buf, "%s/%s", ctdl_file_dir, CC->room.QRdirname);
	filedir = opendir (buf);
	
	if (filedir == NULL) {
		cprintf("%d not here.\n", ERROR + HIGHER_ACCESS_REQUIRED);
		return;
	}
	cprintf("%d %s|%s/%s\n", LISTING_FOLLOWS, CtdlGetConfigStr("c_fqdn"), ctdl_file_dir, CC->room.QRdirname);
	
	snprintf(buf, sizeof buf, "%s/%s/filedir", ctdl_file_dir, CC->room.QRdirname);
	fd = fopen(buf, "r");
	if (fd == NULL)
		fd = fopen("/dev/null", "r");
	while ((filedir_entry = readdir(filedir)))
	{
		if (strcasecmp(filedir_entry->d_name, "filedir") && filedir_entry->d_name[0] != '.')
		{
#ifdef _DIRENT_HAVE_D_NAMELEN
			d_namelen = filedir_entry->d_namlen;
#else
			d_namelen = strlen(filedir_entry->d_name);
#endif
			snprintf(buf, sizeof buf, "%s/%s/%s", ctdl_file_dir, CC->room.QRdirname, filedir_entry->d_name);
			stat(buf, &statbuf);	/* stat the file */
			if (!(statbuf.st_mode & S_IFREG))
			{
				snprintf(buf2, sizeof buf2,
					"\"%s\" appears in the file directory for room \"%s\" but is not a regular file.  Directories, named pipes, sockets, etc. are not usable in Citadel room directories.\n",
					buf, CC->room.QRname
				);
				CtdlAideMessage(buf2, "Unusable data found in room directory");
				continue;	/* not a useable file type so don't show it */
			}
			safestrncpy(comment, "", sizeof comment);
			fseek(fd, 0L, 0);	/* rewind descriptions file */
			/* Get the description from the descriptions file */
			while ((fgets(buf, sizeof buf, fd) != NULL) && (IsEmptyStr(comment))) 
			{
				buf[strlen(buf) - 1] = 0;
				if ((!strncasecmp(buf, filedir_entry->d_name, d_namelen)) && (buf[d_namelen] == ' '))
					safestrncpy(comment, &buf[d_namelen + 1], sizeof comment);
			}
			len = extract_token (mimebuf, comment, 0,' ', 64);
			if ((len <0) || strchr(mimebuf, '/') == NULL)
			{
				snprintf (mimebuf, 64, "application/octetstream");
				len = 0;
			}
			cprintf("%s|%ld|%s|%s\n", 
				filedir_entry->d_name, 
				(long)statbuf.st_size, 
				mimebuf, 
				&comment[len]);
		}
	}
	fclose(fd);
	closedir(filedir);
	
	cprintf("000\n");
}
Пример #9
0
/* 
 * cmd_goto()  -  goto a new room
 */
void cmd_goto(char *gargs)
{
	struct ctdlroom QRscratch;
	int c;
	int ok = 0;
	int ra;
	char augmented_roomname[ROOMNAMELEN];
	char towhere[ROOMNAMELEN];
	char password[32];
	int transiently = 0;

	if (CtdlAccessCheck(ac_logged_in_or_guest)) return;

	extract_token(towhere, gargs, 0, '|', sizeof towhere);
	extract_token(password, gargs, 1, '|', sizeof password);
	transiently = extract_int(gargs, 2);

	CtdlGetUser(&CC->user, CC->curr_user);

	/*
	 * Handle some of the macro named rooms
	 */
	convert_room_name_macros(towhere, sizeof towhere);

	/* First try a regular match */
	c = CtdlGetRoom(&QRscratch, towhere);

	/* Then try a mailbox name match */
	if (c != 0) {
		CtdlMailboxName(augmented_roomname, sizeof augmented_roomname,
			    &CC->user, towhere);
		c = CtdlGetRoom(&QRscratch, augmented_roomname);
		if (c == 0)
			safestrncpy(towhere, augmented_roomname, sizeof towhere);
	}

	/* And if the room was found... */
	if (c == 0) {

		/* Let internal programs go directly to any room. */
		if (CC->internal_pgm) {
			memcpy(&CC->room, &QRscratch,
				sizeof(struct ctdlroom));
			CtdlUserGoto(NULL, 1, transiently, NULL, NULL, NULL, NULL);
			return;
		}

		/* See if there is an existing user/room relationship */
		CtdlRoomAccess(&QRscratch, &CC->user, &ra, NULL);

		/* normal clients have to pass through security */
		if (ra & UA_GOTOALLOWED) {
			ok = 1;
		}

		if (ok == 1) {
			if ((QRscratch.QRflags & QR_MAILBOX) &&
			    ((ra & UA_GOTOALLOWED))) {
				memcpy(&CC->room, &QRscratch,
					sizeof(struct ctdlroom));
				CtdlUserGoto(NULL, 1, transiently, NULL, NULL, NULL, NULL);
				return;
			} else if ((QRscratch.QRflags & QR_PASSWORDED) &&
			    ((ra & UA_KNOWN) == 0) &&
			    (strcasecmp(QRscratch.QRpasswd, password)) &&
			    (CC->user.axlevel < AxAideU)
			    ) {
				cprintf("%d wrong or missing passwd\n",
					ERROR + PASSWORD_REQUIRED);
				return;
			} else if ((QRscratch.QRflags & QR_PRIVATE) &&
				   ((QRscratch.QRflags & QR_PASSWORDED) == 0) &&
				   ((QRscratch.QRflags & QR_GUESSNAME) == 0) &&
				   ((ra & UA_KNOWN) == 0) &&
			           (CC->user.axlevel < AxAideU)
                                  ) {
				syslog(LOG_DEBUG, "Failed to acquire private room\n");
			} else {
				memcpy(&CC->room, &QRscratch,
					sizeof(struct ctdlroom));
				CtdlUserGoto(NULL, 1, transiently, NULL, NULL, NULL, NULL);
				return;
			}
		}
	}

	cprintf("%d room '%s' not found\n", ERROR + ROOM_NOT_FOUND, towhere);
}
Пример #10
0
/* 
 * cmd_stat()  -  return the modification time of the current room (maybe other things in the future)
 */
void cmd_stat(char *gargs)
{
	if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
	CtdlGetRoom(&CC->room, CC->room.QRname);
	cprintf("%d %s|%ld|\n", CIT_OK, CC->room.QRname, CC->room.QRmtime);
}
Пример #11
0
//
// Implements the GROUP and LISTGROUP commands
//
void nntp_group(const char *cmd) {
	if (CtdlAccessCheck(ac_logged_in_or_guest)) return;

	citnntp *nntpstate = (citnntp *) CC->session_specific_data;
	char verb[16];
	char requested_group[1024];
	char message_range[256];
	char range_lo[256];
	char range_hi[256];
	char requested_room[ROOMNAMELEN];
	char augmented_roomname[ROOMNAMELEN];
	int c = 0;
	int ok = 0;
	int ra = 0;
	struct ctdlroom QRscratch;
	int msgs, new;
	long oldest,newest;
	struct listgroup_range lr;

	extract_token(verb, cmd, 0, ' ', sizeof verb);
	extract_token(requested_group, cmd, 1, ' ', sizeof requested_group);
	extract_token(message_range, cmd, 2, ' ', sizeof message_range);
	extract_token(range_lo, message_range, 0, '-', sizeof range_lo);
	extract_token(range_hi, message_range, 1, '-', sizeof range_hi);
	lr.lo = atoi(range_lo);
	lr.hi = atoi(range_hi);

	/* In LISTGROUP mode we can specify an empty name for 'currently selected' */
	if ((!strcasecmp(verb, "LISTGROUP")) && (IsEmptyStr(requested_group))) {
		room_to_newsgroup(requested_group, CC->room.QRname, sizeof requested_group);
	}

	/* First try a regular match */
	newsgroup_to_room(requested_room, requested_group, sizeof requested_room);
	c = CtdlGetRoom(&QRscratch, requested_room);

	/* Then try a mailbox name match */
	if (c != 0) {
		CtdlMailboxName(augmented_roomname, sizeof augmented_roomname, &CC->user, requested_room);
		c = CtdlGetRoom(&QRscratch, augmented_roomname);
		if (c == 0) {
			safestrncpy(requested_room, augmented_roomname, sizeof(requested_room));
		}
	}

	/* If the room exists, check security/access */
	if (c == 0) {
		/* See if there is an existing user/room relationship */
		CtdlRoomAccess(&QRscratch, &CC->user, &ra, NULL);

		/* normal clients have to pass through security */
		if (ra & UA_KNOWN) {
			ok = 1;
		}
	}

	/* Fail here if no such room */
	if (!ok) {
		cprintf("411 no such newsgroup\r\n");
		return;
	}


	/*
	 * CtdlUserGoto() formally takes us to the desired room, happily returning
	 * the number of messages and number of new messages.
	 */
	memcpy(&CC->room, &QRscratch, sizeof(struct ctdlroom));
	CtdlUserGoto(NULL, 0, 0, &msgs, &new, &oldest, &newest);
	cprintf("211 %d %ld %ld %s\r\n", msgs, oldest, newest, requested_group);

	// If this is a GROUP command, set the "current article number" to zero, and then stop here.
	if (!strcasecmp(verb, "GROUP")) {
		nntpstate->current_article_number = oldest;
		return;
	}

	// If we get to this point we are running a LISTGROUP command.  Fetch those message numbers.
	CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, nntp_listgroup_backend, &lr);
	cprintf(".\r\n");
}
Пример #12
0
void inetcfg_init(void) {
	if (CtdlGetRoom(&CC->room, SYSCONFIGROOM) != 0) return;
	CtdlForEachMessage(MSGS_LAST, 1, NULL, INTERNETCFG, NULL,
		inetcfg_init_backend, NULL);
}
Пример #13
0
/*
 * Attempt to autocomplete an address based on a partial...
 */
void cmd_auto(char *argbuf) {
	char hold_rm[ROOMNAMELEN];
	char search_string[256];
	long *msglist = NULL;
	int num_msgs = 0;
	long *fts_msgs = NULL;
	int fts_num_msgs = 0;
	struct cdbdata *cdbfr;
	int r = 0;
	int i = 0;
	int j = 0;
	int search_match = 0;
	char *rooms_to_try[] = { USERCONTACTSROOM, ADDRESS_BOOK_ROOM };
		
	if (CtdlAccessCheck(ac_logged_in)) return;
	extract_token(search_string, argbuf, 0, '|', sizeof search_string);
	if (IsEmptyStr(search_string)) {
		cprintf("%d You supplied an empty partial.\n",
			ERROR + ILLEGAL_VALUE);
		return;
	}

	strcpy(hold_rm, CC->room.QRname);       /* save current room */
	cprintf("%d try these:\n", LISTING_FOLLOWS);

	/*
	 * Gather up message pointers in rooms containing vCards
	 */
	for (r=0; r < (sizeof(rooms_to_try) / sizeof(char *)); ++r) {
		if (CtdlGetRoom(&CC->room, rooms_to_try[r]) == 0) {
			cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
			if (cdbfr != NULL) {
				msglist = realloc(msglist, (num_msgs * sizeof(long)) + cdbfr->len + 1);
				memcpy(&msglist[num_msgs], cdbfr->ptr, cdbfr->len);
				num_msgs += (cdbfr->len / sizeof(long));
				cdb_free(cdbfr);
			}
		}
	}

	/*
	 * Search-reduce the results if we have the full text index available
	 */
	if (config.c_enable_fulltext) {
		CtdlModuleDoSearch(&fts_num_msgs, &fts_msgs, search_string, "fulltext");
		if (fts_msgs) {
			for (i=0; i<num_msgs; ++i) {
				search_match = 0;
				for (j=0; j<fts_num_msgs; ++j) {
					if (msglist[i] == fts_msgs[j]) {
						search_match = 1;
						j = fts_num_msgs + 1;	/* end the search */
					}
				}
				if (!search_match) {
					msglist[i] = 0;		/* invalidate this result */
				}
			}
			free(fts_msgs);
		}
		else {
			/* If no results, invalidate the whole list */
			free(msglist);
			msglist = NULL;
			num_msgs = 0;
		}
	}

	/*
	 * Now output the ones that look interesting
	 */
	if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
		if (msglist[i] != 0) {
			hunt_for_autocomplete(msglist[i], search_string);
		}
	}
	
	cprintf("000\n");
	if (strcmp(CC->room.QRname, hold_rm)) {
		CtdlGetRoom(&CC->room, hold_rm);    /* return to saved room */
	}

	if (msglist) {
		free(msglist);
	}
	
}
Пример #14
0
/*
 * Validate recipients, count delivery types and errors, and handle aliasing
 * FIXME check for dupes!!!!!
 *
 * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses 
 * were specified, or the number of addresses found invalid.
 *
 * Caller needs to free the result using free_recipients()
 */
recptypes *validate_recipients(const char *supplied_recipients, 
			       const char *RemoteIdentifier, 
			       int Flags) {
	struct CitContext *CCC = CC;
	recptypes *ret;
	char *recipients = NULL;
	char *org_recp;
	char this_recp[256];
	char this_recp_cooked[256];
	char append[SIZ];
	long len;
	int num_recps = 0;
	int i, j;
	int mailtype;
	int invalid;
	struct ctdluser tempUS;
	struct ctdlroom tempQR;
	struct ctdlroom tempQR2;
	int err = 0;
	char errmsg[SIZ];
	int in_quotes = 0;

	/* Initialize */
	ret = (recptypes *) malloc(sizeof(recptypes));
	if (ret == NULL) return(NULL);

	/* Set all strings to null and numeric values to zero */
	memset(ret, 0, sizeof(recptypes));

	if (supplied_recipients == NULL) {
		recipients = strdup("");
	}
	else {
		recipients = strdup(supplied_recipients);
	}

	/* Allocate some memory.  Yes, this allocates 500% more memory than we will
	 * actually need, but it's healthier for the heap than doing lots of tiny
	 * realloc() calls instead.
	 */
	len = strlen(recipients) + 1024;
	ret->errormsg = malloc(len);
	ret->recp_local = malloc(len);
	ret->recp_internet = malloc(len);
	ret->recp_ignet = malloc(len);
	ret->recp_room = malloc(len);
	ret->display_recp = malloc(len);
	ret->recp_orgroom = malloc(len);
	org_recp = malloc(len);

	ret->errormsg[0] = 0;
	ret->recp_local[0] = 0;
	ret->recp_internet[0] = 0;
	ret->recp_ignet[0] = 0;
	ret->recp_room[0] = 0;
	ret->recp_orgroom[0] = 0;
	ret->display_recp[0] = 0;

	ret->recptypes_magic = RECPTYPES_MAGIC;

	/* Change all valid separator characters to commas */
	for (i=0; !IsEmptyStr(&recipients[i]); ++i) {
		if ((recipients[i] == ';') || (recipients[i] == '|')) {
			recipients[i] = ',';
		}
	}

	/* Now start extracting recipients... */

	while (!IsEmptyStr(recipients)) {
		for (i=0; i<=strlen(recipients); ++i) {
			if (recipients[i] == '\"') in_quotes = 1 - in_quotes;
			if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) {
				safestrncpy(this_recp, recipients, i+1);
				this_recp[i] = 0;
				if (recipients[i] == ',') {
					strcpy(recipients, &recipients[i+1]);
				}
				else {
					strcpy(recipients, "");
				}
				break;
			}
		}

		striplt(this_recp);
		if (IsEmptyStr(this_recp))
			break;
		MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp);
		++num_recps;

		strcpy(org_recp, this_recp);
		alias(this_recp);
		alias(this_recp);
		mailtype = alias(this_recp);

		for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) {
			if (this_recp[j]=='_') {
				this_recp_cooked[j] = ' ';
			}
			else {
				this_recp_cooked[j] = this_recp[j];
			}
		}
		this_recp_cooked[j] = '\0';
		invalid = 0;
		errmsg[0] = 0;
		switch(mailtype) {
		case MES_LOCAL:
			if (!strcasecmp(this_recp, "sysop")) {
				++ret->num_room;
				strcpy(this_recp, CtdlGetConfigStr("c_aideroom"));
				if (!IsEmptyStr(ret->recp_room)) {
					strcat(ret->recp_room, "|");
				}
				strcat(ret->recp_room, this_recp);
			}
			else if ( (!strncasecmp(this_recp, "room_", 5))
				  && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) {

				/* Save room so we can restore it later */
				tempQR2 = CCC->room;
				CCC->room = tempQR;
					
				/* Check permissions to send mail to this room */
				err = CtdlDoIHavePermissionToPostInThisRoom(
					errmsg, 
					sizeof errmsg, 
					RemoteIdentifier,
					Flags,
					0			/* 0 = not a reply */
					);
				if (err)
				{
					++ret->num_error;
					invalid = 1;
				} 
				else {
					++ret->num_room;
					if (!IsEmptyStr(ret->recp_room)) {
						strcat(ret->recp_room, "|");
					}
					strcat(ret->recp_room, &this_recp_cooked[5]);

					if (!IsEmptyStr(ret->recp_orgroom)) {
						strcat(ret->recp_orgroom, "|");
					}
					strcat(ret->recp_orgroom, org_recp);

				}
					
				/* Restore room in case something needs it */
				CCC->room = tempQR2;

			}
			else if (CtdlGetUser(&tempUS, this_recp) == 0) {
				++ret->num_local;
				strcpy(this_recp, tempUS.fullname);
				if (!IsEmptyStr(ret->recp_local)) {
					strcat(ret->recp_local, "|");
				}
				strcat(ret->recp_local, this_recp);
			}
			else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) {
				++ret->num_local;
				strcpy(this_recp, tempUS.fullname);
				if (!IsEmptyStr(ret->recp_local)) {
					strcat(ret->recp_local, "|");
				}
				strcat(ret->recp_local, this_recp);
			}
			else {
				++ret->num_error;
				invalid = 1;
			}
			break;
		case MES_INTERNET:
			/* Yes, you're reading this correctly: if the target
			 * domain points back to the local system or an attached
			 * Citadel directory, the address is invalid.  That's
			 * because if the address were valid, we would have
			 * already translated it to a local address by now.
			 */
			if (IsDirectory(this_recp, 0)) {
				++ret->num_error;
				invalid = 1;
			}
			else {
				++ret->num_internet;
				if (!IsEmptyStr(ret->recp_internet)) {
					strcat(ret->recp_internet, "|");
				}
				strcat(ret->recp_internet, this_recp);
			}
			break;
		case MES_IGNET:
			++ret->num_ignet;
			if (!IsEmptyStr(ret->recp_ignet)) {
				strcat(ret->recp_ignet, "|");
			}
			strcat(ret->recp_ignet, this_recp);
			break;
		case MES_ERROR:
			++ret->num_error;
			invalid = 1;
			break;
		}
		if (invalid) {
			if (IsEmptyStr(errmsg)) {
				snprintf(append, sizeof append, "Invalid recipient: %s", this_recp);
			}
			else {
				snprintf(append, sizeof append, "%s", errmsg);
			}
			if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) {
				if (!IsEmptyStr(ret->errormsg)) {
					strcat(ret->errormsg, "; ");
				}
				strcat(ret->errormsg, append);
			}
		}
		else {
			if (IsEmptyStr(ret->display_recp)) {
				strcpy(append, this_recp);
			}
			else {
				snprintf(append, sizeof append, ", %s", this_recp);
			}
			if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) {
				strcat(ret->display_recp, append);
			}
		}
	}
	free(org_recp);

	if ((ret->num_local + ret->num_internet + ret->num_ignet +
	     ret->num_room + ret->num_error) == 0) {
		ret->num_error = (-1);
		strcpy(ret->errormsg, "No recipients specified.");
	}

	MSGM_syslog(LOG_DEBUG, "validate_recipients()\n");
	MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local);
	MSG_syslog(LOG_DEBUG, "  room: %d <%s>\n", ret->num_room, ret->recp_room);
	MSG_syslog(LOG_DEBUG, "  inet: %d <%s>\n", ret->num_internet, ret->recp_internet);
	MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet);
	MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg);

	free(recipients);
	return(ret);
}