コード例 #1
0
ファイル: sv_init.cpp プロジェクト: bdwakefield/OpenJK
void SV_ClearLastLevel(void)
{
	Menu_Reset();
	Z_TagFree(TAG_G_ALLOC);
	Z_TagFree(TAG_UI_ALLOC);
	G_FreeRoffs();
	R_ModelFree();
	Music_Free();
	Sys_IORequestQueueClear();
	AS_FreePartial();
	G_ASPreCacheFree();
	Ghoul2InfoArray_Free();
	G2_FreeRag();
	ClearAllNavStructures();
	ClearModelsAlreadyDone();
	CL_FreeServerCommands();
	CL_FreeReliableCommands();
	CM_Free();
	ShaderEntryPtrs_Clear();

	numVehicles = 0;

	if (svs.clients)
	{
		SV_FreeClient( svs.clients );
	}
}
コード例 #2
0
ファイル: serv_netmail.c プロジェクト: henri14/citadel
/*
 * Spools out one message from the list.
 */
void network_spool_msg(long msgnum,
		       void *userdata)
{
	struct CitContext *CCC = CC;
	struct CtdlMessage *msg = NULL;
	long delete_after_send = 0;	/* Set to 1 to delete after spooling */
	SpoolControl *sc;

	sc = (SpoolControl *)userdata;

	msg = CtdlFetchMessage(msgnum, 1);

	if (msg == NULL)
	{
		QN_syslog(LOG_ERR,
			  "failed to load Message <%ld> from disk\n",
			  msgnum);
		return;
	}
	network_process_list(sc, msg, &delete_after_send);
	network_process_digest(sc, msg, &delete_after_send);
	network_process_participate(sc, msg, &delete_after_send);
	network_process_ignetpush(sc, msg, &delete_after_send);
	
	CM_Free(msg);

	/* update lastsent */
	sc->lastsent = msgnum;

	/* Delete this message if delete-after-send is set */
	if (delete_after_send) {
		CtdlDeleteMessages(CC->room.QRname, &msgnum, 1, "");
	}
}
コード例 #3
0
ファイル: serv_netmail.c プロジェクト: henri14/citadel
/*
 * Deliver digest messages
 */
void network_deliver_digest(SpoolControl *sc)
{
	struct CitContext *CCC = CC;
	long len;
	char buf[SIZ];
	char *pbuf;
	struct CtdlMessage *msg = NULL;
	long msglen;
	recptypes *valid;
	char bounce_to[256];

	if (sc->Users[digestrecp] == NULL)
		return;

	msg = malloc(sizeof(struct CtdlMessage));
	memset(msg, 0, sizeof(struct CtdlMessage));
	msg->cm_magic = CTDLMESSAGE_MAGIC;
	msg->cm_format_type = FMT_RFC822;
	msg->cm_anon_type = MES_NORMAL;

	CM_SetFieldLONG(msg, eTimestamp, time(NULL));
	CM_SetField(msg, eAuthor, CCC->room.QRname, strlen(CCC->room.QRname));
	len = snprintf(buf, sizeof buf, "[%s]", CCC->room.QRname);
	CM_SetField(msg, eMsgSubject, buf, len);

	CM_SetField(msg, erFc822Addr, SKEY(sc->Users[roommailalias]));
	CM_SetField(msg, eRecipient, SKEY(sc->Users[roommailalias]));

	/* Set the 'List-ID' header */
	CM_SetField(msg, eListID, SKEY(sc->ListID));

	/*
	 * Go fetch the contents of the digest
	 */
	fseek(sc->digestfp, 0L, SEEK_END);
	msglen = ftell(sc->digestfp);

	pbuf = malloc(msglen + 1);
	fseek(sc->digestfp, 0L, SEEK_SET);
	fread(pbuf, (size_t)msglen, 1, sc->digestfp);
	pbuf[msglen] = '\0';
	CM_SetAsField(msg, eMesageText, &pbuf, msglen);

	/* Now generate the delivery instructions */

	/* Where do we want bounces and other noise to be heard?
	 * Surely not the list members! */
	snprintf(bounce_to, sizeof bounce_to, "room_aide@%s", config.c_fqdn);

	/* Now submit the message */
	valid = validate_recipients(ChrPtr(sc->Users[digestrecp]), NULL, 0);
	if (valid != NULL) {
		valid->bounce_to = strdup(bounce_to);
		valid->envelope_from = strdup(bounce_to);
		CtdlSubmitMsg(msg, valid, NULL, 0);
	}
	CM_Free(msg);
	free_recipients(valid);
}
コード例 #4
0
ファイル: serv_inetcfg.c プロジェクト: zcw159357/citadel
void inetcfg_init_backend(long msgnum, void *userdata) {
	struct CtdlMessage *msg;

       	msg = CtdlFetchMessage(msgnum, 1, 1);
       	if (msg != NULL) {
		inetcfg_setTo(msg);
               	CM_Free(msg);
	}
}
コード例 #5
0
ファイル: serv_wiki.c プロジェクト: mingodad/citadel
/*
 * Fetch a list of revisions for a particular wiki page
 */
void wiki_history(char *pagename) {
	int r;
	char history_page_name[270];
	long msgnum;
	struct CtdlMessage *msg;

	r = CtdlDoIHavePermissionToReadMessagesInThisRoom();
	if (r != om_ok) {
		if (r == om_not_logged_in) {
			cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
		}
		else {
			cprintf("%d An unknown error has occurred.\n", ERROR);
		}
		return;
	}

	snprintf(history_page_name, sizeof history_page_name, "%s_HISTORY_", pagename);
	msgnum = CtdlLocateMessageByEuid(history_page_name, &CC->room);
	if (msgnum > 0L) {
		msg = CtdlFetchMessage(msgnum, 1, 1);
	}
	else {
		msg = NULL;
	}

	if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) {
		CM_Free(msg);
		msg = NULL;
	}

	if (msg == NULL) {
		cprintf("%d Revision history for '%s' was not found.\n", ERROR+MESSAGE_NOT_FOUND, pagename);
		return;
	}

	
	cprintf("%d Revision history for '%s'\n", LISTING_FOLLOWS, pagename);
	mime_parser(CM_RANGE(msg, eMesageText), *wiki_history_callback, NULL, NULL, NULL, 0);
	cprintf("000\n");

	CM_Free(msg);
	return;
}
コード例 #6
0
ファイル: serv_netmail.c プロジェクト: henri14/citadel
void network_process_participate(SpoolControl *sc, struct CtdlMessage *omsg, long *delete_after_send)
{
	struct CtdlMessage *msg = NULL;
	int ok_to_participate = 0;
	StrBuf *Buf = NULL;
	recptypes *valid;

	/*
	 * Process client-side list participations for this room
	 */
	if (sc->Users[participate] == NULL)
		return;

	msg = CM_Duplicate(omsg);

	/* Only send messages which originated on our own
	 * Citadel network, otherwise we'll end up sending the
	 * remote mailing list's messages back to it, which
	 * is rude...
	 */
	ok_to_participate = 0;
	if (!CM_IsEmpty(msg, eNodeName)) {
		if (!strcasecmp(msg->cm_fields[eNodeName],
				config.c_nodename)) {
			ok_to_participate = 1;
		}
		
		Buf = NewStrBufPlain(CM_KEY(msg, eNodeName));
		if (CtdlIsValidNode(NULL,
				    NULL,
				    Buf,
				    sc->working_ignetcfg,
				    sc->the_netmap) == 0)
		{
			ok_to_participate = 1;
		}
	}
	if (ok_to_participate)
	{
		/* Replace the Internet email address of the
		 * actual author with the email address of the
		 * room itself, so the remote listserv doesn't
		 * reject us.
		 */
		CM_SetField(msg, erFc822Addr, SKEY(sc->Users[roommailalias]));

		valid = validate_recipients(ChrPtr(sc->Users[participate]) , NULL, 0);

		CM_SetField(msg, eRecipient, SKEY(sc->Users[roommailalias]));
		CtdlSubmitMsg(msg, valid, "", 0);
		free_recipients(valid);
	}
	FreeStrBuf(&Buf);
	CM_Free(msg);
}
コード例 #7
0
ファイル: serv_expire.c プロジェクト: henri14/citadel
/*
 * Purge the EUID Index of old records.
 *
 */
int PurgeEuidIndexTable(void) {
	int purged = 0;
	struct cdbdata *cdbei;
	struct EPurgeList *el = NULL;
	struct EPurgeList *eptr; 
	long msgnum;
	struct CtdlMessage *msg = NULL;

	/* Phase 1: traverse through the table, discovering old records... */
	syslog(LOG_DEBUG, "Purge EUID index: phase 1");
	cdb_rewind(CDB_EUIDINDEX);
	while(cdbei = cdb_next_item(CDB_EUIDINDEX), cdbei != NULL) {

		memcpy(&msgnum, cdbei->ptr, sizeof(long));

		msg = CtdlFetchMessage(msgnum, 0);
		if (msg != NULL) {
			CM_Free(msg);	/* it still exists, so do nothing */
		}
		else {
			eptr = (struct EPurgeList *) malloc(sizeof(struct EPurgeList));
			if (eptr != NULL) {
				eptr->next = el;
				eptr->ep_keylen = cdbei->len - sizeof(long);
				eptr->ep_key = malloc(cdbei->len);
				memcpy(eptr->ep_key, &cdbei->ptr[sizeof(long)], eptr->ep_keylen);
				el = eptr;
			}
			++purged;
		}

	       cdb_free(cdbei);

	}

	/* Phase 2: delete the records */
	syslog(LOG_DEBUG, "Purge euid index: phase 2");
	while (el != NULL) {
		cdb_delete(CDB_EUIDINDEX, el->ep_key, el->ep_keylen);
		free(el->ep_key);
		eptr = el->next;
		free(el);
		el = eptr;
	}

	syslog(LOG_DEBUG, "Purge euid index: finished (purged %d records)", purged);
	return(purged);
}
コード例 #8
0
ファイル: serv_messages.c プロジェクト: mingodad/citadel
/*
 * Back end for the MSGS command: output EUID header.
 */
