<commit_before>/*
 *  Off-the-Record Messaging library
 *  Copyright (C) 2004-2012  <NAME>, <NAME>, <NAME>,
 *  			      <NAME>, <NAME>, <NAME>
 *                           <<EMAIL>>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of version 2.1 of the GNU Lesser General
 *  Public License as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/* system headers */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* libgcrypt headers */
#include <gcrypt.h>

/* libotr headers */
#include "privkey.h"
#include "userstate.h"
#include "proto.h"
#include "auth.h"
#include "message.h"
#include "sm.h"
#include "instag.h"

#if OTRL_DEBUGGING
#include <stdio.h>

/* If OTRL_DEBUGGING is on, and the user types this string, the current
 * context and its siblings will be dumped to stderr. */
const char *OTRL_DEBUGGING_DEBUGSTR = "?OTR!";

void otrl_context_all_dump(FILE *f, OtrlUserState us);
void otrl_context_siblings_dump(FILE *f, const ConnContext *context);
#endif

/* The API version */
extern unsigned int otrl_api_version;

/* How long after sending a packet should we wait to send a heartbeat? */
#define HEARTBEAT_INTERVAL 60

/* How old are messages allowed to be in order to be candidates for
 * resending in response to a rekey? */
#define RESEND_INTERVAL 60

/* How long should we wait for the last of the logged-in instances of
 * our buddy to respond before marking our private key as a candidate
 * for wiping (in seconds)? */
#define MAX_AKE_WAIT_TIME 60

/* How frequently should we check our ConnContexts for wipeable private
 * keys (and wipe them) (in seconds)? */
#define POLL_DEFAULT_INTERVAL 70

/* Send a message to the network, fragmenting first if necessary.
 * All messages to be sent to the network should go through this
 * method immediately before they are sent, ie after encryption. */
static gcry_error_t fragment_and_send(const OtrlMessageAppOps *ops,
	void *opdata, ConnContext *context, const char *message,
	OtrlFragmentPolicy fragPolicy, char **returnFragment)
{
    int mms = 0;

    if (message && ops->inject_message) {
	int msglen;

	if (ops->max_message_size) {
	    mms = ops->max_message_size(opdata, context);
	}
	msglen = strlen(message);

	/* Don't incur overhead of fragmentation unless necessary */
	if(mms != 0 && msglen > mms) {
	    char **fragments;
	    gcry_error_t err;
	    int i;
	    int headerlen = context->protocol_version == 3 ? 37 : 19;
	    /* Like ceil(msglen/(mms - headerlen)) */
	    int fragment_count = ((msglen - 1) / (mms - headerlen)) + 1;

	    err = otrl_proto_fragment_create(mms, fragment_count, &fragments,
		    context, message);
	    if (err) {
		return err;
	    }

	    /* Determine which fragments to send and which to return
	     * based on given Fragment Policy.  If the first fragment
	     * should be returned instead of sent, store it. */
	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_FIRST) {
		*returnFragment = strdup(fragments[0]);
	    } else {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username, fragments[0]);
	    }
	    for (i=1; i<fragment_count-1; i++) {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username, fragments[i]);
	    }
	    /* If the last fragment should be stored instead of sent,
	     * store it */
	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_LAST) {
		*returnFragment = strdup(fragments[fragment_count-1]);
	    } else {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username,
			fragments[fragment_count-1]);
	    }
	    /* Now free all fragment memory */
	    otrl_proto_fragment_free(&fragments, fragment_count);

	} else {
	    /* No fragmentation necessary */
	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL) {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username, message);
	    } else {
		/* Copy and return the entire given message. */
		*returnFragment = strdup(message);
	    }
	}
    }

    return gcry_error(GPG_ERR_NO_ERROR);
}

