summaryrefslogtreecommitdiff
path: root/plugins/MirOTR/libotr/src/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/MirOTR/libotr/src/context.c')
-rw-r--r--plugins/MirOTR/libotr/src/context.c609
1 files changed, 413 insertions, 196 deletions
diff --git a/plugins/MirOTR/libotr/src/context.c b/plugins/MirOTR/libotr/src/context.c
index d0d912f76a..44d8b860f7 100644
--- a/plugins/MirOTR/libotr/src/context.c
+++ b/plugins/MirOTR/libotr/src/context.c
@@ -1,6 +1,8 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov
+ * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits,
+ * Chris Alexander, Willy Lew, Lisa Du,
+ * Nikita Borisov
* <otr@cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -14,7 +16,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* system headers */
@@ -26,117 +28,339 @@
/* libotr headers */
#include "context.h"
+#include "instag.h"
+
+#if OTRL_DEBUGGING
+#include <stdio.h>
+
+void otrl_auth_dump(FILE *f, const OtrlAuthInfo *auth);
+void otrl_sm_dump(FILE *f, const OtrlSMState *sm);
+
+/* Dump the contents of a context to the FILE *f. */
+void otrl_context_dump(FILE *f, const ConnContext *context)
+{
+ const Fingerprint *fing;
+
+ fprintf(f, "Context %p:\n\n", context);
+
+ fprintf(f, " Username: %s\n", context->username);
+ fprintf(f, " Accountname: %s\n", context->accountname);
+ fprintf(f, " Protocol: %s\n\n", context->protocol);
+ fprintf(f, " Master context: %p%s\n", context->m_context,
+ context->m_context == context ? " IS MASTER" : "");
+ fprintf(f, " Recent recv child: %p\n", context->recent_rcvd_child);
+ fprintf(f, " Recent sent child: %p\n", context->recent_sent_child);
+ fprintf(f, " Recent child: %p\n\n", context->recent_child);
+ fprintf(f, " Our instance: %08x\n", context->our_instance);
+ fprintf(f, " Their instance: %08x\n\n", context->their_instance);
+ fprintf(f, " Msgstate: %d (%s)\n\n", context->msgstate,
+ context->msgstate == OTRL_MSGSTATE_PLAINTEXT ? "PLAINTEXT" :
+ context->msgstate == OTRL_MSGSTATE_ENCRYPTED ? "ENCRYPTED" :
+ context->msgstate == OTRL_MSGSTATE_FINISHED ? "FINISHED" :
+ "INVALID");
+ otrl_auth_dump(f, &context->auth);
+ fprintf(f, "\n Fingerprints:\n");
+ for (fing = context->fingerprint_root.next; fing; fing = fing->next) {
+ fprintf(f, " %p ", fing);
+ if (fing->fingerprint == NULL) {
+ fprintf(f, "(null)");
+ } else {
+ int i;
+ for (i=0;i<20;++i) {
+ fprintf(f, "%02x", fing->fingerprint[i]);
+ }
+ }
+ fprintf(f, " %p", fing->context);
+ if (fing->trust && fing->trust[0]) {
+ fprintf(f, " %s", fing->trust);
+ }
+ fprintf(f, "\n");
+ }
+ fprintf(f, "\n Active fingerprint: %p\n\n", context->active_fingerprint);
+ fprintf(f, " Protocol version: %d\n", context->protocol_version);
+ fprintf(f, " OTR offer: %d (%s)\n\n", context->otr_offer,
+ context->otr_offer == OFFER_NOT ? "NOT" :
+ context->otr_offer == OFFER_SENT ? "SENT" :
+ context->otr_offer == OFFER_REJECTED ? "REJECTED" :
+ context->otr_offer == OFFER_ACCEPTED ? "ACCEPTED" :
+ "INVALID");
+
+ fprintf(f, " Application data: %p\n", context->app_data);
+ if (context->smstate == NULL) {
+ fprintf(f, " SM state: NULL\n");
+ } else {
+ otrl_sm_dump(f, context->smstate);
+ }
+ fprintf(f, "\n");
+}
+
+/* Dump the master context of this context, and all of its children. */
+void otrl_context_siblings_dump(FILE *f, const ConnContext *context)
+{
+ const ConnContext *citer;
+ for (citer = context->m_context;
+ citer && citer->m_context == context->m_context;
+ citer = citer->next) {
+ if (citer == context) {
+ fprintf(f, "*** ");
+ }
+ otrl_context_dump(f, citer);
+ }
+}
+
+/* Dump all contexts. */
+void otrl_context_all_dump(FILE *f, OtrlUserState us)
+{
+ const ConnContext *citer;
+ unsigned int ctxnum = 1;
+ for (citer = us->context_root; citer; citer = citer->next, ++ctxnum) {
+ fprintf(f, "%u. ", ctxnum);
+ otrl_context_dump(f, citer);
+ }
+}
+#endif
/* Create a new connection context. */
static ConnContext * new_context(const char * user, const char * accountname,
const char * protocol)
{
- ConnContext * context;
- OtrlSMState *smstate;
- context = malloc(sizeof(*context));
- assert(context != NULL);
- context->username = _strdup(user);
- context->accountname = _strdup(accountname);
- context->protocol = _strdup(protocol);
- context->fragment = NULL;
- context->fragment_len = 0;
- context->fragment_n = 0;
- context->fragment_k = 0;
- context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
- otrl_auth_new(&(context->auth));
-
- smstate = malloc(sizeof(OtrlSMState));
- assert(smstate != NULL);
- otrl_sm_state_new(smstate);
- context->smstate = smstate;
-
- context->fingerprint_root.fingerprint = NULL;
- context->fingerprint_root.context = context;
- context->fingerprint_root.next = NULL;
- context->fingerprint_root.tous = NULL;
- context->active_fingerprint = NULL;
- context->their_keyid = 0;
- context->their_y = NULL;
- context->their_old_y = NULL;
- context->our_keyid = 0;
- context->our_dh_key.groupid = 0;
- context->our_dh_key.priv = NULL;
- context->our_dh_key.pub = NULL;
- context->our_old_dh_key.groupid = 0;
- context->our_old_dh_key.priv = NULL;
- context->our_old_dh_key.pub = NULL;
- otrl_dh_session_blank(&(context->sesskeys[0][0]));
- otrl_dh_session_blank(&(context->sesskeys[0][1]));
- otrl_dh_session_blank(&(context->sesskeys[1][0]));
- otrl_dh_session_blank(&(context->sesskeys[1][1]));
- memset(context->sessionid, 0, 20);
- context->sessionid_len = 0;
- context->protocol_version = 0;
- context->numsavedkeys = 0;
- context->preshared_secret = NULL;
- context->preshared_secret_len = 0;
- context->saved_mac_keys = NULL;
- context->generation = 0;
- context->lastsent = 0;
- context->lastmessage = NULL;
- context->may_retransmit = 0;
- context->otr_offer = OFFER_NOT;
- context->app_data = NULL;
- context->app_data_free = NULL;
- context->next = NULL;
- return context;
+ ConnContext * context;
+ OtrlSMState *smstate;
+
+ context = malloc(sizeof(ConnContext));
+ assert(context != NULL);
+
+ context->username = strdup(user);
+ context->accountname = strdup(accountname);
+ context->protocol = strdup(protocol);
+
+ context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
+ otrl_auth_new(context);
+
+ smstate = malloc(sizeof(OtrlSMState));
+ assert(smstate != NULL);
+ otrl_sm_state_new(smstate);
+ context->smstate = smstate;
+
+ context->our_instance = 0;
+ context->their_instance = OTRL_INSTAG_MASTER;
+ context->fingerprint_root.fingerprint = NULL;
+ context->fingerprint_root.context = context;
+ context->fingerprint_root.next = NULL;
+ context->fingerprint_root.tous = NULL;
+ context->active_fingerprint = NULL;
+ memset(context->sessionid, 0, 20);
+ context->sessionid_len = 0;
+ context->protocol_version = 0;
+ context->otr_offer = OFFER_NOT;
+ context->app_data = NULL;
+ context->app_data_free = NULL;
+ context->context_priv = otrl_context_priv_new();
+ assert(context->context_priv != NULL);
+ context->next = NULL;
+ context->m_context = context;
+ context->recent_rcvd_child = NULL;
+ context->recent_sent_child = NULL;
+ context->recent_child = NULL;
+
+ return context;
}
-ConnContext * otrl_context_new(const char * user, const char * accountname,
- const char * protocol)
+ConnContext * otrl_context_find_recent_instance(ConnContext * context,
+ otrl_instag_t recent_instag) {
+ ConnContext * m_context;
+
+ if (!context) return NULL;
+
+ m_context = context->m_context;
+
+ if (!m_context) return NULL;
+
+ switch(recent_instag) {
+ case OTRL_INSTAG_RECENT:
+ return m_context->recent_child;
+ case OTRL_INSTAG_RECENT_RECEIVED:
+ return m_context->recent_rcvd_child;
+ case OTRL_INSTAG_RECENT_SENT:
+ return m_context->recent_sent_child;
+ default:
+ return NULL;
+ }
+}
+
+/* Find the instance of this context that has the best security level,
+ and for which we have most recently received a message from. Note that most
+ recent in this case is limited to a one-second resolution. */
+ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context)
{
- return new_context(user, accountname, protocol);
+ ConnContext *curp; /* for iteration */
+ ConnContext *m_context; /* master */
+ ConnContext *cresult = context; /* best so far */
+
+ if (!context) {
+ return cresult;
+ }
+
+ m_context = context->m_context;
+
+ for (curp = m_context; curp && curp->m_context == m_context;
+ curp = curp->next) {
+ int msgstate_improved = 0; /* 0 == same, 1 == improved */
+ int trust_improved = 0; /* (will immediately 'continue' if worse
+ * than) */
+
+ if (cresult->msgstate == curp->msgstate) {
+ msgstate_improved = 0;
+ } else if (curp->msgstate == OTRL_MSGSTATE_ENCRYPTED ||
+ (cresult->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
+ curp->msgstate == OTRL_MSGSTATE_FINISHED)) {
+ msgstate_improved = 1;
+ } else {
+ continue;
+ }
+
+
+ if (otrl_context_is_fingerprint_trusted(cresult->active_fingerprint) ==
+ otrl_context_is_fingerprint_trusted(curp->active_fingerprint)) {
+
+ trust_improved = 0;
+ } else if
+ (otrl_context_is_fingerprint_trusted(curp->active_fingerprint)){
+
+ trust_improved = 1;
+ } else {
+ continue;
+ }
+
+ if (msgstate_improved || trust_improved ||
+ (!msgstate_improved && !trust_improved &&
+ curp->context_priv->lastrecv >=
+ cresult->context_priv->lastrecv)) {
+ cresult = curp;
+ }
+ }
+
+ return cresult;
}
-/* Look up a connection context by name/account/protocol from the given
+/* Look up a connection context by name/account/protocol/instag from the given
* OtrlUserState. If add_if_missing is true, allocate and return a new
* context if one does not currently exist. In that event, call
* add_app_data(data, context) so that app_data and app_data_free can be
- * filled in by the application, and set *addedp to 1. */
+ * filled in by the application, and set *addedp to 1.
+ * In the 'their_instance' field note that you can also specify a 'meta-
+ * instance' value such as OTRL_INSTAG_MASTER, OTRL_INSTAG_RECENT,
+ * OTRL_INSTAG_RECENT_RECEIVED and OTRL_INSTAG_RECENT_SENT. */
ConnContext * otrl_context_find(OtrlUserState us, const char *user,
- const char *accountname, const char *protocol, int add_if_missing,
- int *addedp,
+ const char *accountname, const char *protocol,
+ otrl_instag_t their_instance, int add_if_missing, int *addedp,
void (*add_app_data)(void *data, ConnContext *context), void *data)
{
- ConnContext ** curp;
- int usercmp = 1, acctcmp = 1, protocmp = 1;
- if (addedp) *addedp = 0;
- if (!user || !accountname || !protocol) return NULL;
- for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) {
- if ((usercmp = strcmp((*curp)->username, user)) > 0 ||
+ ConnContext ** curp;
+ int usercmp = 1, acctcmp = 1, protocmp = 1;
+ if (addedp) *addedp = 0;
+ if (!user || !accountname || !protocol) return NULL;
+
+ for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) {
+ if ((usercmp = strcmp((*curp)->username, user)) > 0 ||
(usercmp == 0 &&
- (acctcmp = strcmp((*curp)->accountname, accountname)) > 0) ||
+ (acctcmp = strcmp((*curp)->accountname, accountname)) > 0) ||
(usercmp == 0 && acctcmp == 0 &&
- (protocmp = strcmp((*curp)->protocol, protocol)) >= 0))
- /* We're at the right place in the list. We've either found
- * it, or gone too far. */
- break;
+ (protocmp = strcmp((*curp)->protocol, protocol)) > 0) ||
+ (usercmp == 0 && acctcmp == 0 && protocmp == 0
+ && (their_instance < OTRL_MIN_VALID_INSTAG ||
+ ((*curp)->their_instance >= their_instance))))
+ /* We're at the right place in the list. We've either found
+ * it, or gone too far. */
+ break;
+ }
+
+ if (usercmp == 0 && acctcmp == 0 && protocmp == 0 && *curp &&
+ (their_instance < OTRL_MIN_VALID_INSTAG ||
+ (their_instance == (*curp)->their_instance))) {
+ /* Found one! */
+ if (their_instance >= OTRL_MIN_VALID_INSTAG ||
+ their_instance == OTRL_INSTAG_MASTER) {
+ return *curp;
}
- if (usercmp == 0 && acctcmp == 0 && protocmp == 0) {
- /* Found it! */
- return *curp;
+
+ /* We need to go back and check more values in the context */
+ switch(their_instance) {
+ case OTRL_INSTAG_BEST:
+ return otrl_context_find_recent_secure_instance(*curp);
+ case OTRL_INSTAG_RECENT:
+ case OTRL_INSTAG_RECENT_RECEIVED:
+ case OTRL_INSTAG_RECENT_SENT:
+ return otrl_context_find_recent_instance(*curp, their_instance);
+ default:
+ return NULL;
}
- if (add_if_missing) {
+ }
+
+ if (add_if_missing) {
ConnContext *newctx;
+ OtrlInsTag *our_instag = (OtrlInsTag *)otrl_instag_find(us, accountname,
+ protocol);
+
if (addedp) *addedp = 1;
newctx = new_context(user, accountname, protocol);
newctx->next = *curp;
if (*curp) {
- (*curp)->tous = &(newctx->next);
+ (*curp)->tous = &(newctx->next);
}
*curp = newctx;
newctx->tous = curp;
if (add_app_data) {
- add_app_data(data, *curp);
+ add_app_data(data, *curp);
}
- return *curp;
+
+ /* Initialize specified instance tags */
+ if (our_instag) {
+ newctx->our_instance = our_instag->instag;
}
- return NULL;
+
+ if (their_instance >= OTRL_MIN_VALID_INSTAG ||
+ their_instance == OTRL_INSTAG_MASTER) {
+ newctx->their_instance = their_instance;
+ }
+
+ if (their_instance >= OTRL_MIN_VALID_INSTAG) {
+ newctx->m_context = otrl_context_find(us, user, accountname,
+ protocol, OTRL_INSTAG_MASTER, 1, NULL, add_app_data, data);
+ }
+
+ if (their_instance == OTRL_INSTAG_MASTER) {
+ /* if we're adding a master, there are no children, so the most
+ * recent context is the one we add. */
+ newctx->recent_child = newctx;
+ newctx->recent_rcvd_child = newctx;
+ newctx->recent_sent_child = newctx;
+ }
+
+ return *curp;
+ }
+ return NULL;
+}
+
+/* Return true iff the given fingerprint is marked as trusted. */
+int otrl_context_is_fingerprint_trusted(Fingerprint *fprint) {
+ return fprint && fprint->trust && fprint->trust[0] != '\0';
+}
+
+/* This method gets called after sending or receiving a message, to
+ * update the master context's "recent context" pointers. */
+void otrl_context_update_recent_child(ConnContext *context,
+ unsigned int sent_msg) {
+ ConnContext *m_context = context->m_context;
+
+ if (sent_msg) {
+ m_context->recent_sent_child = context;
+ } else {
+ m_context->recent_rcvd_child = context;
+ }
+
+ m_context->recent_child = context;
+
}
/* Find a fingerprint in a given context, perhaps adding it if not
@@ -144,107 +368,70 @@ ConnContext * otrl_context_find(OtrlUserState us, const char *user,
Fingerprint *otrl_context_find_fingerprint(ConnContext *context,
unsigned char fingerprint[20], int add_if_missing, int *addedp)
{
- Fingerprint *f = context->fingerprint_root.next;
- if (addedp) *addedp = 0;
- while(f) {
+ Fingerprint *f;
+ if (addedp) *addedp = 0;
+
+ if (!context || !context->m_context) return NULL;
+
+ context = context->m_context;
+
+ f = context->fingerprint_root.next;
+ while(f) {
if (!memcmp(f->fingerprint, fingerprint, 20)) return f;
f = f->next;
- }
- /* Didn't find it. */
- if (add_if_missing) {
+ }
+
+ /* Didn't find it. */
+ if (add_if_missing) {
if (addedp) *addedp = 1;
f = malloc(sizeof(*f));
assert(f != NULL);
f->fingerprint = malloc(20);
assert(f->fingerprint != NULL);
- memcpy(f->fingerprint, fingerprint, 20);
+ memmove(f->fingerprint, fingerprint, 20);
f->context = context;
f->trust = NULL;
f->next = context->fingerprint_root.next;
if (f->next) {
- f->next->tous = &(f->next);
+ f->next->tous = &(f->next);
}
context->fingerprint_root.next = f;
f->tous = &(context->fingerprint_root.next);
return f;
- }
- return NULL;
+ }
+ return NULL;
}
/* Set the trust level for a given fingerprint */
void otrl_context_set_trust(Fingerprint *fprint, const char *trust)
{
- if (fprint == NULL) return;
-
- free(fprint->trust);
- fprint->trust = trust ? _strdup(trust) : NULL;
-}
+ if (fprint == NULL) return;
-/* Set the preshared secret for a given fingerprint. Note that this
- * currently only stores the secret in the ConnContext structure, but
- * doesn't yet do anything with it. */
-void otrl_context_set_preshared_secret(ConnContext *context,
- const unsigned char *secret, size_t secret_len)
-{
- free(context->preshared_secret);
- context->preshared_secret = NULL;
- context->preshared_secret_len = 0;
-
- if (secret_len) {
- context->preshared_secret = malloc(secret_len);
- if (context->preshared_secret) {
- memcpy(context->preshared_secret, secret, secret_len);
- context->preshared_secret_len = secret_len;
- }
- }
+ free(fprint->trust);
+ fprint->trust = trust ? strdup(trust) : NULL;
}
/* Force a context into the OTRL_MSGSTATE_FINISHED state. */
void otrl_context_force_finished(ConnContext *context)
{
- context->msgstate = OTRL_MSGSTATE_FINISHED;
- otrl_auth_clear(&(context->auth));
- free(context->fragment);
- context->fragment = NULL;
- context->fragment_len = 0;
- context->fragment_n = 0;
- context->fragment_k = 0;
- context->active_fingerprint = NULL;
- context->their_keyid = 0;
- gcry_mpi_release(context->their_y);
- context->their_y = NULL;
- gcry_mpi_release(context->their_old_y);
- context->their_old_y = NULL;
- context->our_keyid = 0;
- otrl_dh_keypair_free(&(context->our_dh_key));
- otrl_dh_keypair_free(&(context->our_old_dh_key));
- otrl_dh_session_free(&(context->sesskeys[0][0]));
- otrl_dh_session_free(&(context->sesskeys[0][1]));
- otrl_dh_session_free(&(context->sesskeys[1][0]));
- otrl_dh_session_free(&(context->sesskeys[1][1]));
- memset(context->sessionid, 0, 20);
- context->sessionid_len = 0;
- free(context->preshared_secret);
- context->preshared_secret = NULL;
- context->preshared_secret_len = 0;
- context->protocol_version = 0;
- context->numsavedkeys = 0;
- free(context->saved_mac_keys);
- context->saved_mac_keys = NULL;
- gcry_free(context->lastmessage);
- context->lastmessage = NULL;
- context->may_retransmit = 0;
- otrl_sm_state_free(context->smstate);
+ context->msgstate = OTRL_MSGSTATE_FINISHED;
+ otrl_auth_clear(&(context->auth));
+ context->active_fingerprint = NULL;
+ memset(context->sessionid, 0, 20);
+ context->sessionid_len = 0;
+ context->protocol_version = 0;
+ otrl_sm_state_free(context->smstate);
+ otrl_context_priv_force_finished(context->context_priv);
}
/* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
void otrl_context_force_plaintext(ConnContext *context)
{
- /* First clean up everything we'd need to do for the FINISHED state */
- otrl_context_force_finished(context);
+ /* First clean up everything we'd need to do for the FINISHED state */
+ otrl_context_force_finished(context);
- /* And just set the state properly */
- context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
+ /* And just set the state properly */
+ context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
}
/* Forget a fingerprint (so long as it's not the active one. If it's a
@@ -255,76 +442,106 @@ void otrl_context_force_plaintext(ConnContext *context)
void otrl_context_forget_fingerprint(Fingerprint *fprint,
int and_maybe_context)
{
- ConnContext *context = fprint->context;
- if (fprint == &(context->fingerprint_root)) {
+ ConnContext *context = fprint->context;
+ if (fprint == &(context->fingerprint_root)) {
if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
and_maybe_context) {
- otrl_context_forget(context);
+ otrl_context_forget(context);
}
- } else {
+ } else {
if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT ||
context->active_fingerprint != fprint) {
- free(fprint->fingerprint);
- free(fprint->trust);
- *(fprint->tous) = fprint->next;
- if (fprint->next) {
+
+ free(fprint->fingerprint);
+ free(fprint->trust);
+ *(fprint->tous) = fprint->next;
+ if (fprint->next) {
fprint->next->tous = fprint->tous;
- }
- free(fprint);
- if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
- context->fingerprint_root.next == NULL &&
- and_maybe_context) {
+ }
+ free(fprint);
+ if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
+ context->fingerprint_root.next == NULL &&
+ and_maybe_context) {
/* We just deleted the only fingerprint. Forget the
* whole thing. */
otrl_context_forget(context);
- }
- }
+ }
}
+ }
}
-/* Forget a whole context, so long as it's PLAINTEXT. */
-void otrl_context_forget(ConnContext *context)
+/* Forget a whole context, so long as it's PLAINTEXT. If a context has child
+ * instances, don't remove this instance unless children are also all in
+ * PLAINTEXT state. In this case, the children will also be removed.
+ * Returns 0 on success, 1 on failure. */
+int otrl_context_forget(ConnContext *context)
{
- if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return;
+ if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
- /* Just to be safe, force to plaintext. This also frees any
- * extraneous data lying around. */
- otrl_context_force_plaintext(context);
+ if (context->their_instance == OTRL_INSTAG_MASTER) {
+ ConnContext *c_iter;
- /* First free all the Fingerprints */
- while(context->fingerprint_root.next) {
- otrl_context_forget_fingerprint(context->fingerprint_root.next, 0);
+ for (c_iter = context; c_iter &&
+ c_iter->m_context == context->m_context;
+ c_iter = c_iter->next) {
+ if (c_iter->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
}
- /* Now free all the dynamic info here */
- free(context->username);
- free(context->accountname);
- free(context->protocol);
- free(context->smstate);
- context->username = NULL;
- context->accountname = NULL;
- context->protocol = NULL;
- context->smstate = NULL;
-
- /* Free the application data, if it exists */
- if (context->app_data && context->app_data_free) {
+
+ c_iter = context->next;
+ while (c_iter && c_iter->m_context == context->m_context) {
+ if (!otrl_context_forget(c_iter)) {
+ c_iter = context->next;
+ } else {
+ return 1;
+ }
+ }
+
+ }
+
+ /* Just to be safe, force to plaintext. This also frees any
+ * extraneous data lying around. */
+ otrl_context_force_plaintext(context);
+
+ /* First free all the Fingerprints */
+ while(context->fingerprint_root.next) {
+ otrl_context_forget_fingerprint(context->fingerprint_root.next, 0);
+ }
+ /* Now free all the dynamic info here */
+ free(context->username);
+ free(context->accountname);
+ free(context->protocol);
+ free(context->smstate);
+ context->username = NULL;
+ context->accountname = NULL;
+ context->protocol = NULL;
+ context->smstate = NULL;
+
+ /* Free the application data, if it exists */
+ if (context->app_data && context->app_data_free) {
(context->app_data_free)(context->app_data);
context->app_data = NULL;
- }
+ }
- /* Fix the list linkages */
- *(context->tous) = context->next;
- if (context->next) {
+ /* Fix the list linkages */
+ *(context->tous) = context->next;
+ if (context->next) {
context->next->tous = context->tous;
- }
+ }
- free(context);
+ free(context);
+ return 0;
}
/* Forget all the contexts in a given OtrlUserState. */
void otrl_context_forget_all(OtrlUserState us)
{
- while (us->context_root) {
- otrl_context_force_plaintext(us->context_root);
+ ConnContext *c_iter;
+
+ for (c_iter = us->context_root; c_iter; c_iter = c_iter->next) {
+ otrl_context_force_plaintext(c_iter);
+ }
+
+ while (us->context_root) {
otrl_context_forget(us->context_root);
- }
+ }
}