void headers_euid(long msgnum, void *userdata)
{
	struct CtdlMessage *msg;

	msg = CtdlFetchMessage(msgnum, 0, 1);
	if (msg == NULL) {
		cprintf("%ld||\n", msgnum);
		return;
	}

	cprintf("%ld|%s|%s\n", 
		msgnum, 
		(!CM_IsEmpty(msg, eExclusiveID) ? msg->cm_fields[eExclusiveID] : ""),
		(!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"));
	CM_Free(msg);
}
コード例 #9
0
ファイル: serv_messages.c プロジェクト: mingodad/citadel
/*
 * Back end for the MSGS command: output header summary.
 */
void headers_listing(long msgnum, void *userdata)
{
	struct CtdlMessage *msg;

	msg = CtdlFetchMessage(msgnum, 0, 1);
	if (msg == NULL) {
		cprintf("%ld|0|||||\n", msgnum);
		return;
	}

	cprintf("%ld|%s|%s|%s|%s|%s|\n",
		msgnum,
		(!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"),
		(!CM_IsEmpty(msg, eAuthor) ? msg->cm_fields[eAuthor] : ""),
		(!CM_IsEmpty(msg, eNodeName) ? msg->cm_fields[eNodeName] : ""),
		(!CM_IsEmpty(msg, erFc822Addr) ? msg->cm_fields[erFc822Addr] : ""),
		(!CM_IsEmpty(msg, eMsgSubject) ? msg->cm_fields[eMsgSubject] : "")
	);
	CM_Free(msg);
}
コード例 #10
0
ファイル: serv_nntp.c プロジェクト: mingodad/citadel
//
// back end for the XOVER command , called for each message number
//
void nntp_xover_backend(long msgnum, void *userdata) {

	struct listgroup_range *lr = (struct listgroup_range *)userdata;

	// check range if supplied
	if (msgnum < lr->lo) return;
	if ((lr->hi != 0) && (msgnum > lr->hi)) return;

	struct CtdlMessage *msg = CtdlFetchMessage(msgnum, 0, 1);
	if (msg == NULL) {
		return;
	}

	// Teh RFC says we need:
	// -------------------------
	// Subject header content
	// From header content
	// Date header content
	// Message-ID header content
	// References header content
	// :bytes metadata item
	// :lines metadata item

	time_t msgtime = atol(msg->cm_fields[eTimestamp]);
	char strtimebuf[26];
	ctime_r(&msgtime, strtimebuf);

	// here we go -- print the line o'data
	cprintf("%ld\t%s\t%s <%s>\t%s\t%s\t%s\t100\t10\r\n",
		msgnum,
		msg->cm_fields[eMsgSubject],
		msg->cm_fields[eAuthor],
		msg->cm_fields[erFc822Addr],
		strtimebuf,
		msg->cm_fields[emessageId],
		msg->cm_fields[eWeferences]
	);

	CM_Free(msg);
}
コード例 #11
0
ファイル: serv_netmail.c プロジェクト: henri14/citadel
void network_process_list(SpoolControl *sc, struct CtdlMessage *omsg, long *delete_after_send)
{
	struct CtdlMessage *msg = NULL;

	/*
	 * Process mailing list recipients
	 */
	if (sc->Users[listrecp] == NULL)
		return;

	/* create our own copy of the message.
	 *  We're going to need to modify it
	 * in order to insert the [list name] in it, etc.
	 */

	msg = CM_Duplicate(omsg);


	CM_SetField(msg, eReplyTo, SKEY(sc->Users[roommailalias]));

	/* if there is no other recipient, Set the recipient
	 * of the list message to the email address of the
	 * room itself.
	 */
	if (CM_IsEmpty(msg, eRecipient))
	{
		CM_SetField(msg, eRecipient, SKEY(sc->Users[roommailalias]));
	}

	/* Set the 'List-ID' header */
	CM_SetField(msg, eListID, SKEY(sc->ListID));


	/* Prepend "[List name]" to the subject */
	ListCalculateSubject(msg);

	/* Handle delivery */
	network_deliver_list(msg, sc, CC->room.QRname);
	CM_Free(msg);
}
コード例 #12
0
ファイル: serv_pop3client.c プロジェクト: henri14/citadel
eNextState POP3C_SaveMsg(AsyncIO *IO)
{
	long msgnum;
	pop3aggr *RecvMsg = (pop3aggr *) IO->Data;

	/* Do Something With It (tm) */
	msgnum = CtdlSubmitMsg(RecvMsg->CurrMsg->Msg,
			       NULL,
			       ChrPtr(RecvMsg->RoomName),
			       0);
	if (msgnum > 0L)
	{
		/* Message has been committed to the store
		 * write the uidl to the use table
		 * so we don't fetch this message again
		 */
	}
	CM_Free(RecvMsg->CurrMsg->Msg);

	RecvMsg->count ++;
	return NextDBOperation(&RecvMsg->IO, POP3C_StoreMsgRead);
}
コード例 #13
0
ファイル: xmpp_presence.c プロジェクト: henri14/citadel
void xmpp_fetch_mortuary_backend(long msgnum, void *userdata) {
	HashList *mortuary = (HashList *) userdata;
	struct CtdlMessage *msg;
	char *ptr = NULL;
	char *lasts = NULL;

	msg = CtdlFetchMessage(msgnum, 1);
	if (msg == NULL) {
		return;
	}

	/* now add anyone we find into the hashlist */

	/* skip past the headers */
	ptr = strstr(msg->cm_fields[eMesageText], "\n\n");
	if (ptr != NULL) {
		ptr += 2;
	}
	else {
		ptr = strstr(msg->cm_fields[eMesageText], "\n\r\n");
		if (ptr != NULL) {
			ptr += 3;
		}
	}

	/* the remaining lines are addresses */
	if (ptr != NULL) {
		ptr = strtok_r(ptr, "\n", &lasts);
		while (ptr != NULL) {
			char *pch = strdup(ptr);
			Put(mortuary, pch, strlen(pch), pch, NULL);
			ptr = strtok_r(NULL, "\n", &lasts);
		}
	}

	CM_Free(msg);
}
コード例 #14
0
ファイル: serv_expire.c プロジェクト: henri14/citadel
/*
 * First phase of message purge -- gather the locations of messages which
 * qualify for purging and write them to a temp file.
 */
void GatherPurgeMessages(struct ctdlroom *qrbuf, void *data) {
	struct ExpirePolicy epbuf;
	long delnum;
	time_t xtime, now;
	struct CtdlMessage *msg = NULL;
	int a;
	struct cdbdata *cdbfr;
	long *msglist = NULL;
	int num_msgs = 0;
	FILE *purgelist;

	purgelist = (FILE *)data;
	fprintf(purgelist, "r=%s\n", qrbuf->QRname);

	time(&now);
	GetExpirePolicy(&epbuf, qrbuf);

	/* If the room is set to never expire messages ... do nothing */
	if (epbuf.expire_mode == EXPIRE_NEXTLEVEL) return;
	if (epbuf.expire_mode == EXPIRE_MANUAL) return;

	/* Don't purge messages containing system configuration, dumbass. */
	if (!strcasecmp(qrbuf->QRname, SYSCONFIGROOM)) return;

	/* Ok, we got this far ... now let's see what's in the room */
	cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf->QRnumber, sizeof(long));

	if (cdbfr != NULL) {
		msglist = malloc(cdbfr->len);
		memcpy(msglist, cdbfr->ptr, cdbfr->len);
		num_msgs = cdbfr->len / sizeof(long);
		cdb_free(cdbfr);
	}

	/* Nothing to do if there aren't any messages */
	if (num_msgs == 0) {
		if (msglist != NULL) free(msglist);
		return;
	}


	/* If the room is set to expire by count, do that */
	if (epbuf.expire_mode == EXPIRE_NUMMSGS) {
		if (num_msgs > epbuf.expire_value) {
			for (a=0; a<(num_msgs - epbuf.expire_value); ++a) {
				fprintf(purgelist, "m=%ld\n", msglist[a]);
				++messages_purged;
			}
		}
	}

	/* If the room is set to expire by age... */
	if (epbuf.expire_mode == EXPIRE_AGE) {
		for (a=0; a<num_msgs; ++a) {
			delnum = msglist[a];

			msg = CtdlFetchMessage(delnum, 0); /* dont need body */
			if (msg != NULL) {
				xtime = atol(msg->cm_fields[eTimestamp]);
				CM_Free(msg);
			} else {
				xtime = 0L;
			}

			if ((xtime > 0L)
			   && (now - xtime > (time_t)(epbuf.expire_value * 86400L))) {
				fprintf(purgelist, "m=%ld\n", delnum);
				++messages_purged;
			}
		}
	}

	if (msglist != NULL) free(msglist);
}
コード例 #15
0
ファイル: journaling.c プロジェクト: henri14/citadel
/*
 * Called by JournalRunQueue() to send an individual message.
 */
void JournalRunQueueMsg(struct jnlq *jmsg) {

	struct CtdlMessage *journal_msg = NULL;
	recptypes *journal_recps = NULL;
	StrBuf *message_text = NULL;
	char mime_boundary[256];
	long mblen;
	long rfc822len;
	char recipient[256];
	char inetemail[256];
	static int seq = 0;
	int i;

	if (jmsg == NULL)
		return;
	journal_recps = validate_recipients(config.c_journal_dest, NULL, 0);
	if (journal_recps != NULL) {

		if (  (journal_recps->num_local > 0)
		   || (journal_recps->num_internet > 0)
		   || (journal_recps->num_ignet > 0)
		   || (journal_recps->num_room > 0)
		) {

			/*
			 * Construct journal message.
			 * Note that we are transferring ownership of some of the memory here.
			 */
			journal_msg = malloc(sizeof(struct CtdlMessage));
			memset(journal_msg, 0, sizeof(struct CtdlMessage));
			journal_msg->cm_magic = CTDLMESSAGE_MAGIC;
			journal_msg->cm_anon_type = MES_NORMAL;
			journal_msg->cm_format_type = FMT_RFC822;
			CM_SetField(journal_msg, eJournal, HKEY("is journal"));
			CM_SetField(journal_msg, eAuthor, jmsg->from, strlen(jmsg->from));
			CM_SetField(journal_msg, eNodeName, jmsg->node, strlen(jmsg->node));
			CM_SetField(journal_msg, erFc822Addr, jmsg->rfca, strlen(jmsg->rfca));
			CM_SetField(journal_msg, eMsgSubject, jmsg->subj, strlen(jmsg->subj));

			mblen = snprintf(mime_boundary, sizeof(mime_boundary),
					 "--Citadel-Journal-%08lx-%04x--", time(NULL), ++seq);
			rfc822len = strlen(jmsg->rfc822);
		       
			message_text = NewStrBufPlain(NULL, rfc822len + sizeof(recptypes) + 1024);

			/*
			 * Here is where we begin to compose the journalized message.
			 * NOTE: the superfluous "Content-Identifer: ExJournalReport" header was
			 *       requested by a paying customer, and yes, it is intentionally
			 *       spelled wrong.  Do NOT remove or change it.
			 */
			StrBufAppendBufPlain(
				message_text, 
				HKEY("Content-type: multipart/mixed; boundary=\""), 0);

			StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);

			StrBufAppendBufPlain(
				message_text, 
				HKEY("\"\r\n"
				     "Content-Identifer: ExJournalReport\r\n"
				     "MIME-Version: 1.0\r\n"
				     "\n"
				     "--"), 0);

			StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);

			StrBufAppendBufPlain(
				message_text, 
				HKEY("\r\n"
				     "Content-type: text/plain\r\n"
				     "\r\n"
				     "Sender: "), 0);

			if (CM_IsEmpty(journal_msg, eAuthor))
				StrBufAppendBufPlain(
					message_text, 
					journal_msg->cm_fields[eAuthor], -1, 0);
			else
				StrBufAppendBufPlain(
					message_text, 
					HKEY("(null)"), 0);

			if (!CM_IsEmpty(journal_msg, erFc822Addr)) {
				StrBufAppendPrintf(message_text, " <%s>",
						   journal_msg->cm_fields[erFc822Addr]);
			}
			else if (!CM_IsEmpty(journal_msg, eNodeName)) {
				StrBufAppendPrintf(message_text, " @ %s",
						   journal_msg->cm_fields[eNodeName]);
			}
			else
				StrBufAppendBufPlain(
					message_text, 
					HKEY(" "), 0);

			StrBufAppendBufPlain(
				message_text, 
				HKEY("\r\n"
				     "Message-ID: <"), 0);

			StrBufAppendBufPlain(message_text, jmsg->msgn, -1, 0);
			StrBufAppendBufPlain(
				message_text, 
				HKEY(">\r\n"
				     "Recipients:\r\n"), 0);

			if (jmsg->recps.num_local > 0) {
				for (i=0; i<jmsg->recps.num_local; ++i) {
					extract_token(recipient, jmsg->recps.recp_local,
							i, '|', sizeof recipient);
					local_to_inetemail(inetemail, recipient, sizeof inetemail);
					StrBufAppendPrintf(message_text, 
							   "	%s <%s>\r\n", recipient, inetemail);
				}
			}

			if (jmsg->recps.num_ignet > 0) {
				for (i=0; i<jmsg->recps.num_ignet; ++i) {
					extract_token(recipient, jmsg->recps.recp_ignet,
							i, '|', sizeof recipient);
					StrBufAppendPrintf(message_text, 
							   "	%s\r\n", recipient);
				}
			}

			if (jmsg->recps.num_internet > 0) {
				for (i=0; i<jmsg->recps.num_internet; ++i) {
					extract_token(recipient, jmsg->recps.recp_internet,
							i, '|', sizeof recipient);
					StrBufAppendPrintf(message_text, 
						"	%s\r\n", recipient);
				}
			}

			StrBufAppendBufPlain(
				message_text, 
				HKEY("\r\n"
				     "--"), 0);

			StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);

			StrBufAppendBufPlain(
				message_text, 
				HKEY("\r\n"
				     "Content-type: message/rfc822\r\n"
				     "\r\n"), 0);

			StrBufAppendBufPlain(message_text, jmsg->rfc822, rfc822len, 0);

			StrBufAppendBufPlain(
				message_text, 
				HKEY("--"), 0);

			StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);

			StrBufAppendBufPlain(
				message_text, 
				HKEY("--\r\n"), 0);

			CM_SetAsFieldSB(journal_msg, eMesageText, &message_text);
			free(jmsg->rfc822);
			free(jmsg->msgn);
			jmsg->rfc822 = NULL;
			jmsg->msgn = NULL;
			
			/* Submit journal message */
			CtdlSubmitMsg(journal_msg, journal_recps, "", 0);
			CM_Free(journal_msg);
		}

		free_recipients(journal_recps);
	}

	/* We are responsible for freeing this memory. */
	free(jmsg);
}
コード例 #16
0
ファイル: imap_search.c プロジェクト: henri14/citadel
/*
 * imap_do_search() calls imap_do_search_msg() to search an individual
 * message after it has been fetched from the disk.  This function returns
 * nonzero if there is a match.
 *
 * supplied_msg MAY be used to pass a pointer to the message in memory,
 * if for some reason it's already been loaded.  If not, the message will
 * be loaded only if one or more search criteria require it.
 */