static void populate_context_instag(OtrlUserState us, const OtrlMessageAppOps
	*ops, void *opdata, const char *accountname, const char *protocol,
	ConnContext *context) {
    OtrlInsTag *p_instag;

    p_instag = otrl_instag_find(us, accountname, protocol);
    if ((!p_instag) && ops->create_instag) {
	ops->create_instag(opdata, accountname, protocol);
	p_instag = otrl_instag_find(us, accountname, protocol);
    }

    if (p_instag && p_instag->instag >= OTRL_MIN_VALID_INSTAG) {
	context->our_instance = p_instag->instag;
    } else {
	context->our_instance = otrl_instag_get_new();
    }
}

/* Deallocate a message allocated by other otrl_message_* routines. */
void otrl_message_free(char *message)
{
    free(message);
}

/* Handle a message about to be sent to the network.  It is safe to pass
 * all messages about to be sent to this routine.  add_appdata is a
 * function that will be called in the event that a new ConnContext is
 * created.  It will be passed the data that you supplied, as well as a
 * pointer to the new ConnContext.  You can use this to add
 * application-specific information to the ConnContext using the
 * "context->app" field, for example.  If you don't need to do this, you
 * can pass NULL for the last two arguments of otrl_message_sending.
 *
 * tlvs is a chain of OtrlTLVs to append to the private message.  It is
 * usually correct to just pass NULL here.
 *
 * If non-NULL, ops->convert_msg will be called just before encrypting a
 * message.
 *
 * "instag" specifies the instance tag of the buddy (protocol version 3 only).
 * Meta-instances may also be specified (e.g., OTRL_INSTAG_MOST_SECURE).
 * If "contextp" is not NULL, it will be set to the ConnContext used for
 * sending the message.
 *
 * If no fragmentation or msg injection is wanted, use OTRL_FRAGMENT_SEND_SKIP
 * as the OtrlFragmentPolicy. In this case, this function will assign *messagep
 * with the encrypted msg. If the routine returns non-zero, then the library
 * tried to encrypt the message, but for some reason failed. DO NOT send the
 * message in the clear in that case. If *messagep gets set by the call to
 * something non-NULL, then you should replace your message with the contents
 * of *messagep, and send that instead.
 *
 * Other fragmentation policies are OTRL_FRAGMENT_SEND_ALL,
 * OTRL_FRAGMENT_SEND_ALL_BUT_LAST, or OTRL_FRAGMENT_SEND_ALL_BUT_FIRST. In
 * these cases, the appropriate fragments will be automatically sent. For the
 * last two policies, the remaining fragment will be passed in *original_msg.
 *
 * Call otrl_message_free(*messagep) if you don't need *messagep or when you're
 * done with it. */
