Index: plugins/garble/Makefile.am =================================================================== --- plugins/garble/Makefile.am (revision 0) +++ plugins/garble/Makefile.am (revision 0) @@ -0,0 +1,36 @@ +if TOOLKIT_COCOA + +else +SUBDIRS = xp + +plugindir = $(ABIWORD_PLUGINSDIR) +plugin_LTLIBRARIES = garble.la + +garble_la_LIBADD = \ + xp/libxp.la + +garble_la_LDFLAGS = \ + $(GARBLE_LIBS) \ + -avoid-version \ + -module \ + -no-undefined + +garble_la_SOURCES = + +if TOOLKIT_WIN + +plugin_DATA = \ + garble.dll + +CLEANFILES = \ + garble.def \ + garble.dll \ + garble.dll.a + +.libs/garble.a: garble.la + +garble.dll: .libs/garble.a + $(CXX) -shared $^ -o $@ -Wl,--enable-auto-import -Wl,--out-implib,$@.a $(GARBLE_LIBS) + +endif # TOOLKIT_WIN +endif Index: plugins/garble/plugin.m4 =================================================================== --- plugins/garble/plugin.m4 (revision 0) +++ plugins/garble/plugin.m4 (revision 0) @@ -0,0 +1,47 @@ +garble_deps="no" + +if test "$enable_garble" != ""; then + if test "$TOOLKIT" != "gtk"; then + garble_deps="no" + AC_MSG_WARN([garble plugin: only supported on UNIX/gtk platforms]) + else + # stolen from the original plugin.m4 in abiword-plugins + AC_CHECK_HEADER(readline/readline.h,[ + AC_CHECK_HEADER(readline/history.h,[ + AC_CHECK_LIB(readline,readline,[ + garble_deps="yes" + ],[ AC_CHECK_LIB(readline,rl_initialize,[ + garble_deps="yes" + + ],,) + ],) + ]) + ]) + fi +fi + +if test "$enable_garble" == "yes" || \ + test "$garble_deps" == "yes"; then + +if test "$enable_garble_builtin" == "yes"; then +AC_MSG_ERROR([garble plugin: static linking not supported]) +fi + +AC_MSG_CHECKING([garble plugin: for readline and friends]) +if test "$garble_deps" != "yes"; then + AC_MSG_ERROR([no]) +else + AC_MSG_RESULT([yes]) + GARBLE_LIBS="-lreadline -lhistory $GARBLE_LIBS" +fi + +test "$enable_garble" == "auto" && PLUGINS="$PLUGINS garble" + +GARBLE_CFLAGS="$GARBLE_CFLAGS "'${PLUGIN_CFLAGS}' +GARBLE_LIBS="$GARBLE_LIBS "'${PLUGIN_LIBS}' + +fi + +AC_SUBST([GARBLE_CFLAGS]) +AC_SUBST([GARBLE_LIBS]) + Index: plugins/garble/xp/abiword-garble.cpp =================================================================== --- plugins/garble/xp/abiword-garble.cpp (revision 0) +++ plugins/garble/xp/abiword-garble.cpp (revision 0) @@ -0,0 +1,453 @@ +/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ + +/* AbiSource + * + * Copyright (C) 2009 Marc 'Foddex' Oude Kotte + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "abiword-garble.h" + +//----------------------------------------------------------------------------- +// abiword_document +//----------------------------------------------------------------------------- +abiword_document::abiword_document( abiword_garble* abigarble, const string& filename ) +: mFilename( filename ) +, mDocument( NULL ) +, mAbiGarble( abigarble ) +, mCharsGarbled( 0 ) +, mImagesGarbled( 0 ) { + + if (mAbiGarble->verbose()) + fprintf( stdout, "%s ... ", mFilename.c_str() ); + + // open file with libxml2 + mDocument = xmlReadFile( mFilename.c_str(), "utf-8", XML_PARSE_NOBLANKS | XML_PARSE_NONET ); + if (!mDocument) + throw string( "failed to read file " ) + mFilename; +} + +//----------------------------------------------------------------------------- +abiword_document::~abiword_document() { + + if (mDocument) + xmlFreeDoc( mDocument ); + if (mAbiGarble->verbose()) { + fprintf( stdout, "garbled %u chars", mCharsGarbled ); + if (mAbiGarble->image_garbling()) + fprintf( stdout, ", %u images\n", mImagesGarbled ); + else + fprintf( stdout, "\n" ); + } +} + +//----------------------------------------------------------------------------- +void abiword_document::garble() { + + // find abiword main node + if (!mDocument->children) + throw string( "missing main node" ); + xmlNodePtr abiwordNode = mDocument->children; + while (abiwordNode->type != XML_ELEMENT_NODE) + abiwordNode = abiwordNode->next; + if (xmlStrcmp( abiwordNode->name, BAD_CAST "abiword" )) + throw string( "missing main abiword node" ); + + // find sections + xmlNodePtr curNode = abiwordNode->children; + while (curNode) { + + // if it's a section or data node, handle it + if (curNode->type==XML_ELEMENT_NODE) { + if (!xmlStrcmp( curNode->name, BAD_CAST "section" )) + garble_node( curNode->children ); + else if (!xmlStrcmp( curNode->name, BAD_CAST "data" )) { + if (mAbiGarble->image_garbling()) { + xmlNodePtr dataNode = curNode->children; + while (dataNode) { + if (curNode->type==XML_ELEMENT_NODE) + if (!xmlStrcmp( dataNode->name, BAD_CAST "d" )) + garble_image_node( dataNode ); + dataNode = dataNode->next; + } + } + } + } + + // next node! + curNode = curNode->next; + } +} + +//----------------------------------------------------------------------------- +/*static*/ void abiword_document::_png_read(png_structp png_ptr, png_bytep data, png_size_t length) { + + png_read_data* _data = (png_read_data*) png_get_io_ptr( png_ptr ); + memcpy( data, (char*)_data->data + _data->pos, length ); + _data->pos += length; +} + +//----------------------------------------------------------------------------- +/*static*/ void abiword_document::_png_write( png_structp png_ptr, png_bytep data, png_size_t length ) { + + string* _data = (string*) png_get_io_ptr( png_ptr ); + size_t offset = _data->size(); + _data->resize( offset + length ); + memcpy( &(*_data)[offset], data, length ); +} + +//----------------------------------------------------------------------------- +bool abiword_document::garble_png( void*& data, size_t& size ) { + + png_bytep * dib; + png_uint_32 width; + png_uint_32 height; + int compression_type; + int filter_type; + int interlace_type; + int bit_depth; + int color_type; + png_uint_32 rowbytes; + + // read PNG data + { + png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (void*) NULL, NULL, NULL ); + if (!png_ptr) + return false; + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct( &png_ptr, (png_infopp)NULL, (png_infopp)NULL ); + return false; + } + png_read_data _png_read_data = { data, size, 0 }; + png_set_read_fn( png_ptr, (void*)&_png_read_data, &abiword_document::_png_read ); + png_read_info( png_ptr, info_ptr ); + png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type ); + png_set_packing( png_ptr ); + png_set_expand( png_ptr ); + png_set_strip_16( png_ptr ); + png_set_gray_to_rgb( png_ptr ); + png_set_strip_alpha( png_ptr ); + png_set_interlace_handling( png_ptr ); + png_set_bgr( png_ptr ); + rowbytes = info_ptr->rowbytes; + png_destroy_read_struct( &png_ptr, &info_ptr, NULL ); + } + + // we don't care about the image data itself, we just want a random garbled + // image of the same size + dib = (png_bytep*) malloc( sizeof(png_bytep) * height ); + for (size_t i=0; iproperties; + while (prop) { + if (!xmlStrcmp( prop->name, BAD_CAST "mime-type" )) + mimeTypeStr = prop->children->content; + else if (!xmlStrcmp( prop->name, BAD_CAST "base64" )) + base64EncodedStr = prop->children->content; + prop = prop->next; + } + if (!mimeTypeStr || !base64EncodedStr) + return; + + // check if it's base64 encoded, and then handle based on mimetype + bool base64Encoded = !xmlStrcmp( base64EncodedStr, BAD_CAST "yes" ); + size_t size; + void* data; + if (base64Encoded) { + size = strlen( reinterpret_cast(node->children->content) ); // base64 encoded, so no 0's anyway + data = malloc( size ); + memcpy( data, node->children->content, size ); + size = gsf_base64_decode_simple( (guint8*)data, size ); + } else { + size = xmlUTF8Strlen( node->children->content ); + data = malloc( size ); + memcpy( data, node->children->content, size ); + } + + // now handle based on mime type, data might get reassigned! + bool done; + if (!xmlStrcmp( mimeTypeStr, BAD_CAST "image/png" )) + done = garble_png( data, size ); + else if (!xmlStrcmp( mimeTypeStr, BAD_CAST "image/jpeg" )) + done = garble_jpeg( data, size ); + else + done = false; + + // replace contents + if (done) { + guint8* base64Data = gsf_base64_encode_simple( reinterpret_cast( data ), size ); + xmlNodeSetContent( node, BAD_CAST base64Data ); + g_free(base64Data); + } + + // cleanup data + free( data ); + if (done) + ++mImagesGarbled; +} + +//----------------------------------------------------------------------------- +void abiword_document::garble_node( xmlNodePtr node ) { + + // stop recursion on NULL node + if (!node) + return; + + // garble content, if any + if (node->content) { + + size_t len = xmlUTF8Strlen( node->content ); + if (len) { + + // create string with garbled contents, using spaces, newlines and tabs + // wherever the original string does; + mReplaceString.resize( len, ' ' ); + xmlChar* curChar = node->content; + bool changedStr = false; + for (size_t i=0; ichildren ); + garble_node( node->next ); +} + +//----------------------------------------------------------------------------- +void abiword_document::save() { + + string targetFn = mFilename+".garbled.abw"; + if (xmlSaveFile( targetFn.c_str(), mDocument )<0) + throw string( "failed to write " ) + targetFn; +} + +//----------------------------------------------------------------------------- +char abiword_document::get_random_char() { + + // seed code coming from xap_App.cpp! + static bool seeded = false; + if (!seeded) { + seeded = true; + UT_uint32 t = static_cast(time(NULL)); + UT_srandom(t); + } + + // take these letters, and pick a random one + static string randomChars( + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ); + size_t pos = UT_rand() % randomChars.size(); + return randomChars[ pos ]; +} + +//----------------------------------------------------------------------------- +// abiword_garble +//----------------------------------------------------------------------------- +abiword_garble::abiword_garble( int argc, const char** argv ) +: mVerbose( false ) +, mInitialized( true ) +, mImageGarbling( false ) { + + // parse options + for (int i=1; i::iterator it=mFilenames.begin(); it!=mFilenames.end(); ++it) { + + abiword_document doc( this, *it ); + doc.garble(); + doc.save(); + } + return 0; + } catch (string& err) { + + fprintf( stderr, "error: %s\n", err.c_str() ); + return 1; + } catch (...) { + + fprintf( stderr, "error: unknown exception occured\n" ); + return 1; + } +} + +//----------------------------------------------------------------------------- +// Invoke command +//----------------------------------------------------------------------------- +static bool Garble_invoke( AV_View*, EV_EditMethodCallData* ) { + + int argc = 0; + const char** argv = AP_Args::m_sPluginArgs; + while (argv[argc]) + ++argc; + + abiword_garble g( argc, argv ); + if (g.initialized()) + return g.run() ? false : true; + else + return false; +} + +//----------------------------------------------------------------------------- +static void Garble_registerMethod () { + + XAP_App *pApp = XAP_App::getApp (); + EV_EditMethod *myEditMethod = new EV_EditMethod ("AbiGarble_invoke", Garble_invoke, 0, "" ); + EV_EditMethodContainer *pEMC = pApp->getEditMethodContainer (); + pEMC->addEditMethod (myEditMethod); +} + +//----------------------------------------------------------------------------- +static void Garble_RemoveFromMethods () { + + XAP_App *pApp = XAP_App::getApp (); + EV_EditMethodContainer *pEMC = pApp->getEditMethodContainer (); + EV_EditMethod *pEM = ev_EditMethod_lookup ("AbiGarble_invoke"); + pEMC->removeEditMethod (pEM); + DELETEP (pEM); +} + +//----------------------------------------------------------------------------- +// Abiword Plugin Interface +//----------------------------------------------------------------------------- +ABI_BUILTIN_FAR_CALL int abi_plugin_register( XAP_ModuleInfo* mi ) { + + mi->name = "AbiGarble"; + mi->desc = "Garbles document contents so proprietary documents can be sent in to Abiword's public Bugzilla safely."; + mi->version = ABI_VERSION_STRING; + mi->author = "Marc 'Foddex' Oude Kotte "; + mi->usage = "AbiGarble_invoke"; + Garble_registerMethod(); + return 1; +} + + +//----------------------------------------------------------------------------- +ABI_BUILTIN_FAR_CALL int abi_plugin_unregister( XAP_ModuleInfo* mi ) { + + mi->name = 0; + mi->desc = 0; + mi->version = 0; + mi->author = 0; + mi->usage = 0; + Garble_RemoveFromMethods(); + return 1; +} + + +//----------------------------------------------------------------------------- +ABI_BUILTIN_FAR_CALL int abi_plugin_supports_version( UT_uint32, UT_uint32, UT_uint32 ) { + + return 1; +} Index: plugins/garble/xp/abiword-garble.h =================================================================== --- plugins/garble/xp/abiword-garble.h (revision 0) +++ plugins/garble/xp/abiword-garble.h (revision 0) @@ -0,0 +1,97 @@ +/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ + +/* AbiSource + * + * Copyright (C) 2009 Marc 'Foddex' Oude Kotte + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include "ut_rand.h" +#include "png.h" +#include "xap_Module.h" +#include "xap_App.h" +#include "xav_View.h" +#include "ev_EditMethod.h" +#include "ap_Args.h" + +using namespace std; + +#ifdef ABI_PLUGIN_BUILTIN +#define abi_plugin_register abipgn_garble_register +#define abi_plugin_unregister abipgn_garble_unregister +#define abi_plugin_supports_version abipgn_garble_supports_version +// dll exports break static linking +#define ABI_BUILTIN_FAR_CALL extern "C" +#else +#define ABI_BUILTIN_FAR_CALL ABI_FAR_CALL +ABI_PLUGIN_DECLARE("AbiGarble") +#endif + +class abiword_garble; + +class abiword_document { + + private: + struct png_read_data { + void* data; + size_t size; + size_t pos; + }; + static void _png_read( png_structp png_ptr, png_bytep data, png_size_t length ); + static void _png_write( png_structp png_ptr, png_bytep data, png_size_t length ); + + private: + string mFilename; + xmlDocPtr mDocument; + abiword_garble* mAbiGarble; + size_t mCharsGarbled; + size_t mImagesGarbled; + string mReplaceString; // just a string whose allocated memory is re-used for performance :-) + + void garble_node( xmlNodePtr node ); + void garble_image_node( xmlNodePtr node ); + bool garble_png( void*& data, size_t& size ); + bool garble_jpeg( void*& data, size_t& size ); + char get_random_char(); + public: + abiword_document( abiword_garble* abigarble, const string& filename ); + ~abiword_document(); + void garble(); + void save(); +}; + +class abiword_garble { + + private: + vector mFilenames; + bool mVerbose; + bool mInitialized; + bool mImageGarbling; + + void usage(); + public: + abiword_garble( int argc, const char** argv ); + int run(); + bool verbose() const { return mVerbose; } + bool initialized() const { return mInitialized; } + bool image_garbling() const { return mImageGarbling; } +}; Index: plugins/garble/xp/Makefile.am =================================================================== --- plugins/garble/xp/Makefile.am (revision 0) +++ plugins/garble/xp/Makefile.am (revision 0) @@ -0,0 +1,10 @@ + +noinst_LTLIBRARIES = libxp.la + +AM_CPPFLAGS = \ + $(GARBLE_CFLAGS) \ + -DABI_BUILD_VERSION=\"$(VERSION)\" + +libxp_la_SOURCES = \ + abiword-garble.cpp \ + abiword-garble.h