int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
			int num_items, ConstStr *itemlist, int is_uid) {

	citimap *Imap = IMAP;
	int match = 0;
	int is_not = 0;
	int is_or = 0;
	int pos = 0;
	int i;
	char *fieldptr;
	struct CtdlMessage *msg = NULL;
	int need_to_free_msg = 0;

	if (num_items == 0) {
		return(0);
	}
	msg = supplied_msg;

	/* Initially we start at the beginning. */
	pos = 0;

	/* Check for the dreaded NOT criterion. */
	if (!strcasecmp(itemlist[0].Key, "NOT")) {
		is_not = 1;
		pos = 1;
	}

	/* Check for the dreaded OR criterion. */
	if (!strcasecmp(itemlist[0].Key, "OR")) {
		is_or = 1;
		pos = 1;
	}

	/* Now look for criteria. */
	if (!strcasecmp(itemlist[pos].Key, "ALL")) {
		match = 1;
		++pos;
	}
	
	else if (!strcasecmp(itemlist[pos].Key, "ANSWERED")) {
		if (Imap->flags[seq-1] & IMAP_ANSWERED) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "BCC")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Bcc");
			if (fieldptr != NULL) {
				if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
					match = 1;
				}
				free(fieldptr);
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "BEFORE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) < 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "BODY")) {

		/* If fulltext indexing is active, on this server,
		 *  all messages have already been qualified.
		 */
		if (config.c_enable_fulltext) {
			match = 1;
		}

		/* Otherwise, we have to do a slow search. */
		else {
			if (msg == NULL) {
				msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
				need_to_free_msg = 1;
			}
			if (msg != NULL) {
				if (bmstrcasestr(msg->cm_fields[eMesageText], itemlist[pos+1].Key)) {
					match = 1;
				}
			}
		}

		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "CC")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			fieldptr = msg->cm_fields[eCarbonCopY];
			if (fieldptr != NULL) {
				if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
					match = 1;
				}
			}
			else {
				fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Cc");
				if (fieldptr != NULL) {
					if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
						match = 1;
					}
					free(fieldptr);
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "DELETED")) {
		if (Imap->flags[seq-1] & IMAP_DELETED) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "DRAFT")) {
		if (Imap->flags[seq-1] & IMAP_DRAFT) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "FLAGGED")) {
		if (Imap->flags[seq-1] & IMAP_FLAGGED) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "FROM")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (bmstrcasestr(msg->cm_fields[eAuthor], itemlist[pos+1].Key)) {
				match = 1;
			}
			if (bmstrcasestr(msg->cm_fields[erFc822Addr], itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "HEADER")) {

		/* We've got to do a slow search for this because the client
		 * might be asking for an RFC822 header field that has not been
		 * converted into a Citadel header field.  That requires
		 * examining the message body.
		 */
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}

		if (msg != NULL) {
	
			CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
			CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_FAST, 0, 1, 0);
	
			fieldptr = rfc822_fetch_field(ChrPtr(CC->redirect_buffer), itemlist[pos+1].Key);
			if (fieldptr != NULL) {
				if (bmstrcasestr(fieldptr, itemlist[pos+2].Key)) {
					match = 1;
				}
				free(fieldptr);
			}
	
			FreeStrBuf(&CC->redirect_buffer);
		}

		pos += 3;	/* Yes, three */
	}

	else if (!strcasecmp(itemlist[pos].Key, "KEYWORD")) {
		/* not implemented */
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "LARGER")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (msg->cm_lengths[eMesageText] > atoi(itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "NEW")) {
		if ( (Imap->flags[seq-1] & IMAP_RECENT) && (!(Imap->flags[seq-1] & IMAP_SEEN))) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "OLD")) {
		if (!(Imap->flags[seq-1] & IMAP_RECENT)) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "ON")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) == 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "RECENT")) {
		if (Imap->flags[seq-1] & IMAP_RECENT) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SEEN")) {
		if (Imap->flags[seq-1] & IMAP_SEEN) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SENTBEFORE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) < 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SENTON")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) == 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SENTSINCE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) >= 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SINCE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) >= 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SMALLER")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (msg->cm_lengths[eMesageText] < atoi(itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SUBJECT")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (bmstrcasestr(msg->cm_fields[eMsgSubject], itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "TEXT")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			for (i='A'; i<='Z'; ++i) {
				if (bmstrcasestr(msg->cm_fields[i], itemlist[pos+1].Key)) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "TO")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (bmstrcasestr(msg->cm_fields[eRecipient], itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	/* FIXME this is b0rken.  fix it. */
	else if (imap_is_message_set(itemlist[pos].Key)) {
		if (is_msg_in_sequence_set(itemlist[pos].Key, seq)) {
			match = 1;
		}
		pos += 1;
	}

	/* FIXME this is b0rken.  fix it. */
	else if (!strcasecmp(itemlist[pos].Key, "UID")) {
		if (is_msg_in_sequence_set(itemlist[pos+1].Key, Imap->msgids[seq-1])) {
			match = 1;
		}
		pos += 2;
	}

	/* Now here come the 'UN' criteria.  Why oh why do we have to
	 * implement *both* the 'UN' criteria *and* the 'NOT' keyword?  Why
	 * can't there be *one* way to do things?  More gratuitous complexity.
	 */

	else if (!strcasecmp(itemlist[pos].Key, "UNANSWERED")) {
		if ((Imap->flags[seq-1] & IMAP_ANSWERED) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNDELETED")) {
		if ((Imap->flags[seq-1] & IMAP_DELETED) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNDRAFT")) {
		if ((Imap->flags[seq-1] & IMAP_DRAFT) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNFLAGGED")) {
		if ((Imap->flags[seq-1] & IMAP_FLAGGED) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNKEYWORD")) {
		/* FIXME */
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNSEEN")) {
		if ((Imap->flags[seq-1] & IMAP_SEEN) == 0) {
			match = 1;
		}
		++pos;
	}

	/* Remember to negate if we were told to */
	if (is_not) {
		match = !match;
	}

	/* Keep going if there are more criteria! */
	if (pos < num_items) {

		if (is_or) {
			match = (match || imap_do_search_msg(seq, msg,
				num_items - pos, &itemlist[pos], is_uid));
		}
		else {
			match = (match && imap_do_search_msg(seq, msg,
				num_items - pos, &itemlist[pos], is_uid));
		}

	}

	if (need_to_free_msg) {
		CM_Free(msg);
	}
	return(match);
}
コード例 #17
0
ファイル: smtp_util.c プロジェクト: zcw159357/citadel
/*
 * smtp_do_bounce() is caled by smtp_do_procmsg() to scan a set of delivery
 * instructions for "5" codes (permanent fatal errors) and produce/deliver
 * a "bounce" message (delivery status notification).
 */
void smtp_do_bounce(char *instr, StrBuf *OMsgTxt)
{
	int i;
	int lines;
	int status;
	char buf[1024];
	char key[1024];
	char addr[1024];
	char dsn[1024];
	char bounceto[1024];
	StrBuf *boundary;
	int num_bounces = 0;
	int bounce_this = 0;
	time_t submitted = 0L;
	struct CtdlMessage *bmsg = NULL;
	int give_up = 0;
	recptypes *valid;
	int successful_bounce = 0;
	static int seq = 0;
	StrBuf *BounceMB;
	long omsgid = (-1);

	syslog(LOG_DEBUG, "smtp_do_bounce() called\n");
	strcpy(bounceto, "");
	boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));

	StrBufAppendPrintf(boundary, "%s_%04x%04x", CtdlGetConfigStr("c_fqdn"), getpid(), ++seq);

	lines = num_tokens(instr, '\n');

	/* See if it's time to give up on delivery of this message */
	for (i=0; i<lines; ++i) {
		extract_token(buf, instr, i, '\n', sizeof buf);
		extract_token(key, buf, 0, '|', sizeof key);
		extract_token(addr, buf, 1, '|', sizeof addr);
		if (!strcasecmp(key, "submitted")) {
			submitted = atol(addr);
		}
	}

	if ( (time(NULL) - submitted) > SMTP_GIVE_UP ) {
		give_up = 1;
	}

	/* Start building our bounce message */

	bmsg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
	if (bmsg == NULL) return;
	memset(bmsg, 0, sizeof(struct CtdlMessage));
	BounceMB = NewStrBufPlain(NULL, 1024);

	bmsg->cm_magic = CTDLMESSAGE_MAGIC;
	bmsg->cm_anon_type = MES_NORMAL;
	bmsg->cm_format_type = FMT_RFC822;
	CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
	CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
	CM_SetField(bmsg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
	CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
	StrBufAppendBufPlain(BounceMB, HKEY("Content-type: multipart/mixed; boundary=\""), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\"\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("MIME-Version: 1.0\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("X-Mailer: " CITADEL "\r\n"), 0);

	StrBufAppendBufPlain(
		BounceMB,
		HKEY("\r\nThis is a multipart message in MIME format."
		     "\r\n\r\n"), 0);

	StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
	StrBufAppendBufPlain(BounceMB,
			     HKEY("Content-type: text/plain\r\n\r\n"), 0);

	if (give_up)
	{
		StrBufAppendBufPlain(
			BounceMB,
			HKEY("A message you sent could not be delivered "
			     "to some or all of its recipients\ndue to "
			     "prolonged unavailability of its destination(s).\n"
			     "Giving up on the following addresses:\n\n"), 0);
	}
	else
	{
		StrBufAppendBufPlain(
			BounceMB,
			HKEY("A message you sent could not be delivered "
			     "to some or all of its recipients.\n"
			     "The following addresses were undeliverable:\n\n"
				), 0);
	}

	/*
	 * Now go through the instructions checking for stuff.
	 */
	for (i=0; i<lines; ++i) {
		long addrlen;
		long dsnlen;
		extract_token(buf, instr, i, '\n', sizeof buf);
		extract_token(key, buf, 0, '|', sizeof key);
		addrlen = extract_token(addr, buf, 1, '|', sizeof addr);
		status = extract_int(buf, 2);
		dsnlen = extract_token(dsn, buf, 3, '|', sizeof dsn);
		bounce_this = 0;

		syslog(LOG_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>\n",
		       key, addr, status, dsn);

		if (!strcasecmp(key, "bounceto")) {
			strcpy(bounceto, addr);
		}

		if (!strcasecmp(key, "msgid")) {
			omsgid = atol(addr);
		}

		if (!strcasecmp(key, "remote")) {
			if (status == 5) bounce_this = 1;
			if (give_up) bounce_this = 1;
		}

		if (bounce_this) {
			++num_bounces;

			StrBufAppendBufPlain(BounceMB, addr, addrlen, 0);
			StrBufAppendBufPlain(BounceMB, HKEY(": "), 0);
			StrBufAppendBufPlain(BounceMB, dsn, dsnlen, 0);
			StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);

			remove_token(instr, i, '\n');
			--i;
			--lines;
		}
	}

	/* Attach the original message */
	if (omsgid >= 0) {
		StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
		StrBufAppendBuf(BounceMB, boundary, 0);
		StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);

		StrBufAppendBufPlain(
			BounceMB,
			HKEY("Content-type: message/rfc822\r\n"), 0);

		StrBufAppendBufPlain(
			BounceMB,
			HKEY("Content-Transfer-Encoding: 7bit\r\n"), 0);

		StrBufAppendBufPlain(
			BounceMB,
			HKEY("Content-Disposition: inline\r\n"), 0);

		StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);

		if (OMsgTxt == NULL) {
			CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
			CtdlOutputMsg(omsgid,
				      MT_RFC822,
				      HEADERS_ALL,
				      0, 1, NULL, 0,
				      NULL, NULL, NULL);

			StrBufAppendBuf(BounceMB, CC->redirect_buffer, 0);
			FreeStrBuf(&CC->redirect_buffer);
		}
		else {
			StrBufAppendBuf(BounceMB, OMsgTxt, 0);
		}
	}

	/* Close the multipart MIME scope */
	StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("--\r\n"), 0);
	CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);

	/* Deliver the bounce if there's anything worth mentioning */
	syslog(LOG_DEBUG, "num_bounces = %d\n", num_bounces);
	if (num_bounces > 0) {

		/* First try the user who sent the message */
		if (IsEmptyStr(bounceto))
			syslog(LOG_ERR, "No bounce address specified\n");
		else
			syslog(LOG_DEBUG, "bounce to user <%s>\n", bounceto);
		/* Can we deliver the bounce to the original sender? */
		valid = validate_recipients(bounceto,
					    smtp_get_Recipients (),
					    0);
		if (valid != NULL) {
			if (valid->num_error == 0) {
				CtdlSubmitMsg(bmsg, valid, "", QP_EADDR);
				successful_bounce = 1;
			}
		}

		/* If not, post it in the Aide> room */
		if (successful_bounce == 0) {
			CtdlSubmitMsg(bmsg, NULL, CtdlGetConfigStr("c_aideroom"), QP_EADDR);
		}

		/* Free up the memory we used */
		if (valid != NULL) {
			free_recipients(valid);
		}
	}
	FreeStrBuf(&boundary);
	CM_Free(bmsg);
	syslog(LOG_DEBUG, "Done processing bounces\n");
}
コード例 #18
0
ファイル: serv_netmail.c プロジェクト: henri14/citadel
void network_process_digest(SpoolControl *sc, struct CtdlMessage *omsg, long *delete_after_send)
{

	struct CtdlMessage *msg = NULL;

	if (sc->Users[digestrecp] == NULL)
		return;

	/* If there are digest recipients, we have to build a digest */
	if (sc->digestfp == NULL) {
		
		sc->digestfp = create_digest_file(&sc->room, 1);

		if (sc->digestfp == NULL)
			return;

		sc->haveDigest = ftell(sc->digestfp) > 0;
		if (!sc->haveDigest) {
			fprintf(sc->digestfp, "Content-type: text/plain\n\n");
		}
		sc->haveDigest = 1;
	}

	msg = CM_Duplicate(omsg);
	if (msg != NULL) {
		sc->haveDigest = 1;
		fprintf(sc->digestfp,
			" -----------------------------------"
			"------------------------------------"
			"-------\n");
		fprintf(sc->digestfp, "From: ");
		if (!CM_IsEmpty(msg, eAuthor)) {
			fprintf(sc->digestfp,
				"%s ",
				msg->cm_fields[eAuthor]);
		}
		if (!CM_IsEmpty(msg, erFc822Addr)) {
			fprintf(sc->digestfp,
				"<%s> ",
				msg->cm_fields[erFc822Addr]);
		}
		else if (!CM_IsEmpty(msg, eNodeName)) {
			fprintf(sc->digestfp,
				"@%s ",
				msg->cm_fields[eNodeName]);
		}
		fprintf(sc->digestfp, "\n");
		if (!CM_IsEmpty(msg, eMsgSubject)) {
			fprintf(sc->digestfp,
				"Subject: %s\n",
				msg->cm_fields[eMsgSubject]);
		}

		CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);

		safestrncpy(CC->preferred_formats,
			    "text/plain",
			    sizeof CC->preferred_formats);

		CtdlOutputPreLoadedMsg(msg,
				       MT_CITADEL,
				       HEADERS_NONE,
				       0, 0, 0);

		StrBufTrim(CC->redirect_buffer);
		fwrite(HKEY("\n"), 1, sc->digestfp);
		fwrite(SKEY(CC->redirect_buffer), 1, sc->digestfp);
		fwrite(HKEY("\n"), 1, sc->digestfp);

		FreeStrBuf(&CC->redirect_buffer);

		sc->num_msgs_spooled += 1;
		CM_Free(msg);
	}
}
コード例 #19
0
ファイル: serv_smtpqueue.c プロジェクト: mingodad/citadel
/*
 * smtp_do_procmsg()
 *
 * Called by smtp_do_queue() to handle an individual message.
 */
