--- a/libpurple/protocols/novell/nmrtf.c Wed Jun 04 23:12:27 2025 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,830 +0,0 @@ -/* - * nmrtf.c - * - * Copyright (c) 2004 Novell, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - * - */ - -/* This code was adapted from the sample RTF reader found here: - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnrtfspec/html/rtfspec.asp - */ - -#include <glib.h> -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <ctype.h> -#include <string.h> -#include "nmrtf.h" -#include "debug.h" -#include "util.h" - -/* Internal RTF parser error codes */ -#define NMRTF_OK 0 /* Everything's fine! */ -#define NMRTF_STACK_UNDERFLOW 1 /* Unmatched '}' */ -#define NMRTF_STACK_OVERFLOW 2 /* Too many '{' -- memory exhausted */ -#define NMRTF_UNMATCHED_BRACE 3 /* RTF ended during an open group. */ -#define NMRTF_INVALID_HEX 4 /* invalid hex character found in data */ -#define NMRTF_BAD_TABLE 5 /* RTF table (sym or prop) invalid */ -#define NMRTF_ASSERTION 6 /* Assertion failure */ -#define NMRTF_EOF 7 /* End of file reached while reading RTF */ -#define NMRTF_CONVERT_ERROR 8 /* Error converting text */ - -#define NMRTF_MAX_DEPTH 256 - -typedef enum -{ - NMRTF_STATE_NORMAL, - NMRTF_STATE_SKIP, - NMRTF_STATE_FONTTABLE, - NMRTF_STATE_BIN, - NMRTF_STATE_HEX -} NMRtfState; /* Rtf State */ - -/* Property types that we care about */ -typedef enum -{ - NMRTF_PROP_FONT_IDX, - NMRTF_PROP_FONT_CHARSET, - NMRTF_PROP_MAX -} NMRtfProperty; - -typedef enum -{ - NMRTF_SPECIAL_BIN, - NMRTF_SPECIAL_HEX, - NMRTF_SPECIAL_UNICODE, - NMRTF_SPECIAL_SKIP -} NMRtfSpecialKwd; - -typedef enum -{ - NMRTF_DEST_FONTTABLE, - NMRTF_DEST_SKIP -} NMRtfDestinationType; - -typedef enum -{ - NMRTF_KWD_CHAR, - NMRTF_KWD_DEST, - NMRTF_KWD_PROP, - NMRTF_KWD_SPEC -} NMRtfKeywordType; - -typedef struct _NMRTFCharProp -{ - /* All we care about for now is the font. - * bold, italic, underline, etc. should be - * added here - */ - int font_idx; - int font_charset; -} NMRtfCharProp; - -typedef struct _NMRtfStateSave -{ - NMRtfCharProp chp; - NMRtfState rds; - NMRtfState ris; -} NMRtfStateSave; - -typedef struct _NMRtfSymbol -{ - char *keyword; /* RTF keyword */ - int default_val; /* default value to use */ - gboolean pass_default; /* true to use default value from this table */ - NMRtfKeywordType kwd_type; /* the type of the keyword */ - int action; /* property type if the keyword represents a property */ - /* destination type if the keyword represents a destination */ - /* character to print if the keyword represents a character */ -} NMRtfSymbol; - - -typedef struct _NMRtfFont -{ - int number; - char *name; - int charset; -} NMRtfFont; - -/* RTF Context */ -struct _NMRtfContext -{ - NMRtfState rds; /* destination state */ - NMRtfState ris; /* internal state */ - NMRtfCharProp chp; /* current character properties (ie. font, bold, italic, etc.) */ - GSList *font_table; /* the font table */ - GSList *saved; /* saved state stack */ - int param; /* numeric parameter for the current keyword */ - long bytes_to_skip; /* number of bytes to skip (after encountering \bin) */ - int depth; /* how many groups deep are we */ - gboolean skip_unknown; /* if true, skip any unknown destinations (this is set after encountering '\*') */ - char *input; /* input string */ - guchar nextch; /* next char in input */ - gboolean nextch_available; /* nextch value is set */ - GString *ansi; /* Temporary ansi text, will be convert/flushed to the output string */ - GString *output; /* The plain text UTF8 string */ -}; - -static int rtf_parse(NMRtfContext *ctx); -static int rtf_push_state(NMRtfContext *ctx); -static int rtf_pop_state(NMRtfContext *ctx); -static NMRtfFont *rtf_get_font(NMRtfContext *ctx, int index); -static int rtf_get_char(NMRtfContext *ctx, guchar *ch); -static int rtf_unget_char(NMRtfContext *ctx, guchar ch); -static int rtf_flush_data(NMRtfContext *ctx); -static int rtf_parse_keyword(NMRtfContext *ctx); -static int rtf_dispatch_control(NMRtfContext *ctx, char *keyword, int param, gboolean param_set); -static int rtf_dispatch_char(NMRtfContext *ctx, guchar ch); -static int rtf_dispatch_unicode_char(NMRtfContext *ctx, gunichar ch); -static int rtf_print_char(NMRtfContext *ctx, guchar ch); -static int rtf_print_unicode_char(NMRtfContext *ctx, gunichar ch); -static int rtf_change_destination(NMRtfContext *ctx, NMRtfDestinationType dest); -static int rtf_dispatch_special(NMRtfContext *ctx, NMRtfSpecialKwd special); -static int rtf_apply_property(NMRtfContext *ctx, NMRtfProperty prop, int val); - -/* RTF parser tables */ - -/* Keyword descriptions */ -NMRtfSymbol rtf_symbols[] = { - /* keyword, default, pass_default, keyword_type, action */ - {"fonttbl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_FONTTABLE}, - {"f", 0, FALSE, NMRTF_KWD_PROP, NMRTF_PROP_FONT_IDX}, - {"fcharset", 0, FALSE, NMRTF_KWD_PROP, NMRTF_PROP_FONT_CHARSET}, - {"par", 0, FALSE, NMRTF_KWD_CHAR, 0x0a}, - {"line", 0, FALSE, NMRTF_KWD_CHAR, 0x0a}, - {"\0x0a", 0, FALSE, NMRTF_KWD_CHAR, 0x0a}, - {"\0x0d", 0, FALSE, NMRTF_KWD_CHAR, 0x0a}, - {"tab", 0, FALSE, NMRTF_KWD_CHAR, 0x09}, - {"\r", 0, FALSE, NMRTF_KWD_CHAR, '\r'}, - {"\n", 0, FALSE, NMRTF_KWD_CHAR, '\n'}, - {"ldblquote",0, FALSE, NMRTF_KWD_CHAR, '"'}, - {"rdblquote",0, FALSE, NMRTF_KWD_CHAR, '"'}, - {"{", 0, FALSE, NMRTF_KWD_CHAR, '{'}, - {"}", 0, FALSE, NMRTF_KWD_CHAR, '}'}, - {"\\", 0, FALSE, NMRTF_KWD_CHAR, '\\'}, - {"bin", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_BIN}, - {"*", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_SKIP}, - {"'", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_HEX}, - {"u", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_UNICODE}, - {"colortbl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"author", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"buptim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"comment", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"creatim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"doccomm", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"footer", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"footerf", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"footerl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"footerr", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"footnote", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"ftncn", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"ftnsep", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"ftnsepc", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"header", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"headerf", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"headerl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"headerr", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"info", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"keywords", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"operator", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"pict", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"printim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"private1", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"revtim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"rxe", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"stylesheet", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"subject", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"tc", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"title", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"txe", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}, - {"xe", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP} -}; -int table_size = sizeof(rtf_symbols) / sizeof(NMRtfSymbol); - -NMRtfContext * -nm_rtf_init() -{ - NMRtfContext *ctx = g_new0(NMRtfContext, 1); - ctx->nextch_available = FALSE; - ctx->ansi = g_string_new(""); - ctx->output = g_string_new(""); - return ctx; -} - -char * -nm_rtf_strip_formatting(NMRtfContext *ctx, const char *input) -{ - int status; - - ctx->input = (char *)input; - status = rtf_parse(ctx); - if (status == NMRTF_OK) - return g_strdup(ctx->output->str); - - purple_debug_info("novell", "RTF parser failed with error code %d\n", status); - return NULL; -} - -void -nm_rtf_deinit(NMRtfContext *ctx) -{ - GSList *node; - NMRtfFont *font; - NMRtfStateSave *save; - - if (ctx) { - for (node = ctx->font_table; node; node = node->next) { - font = node->data; - g_free(font->name); - g_free(font); - node->data = NULL; - } - g_slist_free(ctx->font_table); - for (node = ctx->saved; node; node = node->next) { - save = node->data; - g_free(save); - node->data = NULL; - } - g_slist_free(ctx->saved); - g_string_free(ctx->ansi, TRUE); - g_string_free(ctx->output, TRUE); - g_free(ctx); - } -} - -static const char * -get_current_encoding(NMRtfContext *ctx) -{ - NMRtfFont *font; - - font = rtf_get_font(ctx, ctx->chp.font_idx); - - switch (font->charset) { - case 0: - return "CP1252"; - case 77: - return "MACINTOSH"; - case 78: - return "SJIS"; - case 128: - return "CP932"; - case 129: - return "CP949"; - case 130: - return "CP1361"; - case 134: - return "CP936"; - case 136: - return "CP950"; - case 161: - return "CP1253"; - case 162: - return "CP1254"; - case 163: - return "CP1258"; - case 181: - case 177: - return "CP1255"; - case 178: - case 179: - case 180: - return "CP1256"; - case 186: - return "CP1257"; - case 204: - return "CP1251"; - case 222: - return "CP874"; - case 238: - return "CP1250"; - case 254: - return "CP437"; - default: - purple_debug_info("novell", "Unhandled font charset %d\n", font->charset); - return "CP1252"; - } -} - - -/* - * Add an entry to the font table - */ -static int -rtf_add_font_entry(NMRtfContext *ctx, int number, const char *name, int charset) -{ - NMRtfFont *font = g_new0(NMRtfFont, 1); - - font->number = number; - font->name = g_strdup(name); - font->charset = charset; - - purple_debug_info("novell", "Adding font to table: #%d\t%s\t%d\n", - font->number, font->name, font->charset); - - ctx->font_table = g_slist_append(ctx->font_table, font); - - return NMRTF_OK; -} - -/* - * Return the nth entry in the font table - */ -static NMRtfFont * -rtf_get_font(NMRtfContext *ctx, int nth) -{ - NMRtfFont *font; - - font = g_slist_nth_data(ctx->font_table, nth); - - return font; -} - -/* - * Step 1: - * Isolate RTF keywords and send them to rtf_parse_keyword; - * Push and pop state at the start and end of RTF groups; - * Send text to rtf_dispatch_char for further processing. - */ -static int -rtf_parse(NMRtfContext *ctx) -{ - int status; - guchar ch; - guchar hex_byte = 0; - int hex_count = 2; - int len; - - if (ctx->input == NULL) - return NMRTF_OK; - - while (rtf_get_char(ctx, &ch) == NMRTF_OK) { - if (ctx->depth < 0) - return NMRTF_STACK_UNDERFLOW; - - /* if we're parsing binary data, handle it directly */ - if (ctx->ris == NMRTF_STATE_BIN) { - if ((status = rtf_dispatch_char(ctx, ch)) != NMRTF_OK) - return status; - } else { - switch (ch) { - case '{': - if (ctx->depth > NMRTF_MAX_DEPTH) - return NMRTF_STACK_OVERFLOW; - rtf_flush_data(ctx); - if ((status = rtf_push_state(ctx)) != NMRTF_OK) - return status; - break; - case '}': - rtf_flush_data(ctx); - - /* for some reason there is always an unwanted '\par' at the end */ - if (ctx->rds == NMRTF_STATE_NORMAL) { - len = ctx->output->len; - if (ctx->output->str[len-1] == '\n') - ctx->output = g_string_truncate(ctx->output, len-1); - } - - if ((status = rtf_pop_state(ctx)) != NMRTF_OK) - return status; - - if (ctx->depth < 0) - return NMRTF_STACK_OVERFLOW; - break; - case '\\': - if ((status = rtf_parse_keyword(ctx)) != NMRTF_OK) - return status; - break; - case 0x0d: - case 0x0a: /* cr and lf are noise characters... */ - break; - default: - if (ctx->ris == NMRTF_STATE_NORMAL) { - if ((status = rtf_dispatch_char(ctx, ch)) != NMRTF_OK) - return status; - } else { /* parsing a hex encoded character */ - if (ctx->ris != NMRTF_STATE_HEX) - return NMRTF_ASSERTION; - - hex_byte = hex_byte << 4; - if (isdigit(ch)) - hex_byte += (char) ch - '0'; - else { - if (islower(ch)) { - if (ch < 'a' || ch > 'f') - return NMRTF_INVALID_HEX; - hex_byte += (char) ch - 'a' + 10; - } else { - if (ch < 'A' || ch > 'F') - return NMRTF_INVALID_HEX; - hex_byte += (char) ch - 'A' + 10; - } - } - hex_count--; - if (hex_count == 0) { - if ((status = rtf_dispatch_char(ctx, hex_byte)) != NMRTF_OK) - return status; - hex_count = 2; - hex_byte = 0; - ctx->ris = NMRTF_STATE_NORMAL; - } - } - break; - } - } - } - if (ctx->depth < 0) - return NMRTF_STACK_OVERFLOW; - if (ctx->depth > 0) - return NMRTF_UNMATCHED_BRACE; - return NMRTF_OK; -} - -/* - * Push the current state onto stack - */ -static int -rtf_push_state(NMRtfContext *ctx) -{ - NMRtfStateSave *save = g_new0(NMRtfStateSave, 1); - save->chp = ctx->chp; - save->rds = ctx->rds; - save->ris = ctx->ris; - ctx->saved = g_slist_prepend(ctx->saved, save); - ctx->ris = NMRTF_STATE_NORMAL; - (ctx->depth)++; - return NMRTF_OK; -} - -/* - * Restore the state at the top of the stack - */ -static int -rtf_pop_state(NMRtfContext *ctx) -{ - NMRtfStateSave *save_old; - GSList *link_old; - - if (ctx->saved == NULL) - return NMRTF_STACK_UNDERFLOW; - - save_old = ctx->saved->data; - ctx->chp = save_old->chp; - ctx->rds = save_old->rds; - ctx->ris = save_old->ris; - (ctx->depth)--; - - g_free(save_old); - link_old = ctx->saved; - ctx->saved = g_slist_remove_link(ctx->saved, link_old); - g_slist_free_1(link_old); - return NMRTF_OK; -} - -/* - * Step 2: - * Get a control word (and its associated value) and - * dispatch the control. - */ -static int -rtf_parse_keyword(NMRtfContext *ctx) -{ - int status = NMRTF_OK; - guchar ch; - gboolean param_set = FALSE; - gboolean is_neg = FALSE; - int param = 0; - char keyword[30]; - char parameter[20]; - gsize i; - - keyword[0] = '\0'; - parameter[0] = '\0'; - if ((status = rtf_get_char(ctx, &ch)) != NMRTF_OK) - return status; - - if (!isalpha(ch)) { - /* a control symbol; no delimiter. */ - keyword[0] = (char) ch; - keyword[1] = '\0'; - return rtf_dispatch_control(ctx, keyword, 0, param_set); - } - - /* parse keyword */ - for (i = 0; isalpha(ch) && (i < sizeof(keyword) - 1); rtf_get_char(ctx, &ch)) { - keyword[i] = (char) ch; - i++; - } - keyword[i] = '\0'; - - /* check for '-' indicated a negative parameter value */ - if (ch == '-') { - is_neg = TRUE; - if ((status = rtf_get_char(ctx, &ch)) != NMRTF_OK) - return status; - } - - /* check for numerical param */ - if (isdigit(ch)) { - - param_set = TRUE; - for (i = 0; isdigit(ch) && (i < sizeof(parameter) - 1); rtf_get_char(ctx, &ch)) { - parameter[i] = (char) ch; - i++; - } - parameter[i] = '\0'; - - ctx->param = param = atoi(parameter); - if (is_neg) - ctx->param = param = -param; - } - - /* space after control is optional, put character back if it is not a space */ - if (ch != ' ') - rtf_unget_char(ctx, ch); - - return rtf_dispatch_control(ctx, keyword, param, param_set); -} - -/* - * Route the character to the appropriate destination - */ -static int -rtf_dispatch_char(NMRtfContext *ctx, guchar ch) -{ - if (ctx->ris == NMRTF_STATE_BIN && --(ctx->bytes_to_skip) <= 0) - ctx->ris = NMRTF_STATE_NORMAL; - - switch (ctx->rds) { - case NMRTF_STATE_SKIP: - return NMRTF_OK; - case NMRTF_STATE_NORMAL: - return rtf_print_char(ctx, ch); - case NMRTF_STATE_FONTTABLE: - if (ch == ';') { - rtf_add_font_entry(ctx, ctx->chp.font_idx, - ctx->ansi->str, ctx->chp.font_charset); - g_string_truncate(ctx->ansi, 0); - } - else { - return rtf_print_char(ctx, ch); - } - return NMRTF_OK; - default: - return NMRTF_OK; - } -} - -/* Handle a unicode character */ -static int -rtf_dispatch_unicode_char(NMRtfContext *ctx, gunichar ch) -{ - switch (ctx->rds) { - case NMRTF_STATE_SKIP: - return NMRTF_OK; - case NMRTF_STATE_NORMAL: - case NMRTF_STATE_FONTTABLE: - return rtf_print_unicode_char(ctx, ch); - default: - return NMRTF_OK; - } -} - -/* - * Output a character - */ -static int -rtf_print_char(NMRtfContext *ctx, guchar ch) -{ - - ctx->ansi = g_string_append_c(ctx->ansi, ch); - - return NMRTF_OK; -} - -/* - * Output a unicode character - */ -static int -rtf_print_unicode_char(NMRtfContext *ctx, gunichar ch) -{ - char buf[7]; - int num; - - /* convert and flush the ansi buffer to the utf8 buffer */ - rtf_flush_data(ctx); - - /* convert the unicode character to utf8 and add directly to the output buffer */ - num = g_unichar_to_utf8((gunichar) ch, buf); - buf[num] = 0; - purple_debug_info("novell", "converted unichar 0x%X to utf8 char %s\n", ch, buf); - - ctx->output = g_string_append(ctx->output, buf); - return NMRTF_OK; -} - -/* - * Flush the output text - */ -static int -rtf_flush_data(NMRtfContext *ctx) -{ - int status = NMRTF_OK; - char *conv_data = NULL; - const char *enc = NULL; - GError *gerror = NULL; - - if (ctx->rds == NMRTF_STATE_NORMAL && ctx->ansi->len > 0) { - enc = get_current_encoding(ctx); - conv_data = g_convert(ctx->ansi->str, ctx->ansi->len, "UTF-8", enc, - NULL, NULL, &gerror); - if (conv_data) { - ctx->output = g_string_append(ctx->output, conv_data); - g_free(conv_data); - ctx->ansi = g_string_truncate(ctx->ansi, 0); - } else { - status = NMRTF_CONVERT_ERROR; - purple_debug_info("novell", "failed to convert data! error code = %d msg = %s\n", - gerror->code, gerror->message); - g_free(gerror); - } - } - - return status; -} - -/* - * Handle a property change - */ -static int -rtf_apply_property(NMRtfContext *ctx, NMRtfProperty prop, int val) -{ - if (ctx->rds == NMRTF_STATE_SKIP) /* If we're skipping text, */ - return NMRTF_OK; /* don't do anything. */ - - /* Need to flush any temporary data before a property change*/ - rtf_flush_data(ctx); - - switch (prop) { - case NMRTF_PROP_FONT_IDX: - ctx->chp.font_idx = val; - break; - case NMRTF_PROP_FONT_CHARSET: - ctx->chp.font_charset = val; - break; - default: - return NMRTF_BAD_TABLE; - } - - return NMRTF_OK; -} - -/* - * Step 3. - * Search the table for keyword and evaluate it appropriately. - * - * Inputs: - * keyword: The RTF control to evaluate. - * param: The parameter of the RTF control. - * param_set: TRUE if the control had a parameter; (that is, if param is valid) - * FALSE if it did not. - */ -static int -rtf_dispatch_control(NMRtfContext *ctx, char *keyword, int param, gboolean param_set) -{ - int idx; - - for (idx = 0; idx < table_size; idx++) { - if (purple_strequal(keyword, rtf_symbols[idx].keyword)) - break; - } - - if (idx == table_size) { - if (ctx->skip_unknown) - ctx->rds = NMRTF_STATE_SKIP; - ctx->skip_unknown = FALSE; - return NMRTF_OK; - } - - /* found it! use kwd_type and action to determine what to do with it. */ - ctx->skip_unknown = FALSE; - switch (rtf_symbols[idx].kwd_type) { - case NMRTF_KWD_PROP: - if (rtf_symbols[idx].pass_default || !param_set) - param = rtf_symbols[idx].default_val; - return rtf_apply_property(ctx, rtf_symbols[idx].action, param); - case NMRTF_KWD_CHAR: - return rtf_dispatch_char(ctx, rtf_symbols[idx].action); - case NMRTF_KWD_DEST: - return rtf_change_destination(ctx, rtf_symbols[idx].action); - case NMRTF_KWD_SPEC: - return rtf_dispatch_special(ctx, rtf_symbols[idx].action); - default: - return NMRTF_BAD_TABLE; - } - return NMRTF_BAD_TABLE; -} - -/* - * Change to the destination specified. - */ -static int -rtf_change_destination(NMRtfContext *ctx, NMRtfDestinationType type) -{ - /* if we're skipping text, don't do anything */ - if (ctx->rds == NMRTF_STATE_SKIP) - return NMRTF_OK; - - switch (type) { - case NMRTF_DEST_FONTTABLE: - ctx->rds = NMRTF_STATE_FONTTABLE; - g_string_truncate(ctx->ansi, 0); - break; - default: - ctx->rds = NMRTF_STATE_SKIP; /* when in doubt, skip it... */ - break; - } - return NMRTF_OK; -} - -/* - * Dispatch an RTF control that needs special processing - */ -static int -rtf_dispatch_special(NMRtfContext *ctx, NMRtfSpecialKwd type) -{ - int status = NMRTF_OK; - guchar ch; - - if (ctx->rds == NMRTF_STATE_SKIP && type != NMRTF_SPECIAL_BIN) /* if we're skipping, and it's not */ - return NMRTF_OK; /* the \bin keyword, ignore it. */ - - switch (type) { - case NMRTF_SPECIAL_BIN: - ctx->ris = NMRTF_STATE_BIN; - ctx->bytes_to_skip = ctx->param; - break; - case NMRTF_SPECIAL_SKIP: - ctx->skip_unknown = TRUE; - break; - case NMRTF_SPECIAL_HEX: - ctx->ris = NMRTF_STATE_HEX; - break; - case NMRTF_SPECIAL_UNICODE: - purple_debug_info("novell", "parsing unichar\n"); - status = rtf_dispatch_unicode_char(ctx, ctx->param); - /* Skip next char */ - if (status == NMRTF_OK) - status = rtf_get_char(ctx, &ch); - break; - default: - status = NMRTF_BAD_TABLE; - break; - } - - return status; -} - -/* - * Get the next character from the input stream - */ -static int -rtf_get_char(NMRtfContext *ctx, guchar *ch) -{ - if (ctx->nextch_available) { - *ch = ctx->nextch; - ctx->nextch_available = FALSE; - } else { - *ch = *(ctx->input); - ctx->input++; - } - - if (*ch) - return NMRTF_OK; - else - return NMRTF_EOF; -} - -/* - * Move a character back into the input stream - */ -static int -rtf_unget_char(NMRtfContext *ctx, guchar ch) -{ - ctx->nextch = ch; - ctx->nextch_available = TRUE; - return NMRTF_OK; -}