gcry_error_t otrl_message_sending(OtrlUserState us,
	const OtrlMessageAppOps *ops,
	void *opdata, const char *accountname, const char *protocol,
	const char *recipient, otrl_instag_t their_instag,
	const char *original_msg, OtrlTLV *tlvs, char **messagep,
	OtrlFragmentPolicy fragPolicy, ConnContext **contextp,
	void (*add_appdata)(void *data, ConnContext *context),
	void *data)
{
    ConnContext * context = NULL;
    char * msgtosend;
    const char * err_msg;
    gcry_error_t err_code, err;
    OtrlPolicy policy = OTRL_POLICY_DEFAULT;
    int context_added = 0;
    int convert_called = 0;
    char *converted_msg = NULL;

    if (messagep) {
	*messagep = NULL;
    }

    err = gcry_error(GPG_ERR_NO_ERROR);	/* Default to no error */

    if (contextp) {
	*contextp = NULL;
    }

    if (!accountname || !protocol || !recipient ||
		!original_msg || !messagep) {
	err = gcry_error(GPG_ERR_INV_VALUE);
	goto fragment;
    }

    /* See if we have a fingerprint for this user */
    context = otrl_context_find(us, recipient, accountname, protocol,
	    their_instag, 1, &context_added, add_appdata, data);

    /* Update the context list if we added one */
    if (context_added && ops->update_context_list) {
	ops->update_context_list(opdata);
    }

    /* Find or generate the instance tag if needed */
    if (!context->our_instance) {
	populate_context_instag(us, ops, opdata, accountname, protocol,
	    context);
    }

    if (contextp) {
	*contextp = context;
    }

    /* Check the policy */
    if (ops->policy) {
	policy = ops->policy(opdata, context);
    }

    /* Should we go on at all? */
    if ((policy & OTRL_POLICY_VERSION_MASK) == 0) {
	err =  gcry_error(GPG_ERR_NO_ERROR);
	goto fragment;
    }

#if OTRL_DEBUGGING
    /* If the user typed the magic debug string, dump this context and
     * its siblings. */
    {
	const char *debugtag = strstr(original_msg, OTRL_DEBUGGING_DEBUGSTR);

	if (debugtag) {
	    const char *debugargs =
		debugtag + strlen(OTRL_DEBUGGING_DEBUGSTR);
	    if (debugargs[0] == '!') { /* typed ?OTR!! */
		otrl_context_all_dump(stderr, us);
	    } else { /* typed ?OTR! without extra command chars */
		otrl_context_siblings_dump(stderr, context);
	    }

	    /* Don't actually send the message */
	    *messagep = strdup("");
	    if (!(*messagep)) {
		err = gcry_error(GPG_ERR_ENOMEM);
	    }
	    goto fragment;
	}
    }
#endif

    /* If this is an OTR Query message, don't encrypt it. */
    if (otrl_proto_message_type(original_msg) == OTRL_MSGTYPE_QUERY) {
	/* Replace the "?OTR?" with a custom message */
	char *bettermsg = otrl_proto_default_query_msg(accountname, policy);
	if (bettermsg) {
	    *messagep = bettermsg;
	}
	context->otr_offer = OFFER_SENT;
	err = gcry_error(GPG_ERR_NO_ERROR);
	goto fragment;
    }

    /* What is the current message disposition? */
    switch(context->msgstate) {

	case OTRL_MSGSTATE_PLAINTEXT:
	    if ((policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) {
		/* We're trying to send an unencrypted message with a policy
		 * that disallows that.  Don't do that, but try to start
		 * up OTR instead. */
		if (ops->handle_msg_event) {
		    ops->handle_msg_event(opdata,
			    OTRL_MSGEVENT_ENCRYPTION_REQUIRED,
			    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
		}

		context->context_priv->lastmessage =
			gcry_malloc_secure(strlen(original_msg) + 1);
		if (context->context_priv->lastmessage) {
		    char *bettermsg = otrl_proto_default_query_msg(accountname,
			    policy);
		    strcpy(context->context_priv->lastmessage, original_msg);
		    context->context_priv->lastsent = time(NULL);
		    otrl_context_update_recent_child(context, 1);
		    context->context_priv->may_retransmit = 2;
		    if (bettermsg) {
			*messagep = bettermsg;
			context->otr_offer = OFFER_SENT;
		    } else {
			err = gcry_error(GPG_ERR_ENOMEM);
			goto fragment;
		    }
		}
	    } else {
		if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG) &&
			context->otr_offer != OFFER_REJECTED) {
		    /* See if this user can speak OTR.  Append the
		     * OTR_MESSAGE_TAG to the plaintext message, and see
		     * if he responds. */
		    size_t msglen = strlen(original_msg);
		    size_t basetaglen = strlen(OTRL_MESSAGE_TAG_BASE);
		    size_t v1taglen = (policy & OTRL_POLICY_ALLOW_V1) ?
			strlen(OTRL_MESSAGE_TAG_V1) : 0;
		    size_t v2taglen = (policy & OTRL_POLICY_ALLOW_V2) ?
			strlen(OTRL_MESSAGE_TAG_V2) : 0;
		    size_t v3taglen = (policy & OTRL_POLICY_ALLOW_V3) ?
			strlen(OTRL_MESSAGE_TAG_V3) : 0;
		    char *taggedmsg = malloc(msglen + basetaglen + v1taglen
			    + v2taglen + v3taglen + 1);
		    if (taggedmsg) {
			strcpy(taggedmsg, original_msg);
			strcpy(taggedmsg + msglen, OTRL_MESSAGE_TAG_BASE);
			if (v1taglen) {
			    strcpy(taggedmsg + msglen + basetaglen,
				    OTRL_MESSAGE_TAG_V1);
			}
			if (v2taglen) {
			    strcpy(taggedmsg + msglen + basetaglen + v1taglen,
				    OTRL_MESSAGE_TAG_V2);
			}
			if (v3taglen) {
			    strcpy(taggedmsg + msglen + basetaglen + v1taglen
				    + v2taglen, OTRL_MESSAGE_TAG_V3);
			}
			*messagep = taggedmsg;
			context->otr_offer = OFFER_SENT;
		    }
		}
	    }
	    break;
	case OTRL_MSGSTATE_ENCRYPTED:
	    /* convert the original message if necessary */
	    if (ops->convert_msg) {
		ops->convert_msg(opdata, context, OTRL_CONVERT_SENDING,
			&converted_msg, original_msg);

		if (converted_msg) {
		    convert_called = 1;
		}
	    }

	    /* Create the new, encrypted message */
	    if (convert_called) {
		err_code = otrl_proto_create_data(&msgtosend, context,
			converted_msg, tlvs, 0, NULL);

		if (ops->convert_free) {
		    ops->convert_free(opdata, context, converted_msg);
		    converted_msg = NULL;
		}
	    } else {
		err_code = otrl_proto_create_data(&msgtosend, context,
			original_msg, tlvs, 0, NULL);
	    }
	    if (!err_code) {
		context->context_priv->lastsent = time(NULL);
		otrl_context_update_recent_child(context, 1);
		*messagep = msgtosend;
	    } else {
		/* Uh, oh.  Whatever we do, *don't* send the message in the
		 * clear. */
		if (ops->handle_msg_event) {
		    ops->handle_msg_event(opdata,
			    OTRL_MSGEVENT_ENCRYPTION_ERROR,
			    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
		}
		if (ops->otr_error_message) {
		    err_msg = ops->otr_error_message(opdata, context,
			OTRL_ERRCODE_ENCRYPTION_ERROR);
		    *messagep = malloc(strlen(OTR_ERROR_PREFIX) +
			strlen(err_msg) + 1);
		    if (*messagep) {
			strcpy(*messagep, OTR_ERROR_PREFIX);
			strcat(*messagep, err_msg);
		    }
		    if (ops->otr_error_message_free) {
			ops->otr_error_message_free(opdata, err_msg);
		    }
		    if (!(*messagep)) {
			err = gcry_error(GPG_ERR_ENOMEM);
			goto fragment;
		    }
		}
	    }
	    break;
	case OTRL_MSGSTATE_FINISHED:
	    if (ops->handle_msg_event) {
		ops->handle_msg_event(opdata, OTRL_MSGEVENT_CONNECTION_ENDED,
		    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
	    }
	    *messagep = strdup("");
	    if (!(*messagep)) {
		err = gcry_error(GPG_ERR_ENOMEM);
		goto fragment;
	    }
	    break;
    }

fragment:
    if (fragPolicy == OTRL_FRAGMENT_SEND_SKIP ) {
	/* Do not fragment/inject. Default behaviour of libotr3.2.0 */
	return err;
    } else {
	/* Fragment and send according to policy */
	if (!err && messagep && *messagep) {
	    if (context) {
		err = fragment_and_send(ops, NULL, context, *messagep,<commit_msg>Fix: pass opdata when sending message fragment<commit_after>/*
 *  Off-the-Record Messaging library
 *  Copyright (C) 2004-2012  <NAME>, <NAME>, <NAME>,
 *  			      <NAME>, <NAME>, <NAME>
 *                           <<EMAIL>>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of version 2.1 of the GNU Lesser General
 *  Public License as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/* system headers */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* libgcrypt headers */
#include <gcrypt.h>

/* libotr headers */
#include "privkey.h"
#include "userstate.h"
#include "proto.h"
#include "auth.h"
#include "message.h"
#include "sm.h"
#include "instag.h"

#if OTRL_DEBUGGING
#include <stdio.h>

/* If OTRL_DEBUGGING is on, and the user types this string, the current
 * context and its siblings will be dumped to stderr. */
const char *OTRL_DEBUGGING_DEBUGSTR = "?OTR!";

void otrl_context_all_dump(FILE *f, OtrlUserState us);
void otrl_context_siblings_dump(FILE *f, const ConnContext *context);
#endif

/* The API version */
extern unsigned int otrl_api_version;

/* How long after sending a packet should we wait to send a heartbeat? */
#define HEARTBEAT_INTERVAL 60

/* How old are messages allowed to be in order to be candidates for
 * resending in response to a rekey? */
#define RESEND_INTERVAL 60

/* How long should we wait for the last of the logged-in instances of
 * our buddy to respond before marking our private key as a candidate
 * for wiping (in seconds)? */
#define MAX_AKE_WAIT_TIME 60

/* How frequently should we check our ConnContexts for wipeable private
 * keys (and wipe them) (in seconds)? */
#define POLL_DEFAULT_INTERVAL 70

/* Send a message to the network, fragmenting first if necessary.
 * All messages to be sent to the network should go through this
 * method immediately before they are sent, ie after encryption. */
static gcry_error_t fragment_and_send(const OtrlMessageAppOps *ops,
	void *opdata, ConnContext *context, const char *message,
	OtrlFragmentPolicy fragPolicy, char **returnFragment)
{
    int mms = 0;

    if (message && ops->inject_message) {
	int msglen;

	if (ops->max_message_size) {
	    mms = ops->max_message_size(opdata, context);
	}
	msglen = strlen(message);

	/* Don't incur overhead of fragmentation unless necessary */
	if(mms != 0 && msglen > mms) {
	    char **fragments;
	    gcry_error_t err;
	    int i;
	    int headerlen = context->protocol_version == 3 ? 37 : 19;
	    /* Like ceil(msglen/(mms - headerlen)) */
	    int fragment_count = ((msglen - 1) / (mms - headerlen)) + 1;

	    err = otrl_proto_fragment_create(mms, fragment_count, &fragments,
		    context, message);
	    if (err) {
		return err;
	    }

	    /* Determine which fragments to send and which to return
	     * based on given Fragment Policy.  If the first fragment
	     * should be returned instead of sent, store it. */
	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_FIRST) {
		*returnFragment = strdup(fragments[0]);
	    } else {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username, fragments[0]);
	    }
	    for (i=1; i<fragment_count-1; i++) {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username, fragments[i]);
	    }
	    /* If the last fragment should be stored instead of sent,
	     * store it */
	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_LAST) {
		*returnFragment = strdup(fragments[fragment_count-1]);
	    } else {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username,
			fragments[fragment_count-1]);
	    }
	    /* Now free all fragment memory */
	    otrl_proto_fragment_free(&fragments, fragment_count);

	} else {
	    /* No fragmentation necessary */
	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL) {
		ops->inject_message(opdata, context->accountname,
			context->protocol, context->username, message);
	    } else {
		/* Copy and return the entire given message. */
		*returnFragment = strdup(message);
	    }
	}
    }

    return gcry_error(GPG_ERR_NO_ERROR);
}

static void populate_context_instag(OtrlUserState us, const OtrlMessageAppOps
	*ops, void *opdata, const char *accountname, const char *protocol,
	ConnContext *context) {
    OtrlInsTag *p_instag;

    p_instag = otrl_instag_find(us, accountname, protocol);
    if ((!p_instag) && ops->create_instag) {
	ops->create_instag(opdata, accountname, protocol);
	p_instag = otrl_instag_find(us, accountname, protocol);
    }

    if (p_instag && p_instag->instag >= OTRL_MIN_VALID_INSTAG) {
	context->our_instance = p_instag->instag;
    } else {
	context->our_instance = otrl_instag_get_new();
    }
}

/* Deallocate a message allocated by other otrl_message_* routines. */
void otrl_message_free(char *message)
{
    free(message);
}

/* Handle a message about to be sent to the network.  It is safe to pass
 * all messages about to be sent to this routine.  add_appdata is a
 * function that will be called in the event that a new ConnContext is
 * created.  It will be passed the data that you supplied, as well as a
 * pointer to the new ConnContext.  You can use this to add
 * application-specific information to the ConnContext using the
 * "context->app" field, for example.  If you don't need to do this, you
 * can pass NULL for the last two arguments of otrl_message_sending.
 *
 * tlvs is a chain of OtrlTLVs to append to the private message.  It is
 * usually correct to just pass NULL here.
 *
 * If non-NULL, ops->convert_msg will be called just before encrypting a
 * message.
 *
 * "instag" specifies the instance tag of the buddy (protocol version 3 only).
 * Meta-instances may also be specified (e.g., OTRL_INSTAG_MOST_SECURE).
 * If "contextp" is not NULL, it will be set to the ConnContext used for
 * sending the message.
 *
 * If no fragmentation or msg injection is wanted, use OTRL_FRAGMENT_SEND_SKIP
 * as the OtrlFragmentPolicy. In this case, this function will assign *messagep
 * with the encrypted msg. If the routine returns non-zero, then the library
 * tried to encrypt the message, but for some reason failed. DO NOT send the
 * message in the clear in that case. If *messagep gets set by the call to
 * something non-NULL, then you should replace your message with the contents
 * of *messagep, and send that instead.
 *
 * Other fragmentation policies are OTRL_FRAGMENT_SEND_ALL,
 * OTRL_FRAGMENT_SEND_ALL_BUT_LAST, or OTRL_FRAGMENT_SEND_ALL_BUT_FIRST. In
 * these cases, the appropriate fragments will be automatically sent. For the
 * last two policies, the remaining fragment will be passed in *original_msg.
 *
 * Call otrl_message_free(*messagep) if you don't need *messagep or when you're
 * done with it. */
gcry_error_t otrl_message_sending(OtrlUserState us,
	const OtrlMessageAppOps *ops,
	void *opdata, const char *accountname, const char *protocol,
	const char *recipient, otrl_instag_t their_instag,
	const char *original_msg, OtrlTLV *tlvs, char **messagep,
	OtrlFragmentPolicy fragPolicy, ConnContext **contextp,
	void (*add_appdata)(void *data, ConnContext *context),
	void *data)
{
    ConnContext * context = NULL;
    char * msgtosend;
    const char * err_msg;
    gcry_error_t err_code, err;
    OtrlPolicy policy = OTRL_POLICY_DEFAULT;
    int context_added = 0;
    int convert_called = 0;
    char *converted_msg = NULL;

    if (messagep) {
	*messagep = NULL;
    }

    err = gcry_error(GPG_ERR_NO_ERROR);	/* Default to no error */

    if (contextp) {
	*contextp = NULL;
    }

    if (!accountname || !protocol || !recipient ||
		!original_msg || !messagep) {
	err = gcry_error(GPG_ERR_INV_VALUE);
	goto fragment;
    }

    /* See if we have a fingerprint for this user */
    context = otrl_context_find(us, recipient, accountname, protocol,
	    their_instag, 1, &context_added, add_appdata, data);

    /* Update the context list if we added one */
    if (context_added && ops->update_context_list) {
	ops->update_context_list(opdata);
    }

    /* Find or generate the instance tag if needed */
    if (!context->our_instance) {
	populate_context_instag(us, ops, opdata, accountname, protocol,
	    context);
    }

    if (contextp) {
	*contextp = context;
    }

    /* Check the policy */
    if (ops->policy) {
	policy = ops->policy(opdata, context);
    }

    /* Should we go on at all? */
    if ((policy & OTRL_POLICY_VERSION_MASK) == 0) {
	err =  gcry_error(GPG_ERR_NO_ERROR);
	goto fragment;
    }

#if OTRL_DEBUGGING
    /* If the user typed the magic debug string, dump this context and
     * its siblings. */
    {
	const char *debugtag = strstr(original_msg, OTRL_DEBUGGING_DEBUGSTR);

	if (debugtag) {
	    const char *debugargs =
		debugtag + strlen(OTRL_DEBUGGING_DEBUGSTR);
	    if (debugargs[0] == '!') { /* typed ?OTR!! */
		otrl_context_all_dump(stderr, us);
	    } else { /* typed ?OTR! without extra command chars */
		otrl_context_siblings_dump(stderr, context);
	    }

	    /* Don't actually send the message */
	    *messagep = strdup("");
	    if (!(*messagep)) {
		err = gcry_error(GPG_ERR_ENOMEM);
	    }
	    goto fragment;
	}
    }
#endif

    /* If this is an OTR Query message, don't encrypt it. */
    if (otrl_proto_message_type(original_msg) == OTRL_MSGTYPE_QUERY) {
	/* Replace the "?OTR?" with a custom message */
	char *bettermsg = otrl_proto_default_query_msg(accountname, policy);
	if (bettermsg) {
	    *messagep = bettermsg;
	}
	context->otr_offer = OFFER_SENT;
	err = gcry_error(GPG_ERR_NO_ERROR);
	goto fragment;
    }

    /* What is the current message disposition? */
    switch(context->msgstate) {

	case OTRL_MSGSTATE_PLAINTEXT:
	    if ((policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) {
		/* We're trying to send an unencrypted message with a policy
		 * that disallows that.  Don't do that, but try to start
		 * up OTR instead. */
		if (ops->handle_msg_event) {
		    ops->handle_msg_event(opdata,
			    OTRL_MSGEVENT_ENCRYPTION_REQUIRED,
			    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
		}

		context->context_priv->lastmessage =
			gcry_malloc_secure(strlen(original_msg) + 1);
		if (context->context_priv->lastmessage) {
		    char *bettermsg = otrl_proto_default_query_msg(accountname,
			    policy);
		    strcpy(context->context_priv->lastmessage, original_msg);
		    context->context_priv->lastsent = time(NULL);
		    otrl_context_update_recent_child(context, 1);
		    context->context_priv->may_retransmit = 2;
		    if (bettermsg) {
			*messagep = bettermsg;
			context->otr_offer = OFFER_SENT;
		    } else {
			err = gcry_error(GPG_ERR_ENOMEM);
			goto fragment;
		    }
		}
	    } else {
		if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG) &&
			context->otr_offer != OFFER_REJECTED) {
		    /* See if this user can speak OTR.  Append the
		     * OTR_MESSAGE_TAG to the plaintext message, and see
		     * if he responds. */
		    size_t msglen = strlen(original_msg);
		    size_t basetaglen = strlen(OTRL_MESSAGE_TAG_BASE);
		    size_t v1taglen = (policy & OTRL_POLICY_ALLOW_V1) ?
			strlen(OTRL_MESSAGE_TAG_V1) : 0;
		    size_t v2taglen = (policy & OTRL_POLICY_ALLOW_V2) ?
			strlen(OTRL_MESSAGE_TAG_V2) : 0;
		    size_t v3taglen = (policy & OTRL_POLICY_ALLOW_V3) ?
			strlen(OTRL_MESSAGE_TAG_V3) : 0;
		    char *taggedmsg = malloc(msglen + basetaglen + v1taglen
			    + v2taglen + v3taglen + 1);
		    if (taggedmsg) {
			strcpy(taggedmsg, original_msg);
			strcpy(taggedmsg + msglen, OTRL_MESSAGE_TAG_BASE);
			if (v1taglen) {
			    strcpy(taggedmsg + msglen + basetaglen,
				    OTRL_MESSAGE_TAG_V1);
			}
			if (v2taglen) {
			    strcpy(taggedmsg + msglen + basetaglen + v1taglen,
				    OTRL_MESSAGE_TAG_V2);
			}
			if (v3taglen) {
			    strcpy(taggedmsg + msglen + basetaglen + v1taglen
				    + v2taglen, OTRL_MESSAGE_TAG_V3);
			}
			*messagep = taggedmsg;
			context->otr_offer = OFFER_SENT;
		    }
		}
	    }
	    break;
	case OTRL_MSGSTATE_ENCRYPTED:
	    /* convert the original message if necessary */
	    if (ops->convert_msg) {
		ops->convert_msg(opdata, context, OTRL_CONVERT_SENDING,
			&converted_msg, original_msg);

		if (converted_msg) {
		    convert_called = 1;
		}
	    }

	    /* Create the new, encrypted message */
	    if (convert_called) {
		err_code = otrl_proto_create_data(&msgtosend, context,
			converted_msg, tlvs, 0, NULL);

		if (ops->convert_free) {
		    ops->convert_free(opdata, context, converted_msg);
		    converted_msg = NULL;
		}
	    } else {
		err_code = otrl_proto_create_data(&msgtosend, context,
			original_msg, tlvs, 0, NULL);
	    }
	    if (!err_code) {
		context->context_priv->lastsent = time(NULL);
		otrl_context_update_recent_child(context, 1);
		*messagep = msgtosend;
	    } else {
		/* Uh, oh.  Whatever we do, *don't* send the message in the
		 * clear. */
		if (ops->handle_msg_event) {
		    ops->handle_msg_event(opdata,
			    OTRL_MSGEVENT_ENCRYPTION_ERROR,
			    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
		}
		if (ops->otr_error_message) {
		    err_msg = ops->otr_error_message(opdata, context,
			OTRL_ERRCODE_ENCRYPTION_ERROR);
		    *messagep = malloc(strlen(OTR_ERROR_PREFIX) +
			strlen(err_msg) + 1);
		    if (*messagep) {
			strcpy(*messagep, OTR_ERROR_PREFIX);
			strcat(*messagep, err_msg);
		    }
		    if (ops->otr_error_message_free) {
			ops->otr_error_message_free(opdata, err_msg);
		    }
		    if (!(*messagep)) {
			err = gcry_error(GPG_ERR_ENOMEM);
			goto fragment;
		    }
		}
	    }
	    break;
	case OTRL_MSGSTATE_FINISHED:
	    if (ops->handle_msg_event) {
		ops->handle_msg_event(opdata, OTRL_MSGEVENT_CONNECTION_ENDED,
		    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
	    }
	    *messagep = strdup("");
	    if (!(*messagep)) {
		err = gcry_error(GPG_ERR_ENOMEM);
		goto fragment;
	    }
	    break;
    }

fragment:
    if (fragPolicy == OTRL_FRAGMENT_SEND_SKIP ) {
	/* Do not fragment/inject. Default behaviour of libotr3.2.0 */
	return err;
    } else {
	/* Fragment and send according to policy */
	if (!err && messagep && *messagep) {
	    if (context) {
		err = fragment_and_send(ops, opdata, context, *messagep,
{'fraction_non_alphanumeric': 0.10259664528521936, 'fraction_numerical': 0.005899907385174767, 'mean_word_length': 3.481783243658724, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 161, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '710084', 'n_tokens_mistral': 10684, 'n_tokens_neox': 9761, 'n_words': 2783}