void smtp_do_procmsg(long msgnum, void *userdata) {
	time_t now;
	int mynumsessions = num_sessions;
	struct CtdlMessage *msg = NULL;
	char *Author = NULL;
	char *Address = NULL;
	char *instr = NULL;
	StrBuf *PlainQItem;
	OneQueItem *MyQItem;
	char *pch;
	HashPos  *It;
	void *vQE;
	long len;
	const char *Key;
	int HaveBuffers = 0;
	StrBuf *Msg =NULL;

	if (mynumsessions > max_sessions_for_outbound_smtp) {
		SMTPC_syslog(LOG_INFO,
			     "skipping because of num jobs %d > %d max_sessions_for_outbound_smtp",
			     mynumsessions,
			     max_sessions_for_outbound_smtp);
	}

	SMTPC_syslog(LOG_DEBUG, "smtp_do_procmsg(%ld)\n", msgnum);
	///strcpy(envelope_from, "");

	msg = CtdlFetchMessage(msgnum, 1, 1);
	if (msg == NULL) {
		SMTPC_syslog(LOG_ERR, "tried %ld but no such message!\n",
		       msgnum);
		return;
	}

	pch = instr = msg->cm_fields[eMesageText];

	/* Strip out the headers (no not amd any other non-instruction) line */
	while (pch != NULL) {
		pch = strchr(pch, '\n');
		if ((pch != NULL) &&
		    ((*(pch + 1) == '\n') ||
		     (*(pch + 1) == '\r')))
		{
			instr = pch + 2;
			pch = NULL;
		}
	}
	PlainQItem = NewStrBufPlain(instr, -1);
	CM_Free(msg);
	MyQItem = DeserializeQueueItem(PlainQItem, msgnum);
	FreeStrBuf(&PlainQItem);

	if (MyQItem == NULL) {
		SMTPC_syslog(LOG_ERR,
			     "Msg No %ld: already in progress!\n",
			     msgnum);
		return; /* s.b. else is already processing... */
	}

	/*
	 * Postpone delivery if we've already tried recently.
	 */
	now = time(NULL);
	if ((MyQItem->ReattemptWhen != 0) && 
	    (now < MyQItem->ReattemptWhen) &&
	    (run_queue_now == 0))
	{
		SMTPC_syslog(LOG_DEBUG, 
			     "Retry time not yet reached. %ld seconds left.",
			     MyQItem->ReattemptWhen - now);

		It = GetNewHashPos(MyQItem->MailQEntries, 0);
		pthread_mutex_lock(&ActiveQItemsLock);
		{
			if (GetHashPosFromKey(ActiveQItems,
					      LKEY(MyQItem->MessageID),
					      It))
			{
				DeleteEntryFromHash(ActiveQItems, It);
			}
		}
		pthread_mutex_unlock(&ActiveQItemsLock);
		////FreeQueItem(&MyQItem); TODO: DeleteEntryFromHash frees this?
		DeleteHashPos(&It);
		return;
	}

	/*
	 * Bail out if there's no actual message associated with this
	 */
	if (MyQItem->MessageID < 0L) {
		SMTPCM_syslog(LOG_ERR, "no 'msgid' directive found!\n");
		It = GetNewHashPos(MyQItem->MailQEntries, 0);
		pthread_mutex_lock(&ActiveQItemsLock);
		{
			if (GetHashPosFromKey(ActiveQItems,
					      LKEY(MyQItem->MessageID),
					      It))
			{
				DeleteEntryFromHash(ActiveQItems, It);
			}
		}
		pthread_mutex_unlock(&ActiveQItemsLock);
		DeleteHashPos(&It);
		////FreeQueItem(&MyQItem); TODO: DeleteEntryFromHash frees this?
		return;
	}


	It = GetNewHashPos(MyQItem->MailQEntries, 0);
	while (GetNextHashPos(MyQItem->MailQEntries, It, &len, &Key, &vQE))
	{
		MailQEntry *ThisItem = vQE;
		SMTPC_syslog(LOG_DEBUG, "SMTP Queue: Task: <%s> %d\n",
			     ChrPtr(ThisItem->Recipient),
			     ThisItem->Active);
	}
	DeleteHashPos(&It);

	MyQItem->NotYetShutdownDeliveries = 
		MyQItem->ActiveDeliveries = CountActiveQueueEntries(MyQItem, 1);

	/* failsafe against overload: 
	 * will we exceed the limit set? 
	 */
	if ((MyQItem->ActiveDeliveries + mynumsessions > max_sessions_for_outbound_smtp) && 
	    /* if yes, did we reach more than half of the quota? */
	    ((mynumsessions * 2) > max_sessions_for_outbound_smtp) && 
	    /* if... would we ever fit into half of the quota?? */
	    (((MyQItem->ActiveDeliveries * 2)  < max_sessions_for_outbound_smtp)))
	{
		/* abort delivery for another time. */
		SMTPC_syslog(LOG_INFO,
			     "SMTP Queue: skipping because of num jobs %d + %ld > %d max_sessions_for_outbound_smtp",
			     mynumsessions,
			     MyQItem->ActiveDeliveries,
			     max_sessions_for_outbound_smtp);

		It = GetNewHashPos(MyQItem->MailQEntries, 0);
		pthread_mutex_lock(&ActiveQItemsLock);
		{
			if (GetHashPosFromKey(ActiveQItems,
					      LKEY(MyQItem->MessageID),
					      It))
			{
				DeleteEntryFromHash(ActiveQItems, It);
			}
		}
		pthread_mutex_unlock(&ActiveQItemsLock);

		return;
	}


	if (MyQItem->ActiveDeliveries > 0)
	{
		ParsedURL *RelayUrls = NULL;
		int nActivated = 0;
		int n = MsgCount++;
		int m = MyQItem->ActiveDeliveries;
		int i = 1;

		It = GetNewHashPos(MyQItem->MailQEntries, 0);

		Msg = smtp_load_msg(MyQItem, n, &Author, &Address);
		RelayUrls = LoadRelayUrls(MyQItem, Author, Address);
		if ((RelayUrls == NULL) && MyQItem->HaveRelay) {

			while ((i <= m) &&
			       (GetNextHashPos(MyQItem->MailQEntries,
					       It, &len, &Key, &vQE)))
			{
				int KeepBuffers = (i == m);
				MailQEntry *ThisItem = vQE;
				StrBufPrintf(ThisItem->StatusMessage,
					     "No relay configured matching %s / %s", 
					     (Author != NULL)? Author : "",
					     (Address != NULL)? Address : "");
				ThisItem->Status = 5;

				nActivated++;

				if (i > 1) n = MsgCount++;
				SMTPC_syslog(LOG_INFO,
					     "SMTPC: giving up on <%ld> <%s> %d / %d \n",
					     MyQItem->MessageID,
					     ChrPtr(ThisItem->Recipient),
					     i,
					     m);
				(*((int*) userdata)) ++;
				smtp_try_one_queue_entry(MyQItem,
							 ThisItem,
							 Msg,
							 KeepBuffers,
							 n,
							 RelayUrls);

				if (KeepBuffers) HaveBuffers++;

				i++;
			}
			if (Author != NULL) free (Author);
			if (Address != NULL) free (Address);
			DeleteHashPos(&It);

			return;
		}
		if (Author != NULL) free (Author);
		if (Address != NULL) free (Address);

		while ((i <= m) &&
		       (GetNextHashPos(MyQItem->MailQEntries,
				       It, &len, &Key, &vQE)))
		{
			MailQEntry *ThisItem = vQE;

			if (ThisItem->Active == 1)
			{
				int KeepBuffers = (i == m);

				nActivated++;
				if (nActivated % ndelay_count == 0)
					usleep(delay_msec);

				if (i > 1) n = MsgCount++;
				SMTPC_syslog(LOG_DEBUG,
					     "SMTPC: Trying <%ld> <%s> %d / %d \n",
					     MyQItem->MessageID,
					     ChrPtr(ThisItem->Recipient),
					     i,
					     m);
				(*((int*) userdata)) ++;
				smtp_try_one_queue_entry(MyQItem,
							 ThisItem,
							 Msg,
							 KeepBuffers,
							 n,
							 RelayUrls);

				if (KeepBuffers) HaveBuffers++;

				i++;
			}
		}
		DeleteHashPos(&It);
	}
	else
	{
		It = GetNewHashPos(MyQItem->MailQEntries, 0);
		pthread_mutex_lock(&ActiveQItemsLock);
		{
			if (GetHashPosFromKey(ActiveQItems,
					      LKEY(MyQItem->MessageID),
					      It))
			{
				DeleteEntryFromHash(ActiveQItems, It);
			}
			else
			{
				long len;
				const char* Key;
				void *VData;

				SMTPC_syslog(LOG_WARNING,
					     "unable to find QItem with ID[%ld]",
					     MyQItem->MessageID);
				while (GetNextHashPos(ActiveQItems,
						      It,
						      &len,
						      &Key,
						      &VData))
				{
					SMTPC_syslog(LOG_WARNING,
						     "have: ID[%ld]",
						     ((OneQueItem *)VData)->MessageID);
				}
			}

		}
		pthread_mutex_unlock(&ActiveQItemsLock);
		DeleteHashPos(&It);
		////FreeQueItem(&MyQItem); TODO: DeleteEntryFromHash frees this?

// TODO: bounce & delete?

	}
	if (!HaveBuffers) {
		FreeStrBuf (&Msg);
// TODO : free RelayUrls
	}
}
コード例 #20
0
ファイル: serv_wiki.c プロジェクト: mingodad/citadel
/*
 * Fetch a specific revision of a wiki page.  The "operation" string may be set to "fetch" in order
 * to simply fetch the desired revision and store it in a temporary location for viewing, or "revert"
 * to revert the currently active page to that revision.
 */
void wiki_rev(char *pagename, char *rev, char *operation)
{
	struct CitContext *CCC = CC;
	int r;
	char history_page_name[270];
	long msgnum;
	char temp[PATH_MAX];
	struct CtdlMessage *msg;
	FILE *fp;
	struct HistoryEraserCallBackData hecbd;
	long len = 0L;
	int rv;

	r = CtdlDoIHavePermissionToReadMessagesInThisRoom();
	if (r != om_ok) {
		if (r == om_not_logged_in) {
			cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
		}
		else {
			cprintf("%d An unknown error has occurred.\n", ERROR);
		}
		return;
	}

	if (!strcasecmp(operation, "revert")) {
		r = CtdlDoIHavePermissionToPostInThisRoom(temp, sizeof temp, NULL, POST_LOGGED_IN, 0);
		if (r != 0) {
			cprintf("%d %s\n", r, temp);
			return;
		}
	}

	/* Begin by fetching the current version of the page.  We're going to patch
	 * backwards through the diffs until we get the one we want.
	 */
	msgnum = CtdlLocateMessageByEuid(pagename, &CCC->room);
	if (msgnum > 0L) {
		msg = CtdlFetchMessage(msgnum, 1, 1);
	}
	else {
		msg = NULL;
	}

	if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) {
		CM_Free(msg);
		msg = NULL;
	}

	if (msg == NULL) {
		cprintf("%d Page '%s' was not found.\n", ERROR+MESSAGE_NOT_FOUND, pagename);
		return;
	}

	/* Output it to a temporary file */

	CtdlMakeTempFileName(temp, sizeof temp);
	fp = fopen(temp, "w");
	if (fp != NULL) {
		r = fwrite(msg->cm_fields[eMesageText], msg->cm_lengths[eMesageText], 1, fp);
		fclose(fp);
	}
	else {
		syslog(LOG_ALERT, "Cannot open %s: %s\n", temp, strerror(errno));
	}
	CM_Free(msg);

	/* Get the revision history */

	snprintf(history_page_name, sizeof history_page_name, "%s_HISTORY_", pagename);
	msgnum = CtdlLocateMessageByEuid(history_page_name, &CCC->room);
	if (msgnum > 0L) {
		msg = CtdlFetchMessage(msgnum, 1, 1);
	}
	else {
		msg = NULL;
	}

	if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) {
		CM_Free(msg);
		msg = NULL;
	}

	if (msg == NULL) {
		cprintf("%d Revision history for '%s' was not found.\n", ERROR+MESSAGE_NOT_FOUND, pagename);
		return;
	}

	/* Start patching backwards (newest to oldest) through the revision history until we
	 * hit the revision uuid requested by the user.  (The callback will perform each one.)
	 */

	memset(&hecbd, 0, sizeof(struct HistoryEraserCallBackData));
	hecbd.tempfilename = temp;
	hecbd.stop_when = rev;
	striplt(hecbd.stop_when);

	mime_parser(CM_RANGE(msg, eMesageText), *wiki_rev_callback, NULL, NULL, (void *)&hecbd, 0);
	CM_Free(msg);

	/* Were we successful? */
	if (hecbd.done == 0) {
		cprintf("%d Revision '%s' of page '%s' was not found.\n",
			ERROR + MESSAGE_NOT_FOUND, rev, pagename
		);
	}

	/* We have the desired revision on disk.  Now do something with it. */

	else if ( (!strcasecmp(operation, "fetch")) || (!strcasecmp(operation, "revert")) ) {
		msg = malloc(sizeof(struct CtdlMessage));
		memset(msg, 0, sizeof(struct CtdlMessage));
		msg->cm_magic = CTDLMESSAGE_MAGIC;
		msg->cm_anon_type = MES_NORMAL;
		msg->cm_format_type = FMT_RFC822;
		fp = fopen(temp, "r");
		if (fp) {
			char *msgbuf;
			fseek(fp, 0L, SEEK_END);
			len = ftell(fp);
			fseek(fp, 0L, SEEK_SET);
			msgbuf = malloc(len + 1);
			rv = fread(msgbuf, len, 1, fp);
			syslog(LOG_DEBUG, "did %d blocks of %ld bytes\n", rv, len);
			msgbuf[len] = '\0';
			CM_SetAsField(msg, eMesageText, &msgbuf, len);
			fclose(fp);
		}
		if (len <= 0) {
			msgnum = (-1L);
		}
		else if (!strcasecmp(operation, "fetch")) {
			CM_SetField(msg, eAuthor, HKEY("Citadel"));
			CtdlCreateRoom(wwm, 5, "", 0, 1, 1, VIEW_BBS);	/* Not an error if already exists */
			msgnum = CtdlSubmitMsg(msg, NULL, wwm, 0);	/* Store the revision here */

			/*
			 * WARNING: VILE SLEAZY HACK
			 * This will avoid the 'message xxx is not in this room' security error,
			 * but only if the client fetches the message we just generated immediately
			 * without first trying to perform other fetch operations.
			 */
			if (CCC->cached_msglist != NULL) {
				free(CCC->cached_msglist);
				CCC->cached_msglist = NULL;
				CCC->cached_num_msgs = 0;
			}
			CCC->cached_msglist = malloc(sizeof(long));
			if (CCC->cached_msglist != NULL) {
				CCC->cached_num_msgs = 1;
				CCC->cached_msglist[0] = msgnum;
			}

		}
		else if (!strcasecmp(operation, "revert")) {
			CM_SetFieldLONG(msg, eTimestamp, time(NULL));
			if (!IsEmptyStr(CCC->user.fullname)) {
				CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
			}

			if (!IsEmptyStr(CCC->cs_inet_email)) {
				CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email));
			}

			if (!IsEmptyStr(CCC->room.QRname)) {
				CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
			}

			CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
			
			if (!IsEmptyStr(pagename)) {
				CM_SetField(msg, eExclusiveID, pagename, strlen(pagename));
			}
			msgnum = CtdlSubmitMsg(msg, NULL, "", 0);	/* Replace the current revision */
		}
		else {
			/* Theoretically it is impossible to get here, but throw an error anyway */
			msgnum = (-1L);
		}
		CM_Free(msg);
		if (msgnum >= 0L) {
			cprintf("%d %ld\n", CIT_OK, msgnum);		/* Give the client a msgnum */
		}
		else {
			cprintf("%d Error %ld has occurred.\n", ERROR+INTERNAL_ERROR, msgnum);
		}
	}

	/* We did all this work for nothing.  Express anguish to the caller. */
	else {
		cprintf("%d An unknown operation was requested.\n", ERROR+CMD_NOT_SUPPORTED);
	}

	unlink(temp);
	return;
}
コード例 #21
0
ファイル: serv_smtpqueue.c プロジェクト: mingodad/citadel
/*
 * smtp_do_bounce() is caled by smtp_do_procmsg() to scan a set of delivery
 * instructions for "5" codes (permanent fatal errors) and produce/deliver
 * a "bounce" message (delivery status notification).
 */
void smtpq_do_bounce(OneQueItem *MyQItem, StrBuf *OMsgTxt, ParsedURL *Relay)
{
	static int seq = 0;
	
	struct CtdlMessage *bmsg = NULL;
	StrBuf *boundary;
	StrBuf *Msg = NULL;
	StrBuf *BounceMB;
	recptypes *valid;
	time_t now;

	HashPos *It;
	void *vQE;
	long len;
	const char *Key;

	int first_attempt = 0;
	int successful_bounce = 0;
	int num_bounces = 0;
	int give_up = 0;

	SMTPCM_syslog(LOG_DEBUG, "smtp_do_bounce() called\n");

	if (MyQItem->SendBounceMail == 0)
		return;

	now = time (NULL); //ev_time();

	if ( (now - MyQItem->Submitted) > SMTP_GIVE_UP ) {
		give_up = 1;
	}

	if (MyQItem->Retry == SMTP_RETRY_INTERVAL) {
		first_attempt = 1;
	}

	/*
	 * Now go through the instructions checking for stuff.
	 */
	Msg = NewStrBufPlain(NULL, 1024);
	It = GetNewHashPos(MyQItem->MailQEntries, 0);
	while (GetNextHashPos(MyQItem->MailQEntries, It, &len, &Key, &vQE))
	{
		MailQEntry *ThisItem = vQE;
		if ((ThisItem->Active && (ThisItem->Status == 5)) || /* failed now? */
		    ((give_up == 1) && (ThisItem->Status != 2)) ||
		    ((first_attempt == 1) && (ThisItem->Status != 2)))
			/* giving up after failed attempts... */
		{
			++num_bounces;

			StrBufAppendBufPlain(Msg, HKEY(" "), 0);
			StrBufAppendBuf(Msg, ThisItem->Recipient, 0);
			StrBufAppendBufPlain(Msg, HKEY(": "), 0);
			if (ThisItem->AllStatusMessages != NULL)
				StrBufAppendBuf(Msg, ThisItem->AllStatusMessages, 0);
			else
				StrBufAppendBuf(Msg, ThisItem->StatusMessage, 0);
			StrBufAppendBufPlain(Msg, HKEY("\r\n"), 0);
		}
	}
	DeleteHashPos(&It);

	/* Deliver the bounce if there's anything worth mentioning */
	SMTPC_syslog(LOG_DEBUG, "num_bounces = %d\n", num_bounces);

	if (num_bounces == 0) {
		FreeStrBuf(&Msg);
		return;
	}

	if ((StrLength(MyQItem->SenderRoom) == 0) && MyQItem->HaveRelay) {
		const char *RelayUrlStr = "[not found]";
		/* one message that relaying is broken is enough; no extra room error message. */
		StrBuf *RelayDetails = NewStrBuf();

		if (Relay != NULL)
			RelayUrlStr = ChrPtr(Relay->URL);

		StrBufPrintf(RelayDetails,
			     "Relaying via %s failed permanently. \n Reason:\n%s\n Revalidate your relay configuration.",
			     RelayUrlStr,
			     ChrPtr(Msg));
                CtdlAideMessage(ChrPtr(RelayDetails), "Relaying Failed");
		FreeStrBuf(&RelayDetails);
	}

	boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));
	StrBufAppendPrintf(boundary,
			   "%s_%04x%04x",
			   CtdlGetConfigStr("c_fqdn"),
			   getpid(),
			   ++seq);

	/* Start building our bounce message; go shopping for memory first. */
	BounceMB = NewStrBufPlain(
		NULL,
		1024 + /* mime stuff.... */
		StrLength(Msg) +  /* the bounce information... */
		StrLength(OMsgTxt)); /* the original message */
	if (BounceMB == NULL) {
		FreeStrBuf(&boundary);
		SMTPCM_syslog(LOG_ERR, "Failed to alloc() bounce message.\n");

		return;
	}

	bmsg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
	if (bmsg == NULL) {
		FreeStrBuf(&boundary);
		FreeStrBuf(&BounceMB);
		SMTPCM_syslog(LOG_ERR, "Failed to alloc() bounce message.\n");

		return;
	}
	memset(bmsg, 0, sizeof(struct CtdlMessage));


	StrBufAppendBufPlain(BounceMB, HKEY("Content-type: multipart/mixed; boundary=\""), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\"\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("MIME-Version: 1.0\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("X-Mailer: " CITADEL "\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\r\nThis is a multipart message in MIME format.\r\n\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("Content-type: text/plain\r\n\r\n"), 0);

	if (give_up)
		StrBufAppendBufPlain(
			BounceMB,
			HKEY(
				"A message you sent could not be delivered "
				"to some or all of its recipients\n"
				"due to prolonged unavailability "
				"of its destination(s).\n"
				"Giving up on the following addresses:\n\n"
				), 0);
	else
		StrBufAppendBufPlain(
			BounceMB,
			HKEY(
				"A message you sent could not be delivered "
				"to some or all of its recipients.\n"
				"The following addresses "
				"were undeliverable:\n\n"
				), 0);

	StrBufAppendBuf(BounceMB, Msg, 0);
	FreeStrBuf(&Msg);

	if (StrLength(MyQItem->SenderRoom) > 0)
	{
		StrBufAppendBufPlain(
			BounceMB,
			HKEY("The message was originaly posted in: "), 0);
		StrBufAppendBuf(BounceMB, MyQItem->SenderRoom, 0);
		StrBufAppendBufPlain(
			BounceMB,
			HKEY("\n"), 0);
	}

	/* Attach the original message */
	StrBufAppendBufPlain(BounceMB, HKEY("\r\n--"), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
	StrBufAppendBufPlain(BounceMB,
			     HKEY("Content-type: message/rfc822\r\n"), 0);
	StrBufAppendBufPlain(BounceMB,
			     HKEY("Content-Transfer-Encoding: 7bit\r\n"), 0);
	StrBufAppendBufPlain(BounceMB,
			     HKEY("Content-Disposition: inline\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
	StrBufAppendBuf(BounceMB, OMsgTxt, 0);

	/* Close the multipart MIME scope */
	StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("--\r\n"), 0);

	bmsg->cm_magic = CTDLMESSAGE_MAGIC;
	bmsg->cm_anon_type = MES_NORMAL;
	bmsg->cm_format_type = FMT_RFC822;

	CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
	CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
	CM_SetField(bmsg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
	CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
	CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);

	/* First try the user who sent the message */
	if (StrLength(MyQItem->BounceTo) == 0) {
		SMTPCM_syslog(LOG_ERR, "No bounce address specified\n");
	}
	else {
		SMTPC_syslog(LOG_DEBUG, "bounce to user? <%s>\n",
		       ChrPtr(MyQItem->BounceTo));
	}

	/* Can we deliver the bounce to the original sender? */
	valid = validate_recipients(ChrPtr(MyQItem->BounceTo), NULL, 0);
	if ((valid != NULL) && (valid->num_error == 0)) {
		CtdlSubmitMsg(bmsg, valid, "", QP_EADDR);
		successful_bounce = 1;
	}

	/* If not, post it in the Aide> room */
	if (successful_bounce == 0) {
		CtdlSubmitMsg(bmsg, NULL, CtdlGetConfigStr("c_aideroom"), QP_EADDR);
	}

	/* Free up the memory we used */
	free_recipients(valid);
	FreeStrBuf(&boundary);
	CM_Free(bmsg);
	SMTPCM_syslog(LOG_DEBUG, "Done processing bounces\n");
}
コード例 #22
0
ファイル: serv_netmail.c プロジェクト: henri14/citadel
void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long *delete_after_send)
{
	StrBuf *Recipient;
	StrBuf *RemoteRoom;
	const char *Pos = NULL;
	struct CtdlMessage *msg = NULL;
	struct CitContext *CCC = CC;
	struct ser_ret sermsg;
	char buf[SIZ];
	char filename[PATH_MAX];
	FILE *fp;
	StrBuf *Buf = NULL;
	int i;
	int bang = 0;
	int send = 1;

	if (sc->Users[ignet_push_share] == NULL)
		return;

	/*
	 * Process IGnet push shares
	 */
	msg = CM_Duplicate(omsg);

	/* Prepend our node name to the Path field whenever
	 * sending a message to another IGnet node
	 */
	Netmap_AddMe(msg, HKEY("username"));

	/*
	 * Determine if this message is set to be deleted
	 * after sending out on the network
	 */
	if (!CM_IsEmpty(msg, eSpecialField)) {
		if (!strcasecmp(msg->cm_fields[eSpecialField], "CANCEL")) {
			*delete_after_send = 1;
		}
	}

	/* Now send it to every node */
	Recipient = NewStrBufPlain(NULL, StrLength(sc->Users[ignet_push_share]));
	RemoteRoom = NewStrBufPlain(NULL, StrLength(sc->Users[ignet_push_share]));
	while ((Pos != StrBufNOTNULL) &&
	       StrBufExtract_NextToken(Recipient, sc->Users[ignet_push_share], &Pos, ','))
	{
		StrBufExtract_NextToken(RemoteRoom, sc->Users[ignet_push_share], &Pos, ',');
		send = 1;
		NewStrBufDupAppendFlush(&Buf, Recipient, NULL, 1);
			
		/* Check for valid node name */
		if (CtdlIsValidNode(NULL,
				    NULL,
				    Buf,
				    sc->working_ignetcfg,
				    sc->the_netmap) != 0)
		{
			QN_syslog(LOG_ERR,
				  "Invalid node <%s>\n",
				  ChrPtr(Recipient));
			
			send = 0;
		}
		
		/* Check for split horizon */
		QN_syslog(LOG_DEBUG, "Path is %s\n", msg->cm_fields[eMessagePath]);
		bang = num_tokens(msg->cm_fields[eMessagePath], '!');
		if (bang > 1) {
			for (i=0; i<(bang-1); ++i) {
				extract_token(buf,
					      msg->cm_fields[eMessagePath],
					      i, '!',
					      sizeof buf);

				QN_syslog(LOG_DEBUG, "Compare <%s> to <%s>\n",
					  buf, ChrPtr(Recipient)) ;
				if (!strcasecmp(buf, ChrPtr(Recipient))) {
					send = 0;
					break;
				}
			}
			
			QN_syslog(LOG_INFO,
				  " %sSending to %s\n",
				  (send)?"":"Not ",
				  ChrPtr(Recipient));
		}
		
		/* Send the message */
		if (send == 1)
		{
			/*
			 * Force the message to appear in the correct
			 * room on the far end by setting the C field
			 * correctly
			 */
			if (StrLength(RemoteRoom) > 0) {
				CM_SetField(msg, eRemoteRoom, SKEY(RemoteRoom));
			}
			else {
				CM_SetField(msg, eRemoteRoom, CCC->room.QRname, strlen(CCC->room.QRname));
			}
			
			/* serialize it for transmission */
			CtdlSerializeMessage(&sermsg, msg);
			if (sermsg.len > 0) {
				
				/* write it to a spool file */
				snprintf(filename,
					 sizeof(filename),
					 "%s/%s@%lx%x",
					 ctdl_netout_dir,
					 ChrPtr(Recipient),
					 time(NULL),
					 rand()
					);
					
				QN_syslog(LOG_DEBUG,
					  "Appending to %s\n",
					  filename);
				
				fp = fopen(filename, "ab");
				if (fp != NULL) {
					fwrite(sermsg.ser,
					       sermsg.len, 1, fp);
					fclose(fp);
				}
				else {
					QN_syslog(LOG_ERR,
						  "%s: %s\n",
						  filename,
						  strerror(errno));
				}

				/* free the serialized version */
				free(sermsg.ser);
			}
		}
	}
	FreeStrBuf(&Buf);
	FreeStrBuf(&Recipient);
	FreeStrBuf(&RemoteRoom);
	CM_Free(msg);
}
コード例 #23
0
ファイル: tr_init.cpp プロジェクト: Camron/OpenJK
void R_Init( void ) {	
	int	err;
	int i;

	//VID_Printf( PRINT_ALL, "----- R_Init -----\n" );
#ifdef _XBOX
	extern qboolean vidRestartReloadMap;
	if (!vidRestartReloadMap)
	{
		Hunk_Clear();
		
		extern void CM_Free(void);
		CM_Free();
		
		void CM_CleanLeafCache(void);
		CM_CleanLeafCache();
	}
#endif

	ShaderEntryPtrs_Clear();

#ifdef _XBOX
	//Save visibility info as it has already been set.
	SPARC<byte> *vis = tr.externalVisData;
#endif

	// clear all our internal state
	memset( &tr, 0, sizeof( tr ) );
	memset( &backEnd, 0, sizeof( backEnd ) );
	memset( &tess, 0, sizeof( tess ) );

#ifdef _XBOX
	//Restore visibility info.
	tr.externalVisData = vis;
#endif

	Swap_Init();

#ifndef FINAL_BUILD
	if ( (int)tess.xyz & 15 ) {
		Com_Printf( "WARNING: tess.xyz not 16 byte aligned (%x)\n",(int)tess.xyz & 15 );
	}
#endif

	//
	// init function tables
	//
	for ( i = 0; i < FUNCTABLE_SIZE; i++ )
	{
		tr.sinTable[i]		= sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );
		tr.squareTable[i]	= ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
		tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
		tr.inverseSawToothTable[i] = 1.0 - tr.sawToothTable[i];

		if ( i < FUNCTABLE_SIZE / 2 )
		{
			if ( i < FUNCTABLE_SIZE / 4 )
			{
				tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );
			}
			else
			{
				tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];
			}
		}
		else
		{
			tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];
		}
	}

	R_InitFogTable();

	R_NoiseInit();

	R_Register();

	backEndData = (backEndData_t *) Hunk_Alloc( sizeof( backEndData_t ), qtrue );
	R_ToggleSmpFrame();	//r_smp

	const color4ub_t	color = {0xff, 0xff, 0xff, 0xff};
	for(i=0;i<MAX_LIGHT_STYLES;i++)
	{
		RE_SetLightStyle(i, *(int*)color);
	}

	InitOpenGL();

	R_InitImages();
	R_InitShaders();
	R_InitSkins();
#ifndef _XBOX
	R_TerrainInit();
#endif
	R_ModelInit();
//	R_InitWorldEffects();
	R_InitFonts();

	err = qglGetError();
	if ( err != GL_NO_ERROR )
		VID_Printf (PRINT_ALL, "glGetError() = 0x%x\n", err);

	//VID_Printf( PRINT_ALL, "----- finished R_Init -----\n" );
}
コード例 #24
0
ファイル: serv_instmsg.c プロジェクト: henri14/citadel
/*
 * This is the back end for flush_conversations_to_disk()
 * At this point we've isolated a single conversation (struct imlog)
 * and are ready to write it to disk.
 */
void flush_individual_conversation(struct imlog *im) {
	struct CtdlMessage *msg;
	long msgnum = 0;
	char roomname[ROOMNAMELEN];
	StrBuf *MsgBuf, *FullMsgBuf;

	StrBufAppendBufPlain(im->conversation, HKEY(
		"</body>\r\n"
		"</html>\r\n"
		), 0
	);

	MsgBuf = StrBufRFC2047encodeMessage(im->conversation);
	FlushStrBuf(im->conversation);
	FullMsgBuf = NewStrBufPlain(NULL, StrLength(im->conversation) + 100);

	StrBufAppendBufPlain(FullMsgBuf, HKEY(
			"Content-type: text/html; charset=UTF-8\r\n"
			"Content-Transfer-Encoding: quoted-printable\r\n"
			"\r\n"
			), 0);
	StrBufAppendBuf (FullMsgBuf, MsgBuf, 0);
	FreeStrBuf(&MsgBuf);

	msg = malloc(sizeof(struct CtdlMessage));
	memset(msg, 0, sizeof(struct CtdlMessage));
	msg->cm_magic = CTDLMESSAGE_MAGIC;
	msg->cm_anon_type = MES_NORMAL;
	msg->cm_format_type = FMT_RFC822;
	if (!IsEmptyStr(im->usernames[0])) {
		CM_SetField(msg, eAuthor, im->usernames[0], strlen(im->usernames[0]));
	} else {
		CM_SetField(msg, eAuthor, HKEY("Citadel"));
	}
	if (!IsEmptyStr(im->usernames[1])) {
		CM_SetField(msg, eRecipient, im->usernames[1], strlen(im->usernames[1]));
	}

	CM_SetField(msg, eOriginalRoom, HKEY(PAGELOGROOM));
	CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
	CM_SetAsFieldSB(msg, eMesageText, &FullMsgBuf);	/* we own this memory now */

	/* Start with usernums[1] because it's guaranteed to be higher than usernums[0],
	 * so if there's only one party, usernums[0] will be zero but usernums[1] won't.
	 * Create the room if necessary.  Note that we create as a type 5 room rather
	 * than 4, which indicates that it's a personal room but we've already supplied
	 * the namespace prefix.
	 *
	 * In the unlikely event that usernums[1] is zero, a room with an invalid namespace
	 * prefix will be created.  That's ok because the auto-purger will clean it up later.
	 */
	snprintf(roomname, sizeof roomname, "%010ld.%s", im->usernums[1], PAGELOGROOM);
	CtdlCreateRoom(roomname, 5, "", 0, 1, 1, VIEW_BBS);
	msgnum = CtdlSubmitMsg(msg, NULL, roomname, 0);
	CM_Free(msg);

	/* If there is a valid user number in usernums[0], save a copy for them too. */
	if (im->usernums[0] > 0) {
		snprintf(roomname, sizeof roomname, "%010ld.%s", im->usernums[0], PAGELOGROOM);
		CtdlCreateRoom(roomname, 5, "", 0, 1, 1, VIEW_BBS);
		CtdlSaveMsgPointerInRoom(roomname, msgnum, 0, NULL);
	}

	/* Finally, if we're logging instant messages globally, do that now. */
	if (!IsEmptyStr(config.c_logpages)) {
		CtdlCreateRoom(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS);
		CtdlSaveMsgPointerInRoom(config.c_logpages, msgnum, 0, NULL);
	}

}
コード例 #25
0
ファイル: serv_wiki.c プロジェクト: mingodad/citadel
/*
 * Before allowing a wiki page save to execute, we have to perform version control.
 * This involves fetching the old version of the page if it exists.
 */
int wiki_upload_beforesave(struct CtdlMessage *msg, recptypes *recp) {
	struct CitContext *CCC = CC;
	long old_msgnum = (-1L);
	struct CtdlMessage *old_msg = NULL;
	long history_msgnum = (-1L);
	struct CtdlMessage *history_msg = NULL;
	char diff_old_filename[PATH_MAX];
	char diff_new_filename[PATH_MAX];
	char diff_out_filename[PATH_MAX];
	char diff_cmd[PATH_MAX];
	FILE *fp;
	int rv;
	char history_page[1024];
	long history_page_len;
	char boundary[256];
	char prefixed_boundary[258];
	char buf[1024];
	char *diffbuf = NULL;
	size_t diffbuf_len = 0;
	char *ptr = NULL;
	long newmsgid;
	StrBuf *msgidbuf;

	if (!CCC->logged_in) return(0);	/* Only do this if logged in. */

	/* Is this a room with a Wiki in it, don't run this hook. */
	if ((CCC->room.QRdefaultview != VIEW_WIKI) &&
	    (CCC->room.QRdefaultview != VIEW_WIKIMD)) {
		return(0);
	}

	/* If this isn't a MIME message, don't bother. */
	if (msg->cm_format_type != 4) return(0);

	/* If there's no EUID we can't do this.  Reject the post. */
	if (CM_IsEmpty(msg, eExclusiveID)) return(1);

	newmsgid = get_new_message_number();
	msgidbuf = NewStrBuf();
	StrBufPrintf(msgidbuf, "%08lX-%08lX@%s/%s",
		     (long unsigned int) time(NULL),
		     (long unsigned int) newmsgid,
		     CtdlGetConfigStr("c_fqdn"),
		     msg->cm_fields[eExclusiveID]
		);

	CM_SetAsFieldSB(msg, emessageId, &msgidbuf);

	history_page_len = snprintf(history_page, sizeof history_page,
				    "%s_HISTORY_", msg->cm_fields[eExclusiveID]);

	/* Make sure we're saving a real wiki page rather than a wiki history page.
	 * This is important in order to avoid recursing infinitely into this hook.
	 */
	if (	(msg->cm_lengths[eExclusiveID] >= 9)
		&& (!strcasecmp(&msg->cm_fields[eExclusiveID][msg->cm_lengths[eExclusiveID]-9], "_HISTORY_"))
	) {
		syslog(LOG_DEBUG, "History page not being historied\n");
		return(0);
	}

	/* If there's no message text, obviously this is all b0rken and shouldn't happen at all */
	if (CM_IsEmpty(msg, eMesageText)) return(0);

	/* Set the message subject identical to the page name */
	CM_CopyField(msg, eMsgSubject, eExclusiveID);

	/* See if we can retrieve the previous version. */
	old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CCC->room);
	if (old_msgnum > 0L) {
		old_msg = CtdlFetchMessage(old_msgnum, 1, 1);
	}
	else {
		old_msg = NULL;
	}

	if ((old_msg != NULL) && (CM_IsEmpty(old_msg, eMesageText))) {	/* old version is corrupt? */
		CM_Free(old_msg);
		old_msg = NULL;
	}
	
	/* If no changes were made, don't bother saving it again */
	if ((old_msg != NULL) && (!strcmp(msg->cm_fields[eMesageText], old_msg->cm_fields[eMesageText]))) {
		CM_Free(old_msg);
		return(1);
	}

	/*
	 * Generate diffs
	 */
	CtdlMakeTempFileName(diff_old_filename, sizeof diff_old_filename);
	CtdlMakeTempFileName(diff_new_filename, sizeof diff_new_filename);
	CtdlMakeTempFileName(diff_out_filename, sizeof diff_out_filename);

	if (old_msg != NULL) {
		fp = fopen(diff_old_filename, "w");
		rv = fwrite(old_msg->cm_fields[eMesageText], old_msg->cm_lengths[eMesageText], 1, fp);
		fclose(fp);
		CM_Free(old_msg);
	}

	fp = fopen(diff_new_filename, "w");
	rv = fwrite(msg->cm_fields[eMesageText], msg->cm_lengths[eMesageText], 1, fp);
	fclose(fp);

	snprintf(diff_cmd, sizeof diff_cmd,
		DIFF " -u %s %s >%s",
		diff_new_filename,
		((old_msg != NULL) ? diff_old_filename : "/dev/null"),
		diff_out_filename
	);
	syslog(LOG_DEBUG, "diff cmd: %s", diff_cmd);
	rv = system(diff_cmd);
	syslog(LOG_DEBUG, "diff cmd returned %d", rv);

	diffbuf_len = 0;
	diffbuf = NULL;
	fp = fopen(diff_out_filename, "r");
	if (fp == NULL) {
		fp = fopen("/dev/null", "r");
	}
	if (fp != NULL) {
		fseek(fp, 0L, SEEK_END);
		diffbuf_len = ftell(fp);
		fseek(fp, 0L, SEEK_SET);
		diffbuf = malloc(diffbuf_len + 1);
		fread(diffbuf, diffbuf_len, 1, fp);
		diffbuf[diffbuf_len] = '\0';
		fclose(fp);
	}

	syslog(LOG_DEBUG, "diff length is "SIZE_T_FMT" bytes", diffbuf_len);

	unlink(diff_old_filename);
	unlink(diff_new_filename);
	unlink(diff_out_filename);

	/* Determine whether this was a bogus (empty) edit */
	if ((diffbuf_len = 0) && (diffbuf != NULL)) {
		free(diffbuf);
		diffbuf = NULL;
	}
	if (diffbuf == NULL) {
		return(1);		/* No changes at all?  Abandon the post entirely! */
	}

	/* Now look for the existing edit history */

	history_msgnum = CtdlLocateMessageByEuid(history_page, &CCC->room);
	history_msg = NULL;
	if (history_msgnum > 0L) {
		history_msg = CtdlFetchMessage(history_msgnum, 1, 1);
	}

	/* Create a new history message if necessary */
	if (history_msg == NULL) {
		char *buf;
		long len;

		history_msg = malloc(sizeof(struct CtdlMessage));
		memset(history_msg, 0, sizeof(struct CtdlMessage));
		history_msg->cm_magic = CTDLMESSAGE_MAGIC;
		history_msg->cm_anon_type = MES_NORMAL;
		history_msg->cm_format_type = FMT_RFC822;
		CM_SetField(history_msg, eAuthor, HKEY("Citadel"));
		if (!IsEmptyStr(CCC->room.QRname)){
			CM_SetField(history_msg, eRecipient, CCC->room.QRname, strlen(CCC->room.QRname));
		}
		CM_SetField(history_msg, eExclusiveID, history_page, history_page_len);
		CM_SetField(history_msg, eMsgSubject, history_page, history_page_len);
		CM_SetField(history_msg, eSuppressIdx, HKEY("1")); /* suppress full text indexing */
		snprintf(boundary, sizeof boundary, "Citadel--Multipart--%04x--%08lx", getpid(), time(NULL));
		buf = (char*) malloc(1024);
		len = snprintf(buf, 1024,
			       "Content-type: multipart/mixed; boundary=\"%s\"\n\n"
			       "This is a Citadel wiki history encoded as multipart MIME.\n"
			       "Each part is comprised of a diff script representing one change set.\n"
			       "\n"
			       "--%s--\n",
			       boundary, boundary
		);
		CM_SetAsField(history_msg, eMesageText, &buf, len);
	}

	/* Update the history message (regardless of whether it's new or existing) */

	/* Remove the Message-ID from the old version of the history message.  This will cause a brand
	 * new one to be generated, avoiding an uninitentional hit of the loop zapper when we replicate.
	 */
	CM_FlushField(history_msg, emessageId);

	/* Figure out the boundary string.  We do this even when we generated the
	 * boundary string in the above code, just to be safe and consistent.
	 */
	*boundary = '\0';

	ptr = history_msg->cm_fields[eMesageText];
	do {
		ptr = memreadline(ptr, buf, sizeof buf);
		if (*ptr != 0) {
			striplt(buf);
			if (!IsEmptyStr(buf) && (!strncasecmp(buf, "Content-type:", 13))) {
				if (
					(bmstrcasestr(buf, "multipart") != NULL)
					&& (bmstrcasestr(buf, "boundary=") != NULL)
				) {
					safestrncpy(boundary, bmstrcasestr(buf, "\""), sizeof boundary);
					char *qu;
					qu = strchr(boundary, '\"');
					if (qu) {
						strcpy(boundary, ++qu);
					}
					qu = strchr(boundary, '\"');
					if (qu) {
						*qu = 0;
					}
				}
			}
		}
	} while ( (IsEmptyStr(boundary)) && (*ptr != 0) );

	/*
	 * Now look for the first boundary.  That is where we need to insert our fun.
	 */
	if (!IsEmptyStr(boundary)) {
		char *MsgText;
		long MsgTextLen;
		time_t Now = time(NULL);

		snprintf(prefixed_boundary, sizeof(prefixed_boundary), "--%s", boundary);
		
		CM_GetAsField(history_msg, eMesageText, &MsgText, &MsgTextLen);

		ptr = bmstrcasestr(MsgText, prefixed_boundary);
		if (ptr != NULL) {
			StrBuf *NewMsgText;
			char uuid[64];
			char memo[512];
			long memolen;
			char encoded_memo[1024];
			
			NewMsgText = NewStrBufPlain(NULL, MsgTextLen + diffbuf_len + 1024);

			generate_uuid(uuid);
			memolen = snprintf(memo, sizeof(memo), "%s|%ld|%s|%s", 
					   uuid,
					   Now,
					   CCC->user.fullname,
					   CtdlGetConfigStr("c_nodename"));

			memolen = CtdlEncodeBase64(encoded_memo, memo, memolen, 0);

			StrBufAppendBufPlain(NewMsgText, HKEY("--"), 0);
			StrBufAppendBufPlain(NewMsgText, boundary, -1, 0);
			StrBufAppendBufPlain(
				NewMsgText, 
				HKEY("\n"
				     "Content-type: text/plain\n"
				     "Content-Disposition: inline; filename=\""), 0);

			StrBufAppendBufPlain(NewMsgText, encoded_memo, memolen, 0);

			StrBufAppendBufPlain(
				NewMsgText, 
				HKEY("\"\n"
				     "Content-Transfer-Encoding: 8bit\n"
				     "\n"), 0);

			StrBufAppendBufPlain(NewMsgText, diffbuf, diffbuf_len, 0);
			StrBufAppendBufPlain(NewMsgText, HKEY("\n"), 0);

			StrBufAppendBufPlain(NewMsgText, ptr, MsgTextLen - (ptr - MsgText), 0);
			free(MsgText);
			CM_SetAsFieldSB(history_msg, eMesageText, &NewMsgText); 
		}
		else
		{
			CM_SetAsField(history_msg, eMesageText, &MsgText, MsgTextLen); 
		}

		CM_SetFieldLONG(history_msg, eTimestamp, Now);
	
		CtdlSubmitMsg(history_msg, NULL, "", 0);
	}
	else {
		syslog(LOG_ALERT, "Empty boundary string in history message.  No history!\n");
	}

	free(diffbuf);
	CM_Free(history_msg);
	return(0);
}
コード例 #26
0
ファイル: serv_autocompletion.c プロジェクト: henri14/citadel
/*
 * Back end for cmd_auto()
 */
void hunt_for_autocomplete(long msgnum, char *search_string) {
	struct CtdlMessage *msg;
	struct vCard *v;
	char *value = NULL;
	char *value2 = NULL;
	int i = 0;
	char *nnn = NULL;

	msg = CtdlFetchMessage(msgnum, 1);
	if (msg == NULL) return;

	v = vcard_load(msg->cm_fields[eMesageText]);
	CM_Free(msg);

	/*
	 * Try to match from a friendly name (the "fn" field).  If there is
	 * a match, return the entry in the form of:
	 *     Display Name <*****@*****.**>
	 */
	value = vcard_get_prop(v, "fn", 0, 0, 0);
	if (value != NULL) if (bmstrcasestr(value, search_string)) {
		value2 = vcard_get_prop(v, "email", 1, 0, 0);
		if (value2 == NULL) value2 = "";
		cprintf("%s <%s>\n", value, value2);
		vcard_free(v);
		return;
	}

	/*
	 * Try to match from a structured name (the "n" field).  If there is
	 * a match, return the entry in the form of:
	 *     Display Name <*****@*****.**>
	 */
	value = vcard_get_prop(v, "n", 0, 0, 0);
	if (value != NULL) if (bmstrcasestr(value, search_string)) {

		value2 = vcard_get_prop(v, "email", 1, 0, 0);
		if (value2 == NULL) value2 = "";
		nnn = n_to_fn(value);
		cprintf("%s <%s>\n", nnn, value2);
		free(nnn);
		vcard_free(v);
		return;
	}

	/*
	 * Try a partial match on all listed email addresses.
	 */
	i = 0;
	while (value = vcard_get_prop(v, "email", 1, i++, 0), value != NULL) {
		if (bmstrcasestr(value, search_string)) {
			if (vcard_get_prop(v, "fn", 0, 0, 0)) {
				cprintf("%s <%s>\n", vcard_get_prop(v, "fn", 0, 0, 0), value);
			}
			else if (vcard_get_prop(v, "n", 0, 0, 0)) {
				nnn = n_to_fn(vcard_get_prop(v, "n", 0, 0, 0));
				cprintf("%s <%s>\n", nnn, value);
				free(nnn);
			
			}
			else {
				cprintf("%s\n", value);
			}
			vcard_free(v);
			return;
		}
	}

	vcard_free(v);
}
コード例 #27
0
/*
* SV_ShutdownGame
* 
* Called when each game quits
*/
void SV_ShutdownGame( const char *finalmsg, qboolean reconnect )
{
	if( !svs.initialized )
		return;

	if( svs.demo.file )
		SV_Demo_Stop_f();

	if( svs.clients )
		SV_FinalMessage( finalmsg, reconnect );

	SV_ShutdownGameProgs();

	// SV_MM_Shutdown();

	NET_CloseSocket( &svs.socket_loopback );
	NET_CloseSocket( &svs.socket_udp );
	NET_CloseSocket( &svs.socket_udp6 );
#ifdef TCP_ALLOW_CONNECT
	if( sv_tcp->integer )
		NET_CloseSocket( &svs.socket_tcp );
#endif

	// get any latched variable changes (sv_maxclients, etc)
	Cvar_GetLatchedVars( CVAR_LATCH );

	if( svs.clients )
	{
		Mem_Free( svs.clients );
		svs.clients = NULL;
	}

	if( svs.client_entities.entities )
	{
		Mem_Free( svs.client_entities.entities );
		memset( &svs.client_entities, 0, sizeof( svs.client_entities ) );
	}

	if( svs.cms )
	{
		CM_Free( svs.cms );
		svs.cms = NULL;
	}

	memset( &sv, 0, sizeof( sv ) );
	Com_SetServerState( sv.state );

	Com_FreePureList( &svs.purelist );

	if( svs.motd )
	{
		Mem_Free( svs.motd );
		svs.motd = NULL;
	}

	if( sv_mempool )
		Mem_EmptyPool( sv_mempool );

	memset( &svs, 0, sizeof( svs ) );

	svs.initialized = qfalse;
}
コード例 #28
0
ファイル: serv_fulltext.c プロジェクト: mingodad/citadel
/*
 * Index or de-index a message.  (op == 1 to index, 0 to de-index)
 */
void ft_index_message(long msgnum, int op) {
	int num_tokens = 0;
	int *tokens = NULL;
	int i, j;
	struct cdbdata *cdb_bucket;
	StrBuf *msgtext;
	char *txt;
	int tok;
	struct CtdlMessage *msg = NULL;

	msg = CtdlFetchMessage(msgnum, 1, 1);
	if (msg == NULL) {
		syslog(LOG_ERR, "ft_index_message() could not load msg %ld", msgnum);
		return;
	}

	if (!CM_IsEmpty(msg, eSuppressIdx)) {
		syslog(LOG_DEBUG, "ft_index_message() excluded msg %ld", msgnum);
		CM_Free(msg);
		return;
	}

	syslog(LOG_DEBUG, "ft_index_message() %s msg %ld", (op ? "adding" : "removing") , msgnum);

	/* Output the message as text before indexing it, so we don't end up
	 * indexing a bunch of encoded base64, etc.
	 */
	CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
	CtdlOutputPreLoadedMsg(msg, MT_CITADEL, HEADERS_ALL, 0, 1, 0);
	CM_Free(msg);
	msgtext = CC->redirect_buffer;
	CC->redirect_buffer = NULL;
	if (msgtext != NULL) {
		syslog(LOG_DEBUG, "Wordbreaking message %ld (%d bytes)", msgnum, StrLength(msgtext));
	}
	txt = SmashStrBuf(&msgtext);
	wordbreaker(txt, &num_tokens, &tokens);
	free(txt);

	syslog(LOG_DEBUG, "Indexing message %ld [%d tokens]", msgnum, num_tokens);
	if (num_tokens > 0) {
		for (i=0; i<num_tokens; ++i) {

			/* Add the message to the relevant token bucket */

			/* search for tokens[i] */
			tok = tokens[i];

			if ( (tok >= 0) && (tok <= 65535) ) {
				/* fetch the bucket, Liza */
				if (ftc_msgs[tok] == NULL) {
					cdb_bucket = cdb_fetch(CDB_FULLTEXT, &tok, sizeof(int));
					if (cdb_bucket != NULL) {
						ftc_num_msgs[tok] = cdb_bucket->len / sizeof(long);
						ftc_msgs[tok] = (long *)cdb_bucket->ptr;
						cdb_bucket->ptr = NULL;
						cdb_free(cdb_bucket);
					}
					else {
						ftc_num_msgs[tok] = 0;
						ftc_msgs[tok] = malloc(sizeof(long));
					}
				}
	
	
				if (op == 1) {	/* add to index */
					++ftc_num_msgs[tok];
					ftc_msgs[tok] = realloc(ftc_msgs[tok],
								ftc_num_msgs[tok]*sizeof(long));
					ftc_msgs[tok][ftc_num_msgs[tok] - 1] = msgnum;
				}
	
				if (op == 0) {	/* remove from index */
					if (ftc_num_msgs[tok] >= 1) {
						for (j=0; j<ftc_num_msgs[tok]; ++j) {
							if (ftc_msgs[tok][j] == msgnum) {
								memmove(&ftc_msgs[tok][j], &ftc_msgs[tok][j+1], ((ftc_num_msgs[tok] - j - 1)*sizeof(long)));
								--ftc_num_msgs[tok];
								--j;
							}
						}
					}
				}
			}
			else {
				syslog(LOG_ALERT, "Invalid token %d !!", tok);
			}
		}

		free(tokens);
	}
}
コード例 #29
0
ファイル: serv_smtpqueue.c プロジェクト: mingodad/citadel
int smtp_aftersave(struct CtdlMessage *msg,
		   recptypes *recps)
{
	/* For internet mail, generate delivery instructions.
	 * Yes, this is recursive.  Deal with it.  Infinite recursion does
	 * not happen because the delivery instructions message does not
	 * contain a recipient.
	 */
	if ((recps != NULL) && (recps->num_internet > 0)) {
		struct CtdlMessage *imsg = NULL;
		char recipient[SIZ];
		CitContext *CCC = MyContext();
		StrBuf *SpoolMsg = NewStrBuf();
		long nTokens;
		int i;

		MSGM_syslog(LOG_DEBUG, "Generating delivery instructions\n");

		StrBufPrintf(SpoolMsg,
			     "Content-type: "SPOOLMIME"\n"
			     "\n"
			     "msgid|%s\n"
			     "submitted|%ld\n"
			     "bounceto|%s\n",
			     msg->cm_fields[eVltMsgNum],
			     (long)time(NULL),
			     recps->bounce_to);

		if (recps->envelope_from != NULL) {
			StrBufAppendBufPlain(SpoolMsg, HKEY("envelope_from|"), 0);
			StrBufAppendBufPlain(SpoolMsg, recps->envelope_from, -1, 0);
			StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0);
		}
		if (recps->sending_room != NULL) {
			StrBufAppendBufPlain(SpoolMsg, HKEY("source_room|"), 0);
			StrBufAppendBufPlain(SpoolMsg, recps->sending_room, -1, 0);
			StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0);
		}

		nTokens = num_tokens(recps->recp_internet, '|');
	  	for (i = 0; i < nTokens; i++) {
			long len;
			len = extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient);
			if (len > 0) {
				StrBufAppendBufPlain(SpoolMsg, HKEY("remote|"), 0);
				StrBufAppendBufPlain(SpoolMsg, recipient, len, 0);
				StrBufAppendBufPlain(SpoolMsg, HKEY("|0||\n"), 0);
			}
		}

		imsg = malloc(sizeof(struct CtdlMessage));
		memset(imsg, 0, sizeof(struct CtdlMessage));
		imsg->cm_magic = CTDLMESSAGE_MAGIC;
		imsg->cm_anon_type = MES_NORMAL;
		imsg->cm_format_type = FMT_RFC822;
		CM_SetField(imsg, eMsgSubject, HKEY("QMSG"));
		CM_SetField(imsg, eAuthor, HKEY("Citadel"));
		CM_SetField(imsg, eJournal, HKEY("do not journal"));
		CM_SetAsFieldSB(imsg, eMesageText, &SpoolMsg);
		CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR);
		CM_Free(imsg);
	}
	return 0;
}
コード例 #30
0
/******************************************************************************
 * So, we're finished with sending (regardless of success or failure)         *
 * This Message might be referenced by several Queue-Items, if we're the last,*
 * we need to free the memory and send bounce messages (on terminal failure)  *
 * else we just free our SMTP-Message struct.                                 *
 ******************************************************************************/
eNextState FinalizeMessageSend_DB(AsyncIO *IO)
{
	const char *Status;
	SmtpOutMsg *Msg = IO->Data;
	StrBuf *StatusMessage;

	if (Msg->MyQEntry->AllStatusMessages != NULL)
		StatusMessage = Msg->MyQEntry->AllStatusMessages;
	else
		StatusMessage = Msg->MyQEntry->StatusMessage;


	if (Msg->MyQEntry->Status == 2) {
		SetSMTPState(IO, eSTMPfinished);
		Status = "Delivery successful.";
	}
	else if (Msg->MyQEntry->Status == 5) {
		SetSMTPState(IO, eSMTPFailTotal);
		Status = "Delivery failed permanently; giving up.";
	}
	else {
		SetSMTPState(IO, eSMTPFailTemporary);
		Status = "Delivery failed temporarily; will retry later.";
	}
			
	EVS_syslog(LOG_INFO,
		   "%s Time[%fs] Recipient <%s> @ <%s> (%s) Status message: %s\n",
		   Status,
		   Msg->IO.Now - Msg->IO.StartIO,
		   Msg->user,
		   Msg->node,
		   Msg->name,
		   ChrPtr(StatusMessage));


	Msg->IDestructQueItem = DecreaseQReference(Msg->MyQItem);

	Msg->nRemain = CountActiveQueueEntries(Msg->MyQItem, 0);

	if (Msg->MyQEntry->Active && 
	    !Msg->MyQEntry->StillActive &&
	    CheckQEntryIsBounce(Msg->MyQEntry))
	{
		/* are we casue for a bounce mail? */
		Msg->MyQItem->SendBounceMail |= (1<<Msg->MyQEntry->Status);
	}

	if ((Msg->nRemain > 0) || Msg->IDestructQueItem)
		Msg->QMsgData = SerializeQueueItem(Msg->MyQItem);
	else
		Msg->QMsgData = NULL;

	/*
	 * Uncompleted delivery instructions remain, so delete the old
	 * instructions and replace with the updated ones.
	 */
	EVS_syslog(LOG_DEBUG, "%ld", Msg->MyQItem->QueMsgID);
	CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, &Msg->MyQItem->QueMsgID, 1, "");
	Msg->MyQItem->QueMsgID = -1;

	if (Msg->IDestructQueItem)
		smtpq_do_bounce(Msg->MyQItem, Msg->msgtext, Msg->pCurrRelay);

	if (Msg->nRemain > 0)
	{
		struct CtdlMessage *msg;
		msg = malloc(sizeof(struct CtdlMessage));
		memset(msg, 0, sizeof(struct CtdlMessage));
		msg->cm_magic = CTDLMESSAGE_MAGIC;
		msg->cm_anon_type = MES_NORMAL;
		msg->cm_format_type = FMT_RFC822;
		CM_SetAsFieldSB(msg, eMesageText, &Msg->QMsgData);
		CM_SetField(msg, eMsgSubject, HKEY("QMSG"));
		Msg->MyQItem->QueMsgID =
			CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR);
		EVS_syslog(LOG_DEBUG, "%ld", Msg->MyQItem->QueMsgID);
		CM_Free(msg);
	}
	else {
		CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM,
				   &Msg->MyQItem->MessageID,
				   1,
				   "");
		FreeStrBuf(&Msg->QMsgData);
	}

	RemoveContext(Msg->IO.CitContext);
	return eAbort;
}