-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi

At the moment there are some problems with the smily system.

1. bug 1224036 - > does not work in emoticons.xml
http://sourceforge.net/tracker/index.php?func=detail&aid=1224036&group_id=254&atid=100254

2. at the moment there is simply a replacement of the smily symbols with
the image even in urls

3. if I have 100 smilies, there will be 100 times "search and replace"
for one message


To solve these problems I wrote this patch. It arranges the smilies
internally in  a tree. Urls are handled as protected content where no
replacement of smily should be done.
For example if there are the smilies :) and :-) the tree would look like
       :
      / \
     )   -
         |
         )
So I search in the message only the ':' symbol and look whether is is
part of the smily. If it is a smily and not part of an url it is
replaces by an image.
Additionally the bug mentioned above is fixed here.


regars,
rsLeo
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFESTwmuFcJvHsEu9gRAsFIAJsEqn6jWES4NP1dzh8xGXoYMshihgCfUbRV
2MXGuRsvAnTOJH4wYxyARnU=
=crJ0
-----END PGP SIGNATURE-----
--- licq/plugins/qt-gui/src/emoticon.h  2006-03-10 12:24:35.000000000 +0100
+++ licq_patched/plugins/qt-gui/src/emoticon.h  2006-04-09 17:17:44.000000000 
+0200
@@ -4,6 +4,7 @@
 #include <qmap.h>
 #include <qstring.h>
 #include <qstringlist.h>
+#include "emotnode.h"
 
 class CEmoticons {
 
--- licq/plugins/qt-gui/src/emoticon.cpp        2006-03-10 12:24:35.000000000 
+0100
+++ licq_patched/plugins/qt-gui/src/emoticon.cpp        2006-04-09 
17:19:27.000000000 +0200
@@ -23,7 +23,6 @@
 {
   QStringList  emoticon;
   QString      file;
-  QRegExp      reg;
 };
 
 typedef std::list<struct node> node_list_t;
@@ -36,6 +35,7 @@
   QString theme;       /* current theme */
 
   node_list_t emoticons;
+  EmotNode *emoticonsTree;
 };
 
 CEmoticons::CEmoticons(const char *basedir, const char *altbasedir, 
@@ -44,10 +44,12 @@
   this->data = new struct Emoticons;
   data->basedir = basedir;
   data->altbasedir = altbasedir;
+  data->emoticonsTree = NULL;
 }
 
 CEmoticons::~CEmoticons()
 {
+  delete this->data->emoticonsTree;
   delete this->data;
 }
 
@@ -140,52 +142,20 @@
   return ret;
 }
 
-static void create_regexp(QStringList &list, QRegExp &reg)
-{
-  unsigned n = 0;
-  QString s = "(";
-
-  for (QStringList::Iterator it = list.begin(); it!=list.end(); ++it)
-  {
-    if (n != 0)
-      s += "|";
-#if QT_VERSION < 0x030100
-    // we have to implement the functionality of QRegExp::escape() 
-    // ourself since qt 3.0.x is missing it.
-    // Our goal is to escape all special characters with a backslash:
-    // The special characters are $, (, ), *, +, ., ?, [, \, ], ^, {, | and }.
-    // The implementation is heavily inspired by QT QRegExp sources ;-)
-    
-    static const char *c = "\\$()*+.?[]^{}|";
-    int i = 0;
-    QString tmp = (*it).latin1();
-    while (i < (int)tmp.length())
-    {
-      if (strstr(c, tmp.mid(i,1).latin1()) != 0)
-        tmp.insert( i++, "\\");
-      i++;
-    }
-    s += tmp;
-#else
-    s += QRegExp::escape(*it);
-#endif
-    n++;
-  }
-  s += ")";
-  reg = QRegExp(s);
-}
 
 /*!
  *
  * \param data       CDT for the CEmoticon class
  * \param themedir   path to the theme directory
  * \param list       list where the results are stored
+ * \param emoticonsTree tree where the smilies are stored
  *
  * \returns the number of loaded emoticons
  */
 static unsigned loadTheme(const struct Emoticons *data,
                           const QString &themedir,
-                          node_list_t &list)
+                          node_list_t &list,
+                          EmotNode *emoticonsTree = NULL)
 {
   QDomDocument doc("doc");
   QFile file(themedir + "/emoticons.xml");
@@ -210,13 +180,14 @@
             unsigned size;
 
             node.emoticon = loadStrings(data, n.firstChild(), &size);
-           if (size)
-           {
-             node.file = f;
-             create_regexp(node.emoticon, node.reg);
-             list.push_back(node);
-             ret += size;
-           }
+            if (size)
+            {
+              node.file = f;
+              list.push_back(node);
+              if (emoticonsTree != NULL)
+                emoticonsTree->insert(node.emoticon, f, true);
+              ret += size;
+            }
           }
         }
       }
@@ -240,13 +211,14 @@
   QDir d1(szdir1);
   QDir d2(szdir2);
   node_list_t list;
+  EmotNode *emoTree = new EmotNode();
   int ret = -1;
   unsigned n = 0;
 
   if (d1.exists())
-    n = loadTheme(data, szdir1.ascii(), list);
+    n = loadTheme(data, szdir1.ascii(), list, emoTree);
   else if(d2.exists())
-    n = loadTheme(data, szdir2.ascii(), list);
+    n = loadTheme(data, szdir2.ascii(), list, emoTree);
 
 
   if (n)
@@ -254,7 +226,10 @@
     ret = n;
     data->theme = theme;
     data->emoticons = list;
+    data->emoticonsTree = emoTree;
   }
+  else
+    delete emoTree;
 
   return ret;
 }
@@ -326,26 +301,9 @@
 
 void CEmoticons::ParseMessage(QString &msg)
 {
-  /**
-   * \todo this sucks: solution create a finite state machine to parse
-   * the message
-   */
-  node_list_t::iterator iter;
-  struct node n;
-
   if (data->theme != QString::null && data->theme != "None")
   {
-    QString r;
-    for( iter  = data->emoticons.begin();
-         iter != data->emoticons.end() ; iter++ )
-    {
-      n = *iter;
-      for ( QStringList::Iterator it = n.emoticon.begin();
-             it != n.emoticon.end(); ++it)
-      {
-        msg.replace(n.reg," <img src=\""+n.file+"\"/>&nbsp;");
-      }
-    }
+    msg = data->emoticonsTree->replaceSmilies(msg);
   }
 }
 
--- licq/plugins/qt-gui/src/Makefile.am 2006-03-10 12:24:35.000000000 +0100
+++ licq_patched/plugins/qt-gui/src/Makefile.am 2006-04-09 20:33:12.578165592 
+0200
@@ -21,7 +21,7 @@
        mmlistview.h mmsenddlg.h userinfodlg.h usereventdlg.h keyrequestdlg.h \
        jfcstyle.h usercodec.h reqauthdlg.h licqdialog.h userselectdlg.h \
        editfilelistdlg.h emoticon.h catdlg.h phonedlg.h ownermanagerdlg.h \
-       gpgkeyselect.h gpgkeymanager.h licqkimiface.h kimiface.h
+       gpgkeyselect.h gpgkeymanager.h licqkimiface.h kimiface.h emotnode.h
 
 licq_gui = adduserdlg.cpp authuserdlg.cpp awaymsgdlg.cpp \
        refusedlg.cpp chatdlg.cpp editgrp.cpp editfile.cpp eventdesc.cpp \
@@ -34,7 +34,7 @@
        mmsenddlg.cpp userinfodlg.cpp usereventdlg.cpp keyrequestdlg.cpp \
        jfcstyle.cpp usercodec.cpp reqauthdlg.cpp licqdialog.cpp 
userselectdlg.cpp \
        editfilelistdlg.cpp emoticon.cpp catdlg.cpp phonedlg.cpp \
-       ownermanagerdlg.cpp gpgkeyselect.cpp gpgkeymanager.cpp 
+       ownermanagerdlg.cpp gpgkeyselect.cpp gpgkeymanager.cpp emotnode.cpp
 
 licq_qt_gui_la_SOURCES = $(licq_gui)
 licq_kde_gui_la_SOURCES = $(licq_gui) wrap_kde_malloc.cpp \
--- /dev/null   2005-08-09 09:06:25.000000000 +0200
+++ licq_patched/plugins/qt-gui/src/emotnode.h  2006-04-06 00:23:05.000000000 
+0200
@@ -0,0 +1,71 @@
+#ifndef EMOTNODE_H
+#define EMOTNODE_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <string>
+#include <map>
+
+
+class EmotNode{
+private:
+  struct file_child_t {
+    QString    m_file;   //every node can have a filename (image)
+    EmotNode*  mp_child; //every node may link to other nodes
+
+  };
+  
+  typedef std::map<QChar,file_child_t>                 node_t;
+  typedef std::map<QChar,file_child_t>::const_iterator node_iter_t;
+  
+  node_t  m_node;   //m_node[symbol_x], m_node[symbol_y] are all nodes
+                    //example with smily :-)
+                    //m_node[:].mp_child[-].mp_child[)].m_file = smily.jpg
+  
+  /**
+  * Check whether at a given position in a message a smily can be found. 
+  * @param msg message with smilies
+  * @param spos position of possible smily
+  * @param endPos returns the end position of a smily if one is found
+  * @return If a smily was found then the filename is returned. Else NULL ist 
returned.
+  */
+  QString  searchSmilyInTree(QString msg, int spos, int &endPos);
+  
+  /**
+  * Parse the msg for contents which should not be replaced with smilies
+  * @param msg 
+  */
+  QString  createSpecialContentSafe(QString msg);
+  
+public:
+  EmotNode();
+  EmotNode(QString icons, QString filename);
+  
+  ~EmotNode();
+  
+  /**
+  * Insert one smily with all his representatives. 
+  * @param iconList list of representatives of the smily
+  * @param filename name of image file
+  * @param doEncodeSmily (optional, default=false) encode the smilies e.g. >:) 
will be &gt;:)
+  */
+  void    insert(QStringList iconList, QString filename, bool doEncode);
+  
+  /**
+  * Insert a new smily in the tree.
+  * @param icons the test of the smily
+  * @param filename the image name of the smily
+  * @param depth used internally because of recursive behaviour
+  */
+  void     insert(QString icons, QString filename, unsigned int depth = 0);
+  
+  /**
+  * Replace all smilies in a message and return the resulting message.
+  * @param msg message with smilies to replace
+  * @return message with replaced smilies
+  */
+  QString  replaceSmilies(QString msg);
+};
+
+#endif
--- /dev/null   2005-08-09 09:06:25.000000000 +0200
+++ licq_patched/plugins/qt-gui/src/emotnode.cpp        2006-04-09 
19:06:43.549017928 +0200
@@ -0,0 +1,221 @@
+/* Licq - A ICQ Client for Unix
+ 
+   Copyright (C) 2006 Martin Garbe <[EMAIL PROTECTED]>
+ 
+   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ * \file Build a tree with smily symbols. Every node has one symbol of
+ *       a smily and maybe a filename to an image. There is a filename
+ *       if the symbols on the path from the root node to this node 
+ *       builds a smily.
+ */
+ 
+#include <qregexp.h>
+#include <qstylesheet.h>
+
+#include "licq_log.h"
+
+#include "emotnode.h"
+
+
+EmotNode::EmotNode()
+{
+
+}
+
+
+/*
+ * Insert one smily with all his representatives. 
+ */
+void EmotNode::insert(QStringList iconList, QString filename, bool 
doEncodeSmily = false)
+{
+  for (QStringList::Iterator iter = iconList.begin(); iter != iconList.end(); 
iter++)
+  {
+    if (doEncodeSmily)
+    {
+      insert(QStyleSheet::escape(*iter), filename);
+    }
+    else
+    {
+      insert(*iter, filename);
+    }
+  }
+}
+
+
+/*
+ * Insert a new smily in the tree.
+ */
+void EmotNode::insert(QString icons, QString filename, unsigned int depth )
+{
+  QChar sym = icons.at(depth);
+  node_iter_t iter = m_node.find(sym);
+  if (iter != m_node.end())
+  {
+    //symbol already exists here
+    if ((depth+1) == icons.length())
+    {
+      //if end of symbol is reached then insert file
+      m_node[sym].m_file = filename;
+    }
+    else
+    {
+      //end of symbol not reached -> go deeper
+      m_node[sym].mp_child->insert(icons, filename, depth+1);
+    }
+  }
+  else
+  {
+    //add symbol here
+    m_node[sym].mp_child = new EmotNode();
+    if ((depth+1) == icons.length())
+    {
+      //end of smily reached, insert image here
+      m_node[sym].m_file = filename;
+    }
+    else
+    {
+      m_node[sym].m_file = "";
+      m_node[sym].mp_child->insert(icons, filename, depth+1);
+    }
+  }
+}
+
+
+//
+//Check whether at a given position in a message a smily can be found. 
+//
+QString EmotNode::searchSmilyInTree(QString msg, int spos, int &endPos)
+{
+  QChar curSym = msg.at(spos);
+  node_iter_t iter = m_node.find(curSym);
+  if (iter != m_node.end())
+  {
+    //found symbol in node, so go deeper
+    QString s = m_node[curSym].mp_child->searchSmilyInTree(msg, spos+1, 
endPos);
+    if (s == NULL) 
+    {
+      //is here any file for the smily?
+      if (m_node[curSym].m_file.length() != 0)
+      {
+        endPos = spos;
+        return m_node[curSym].m_file;
+      }
+    }
+    else
+    {
+      return s;
+    }
+  }
+  return NULL;
+}
+
+
+/*
+ * Replace all smilies in a message and return the resulting message.
+ */
+QString EmotNode::replaceSmilies(QString msg)
+{
+  int pos = 0;
+  int tmppos;
+  int max = msg.length()+1;
+  int spos = -1;            //smallest position
+  int nextToCopyPos = 0;    //saves the next position to copy from msg to 
newMsg
+  QString contentSafe;
+  QString newMsg = "";
+  
+  contentSafe = createSpecialContentSafe(msg);
+  
+  while (spos != max)
+  {
+    spos = max;
+    //search for the first possible smily symbol
+    for ( node_iter_t i = m_node.begin(); i != m_node.end(); ++i)
+    {
+      tmppos = contentSafe.find(i->first, pos);
+      if (tmppos != -1 && tmppos < spos)
+      {
+        //found a position, remember it and try to find one more left
+        spos = tmppos;
+      }
+    }
+    if (spos != max)
+    {
+      //check if at this position is a smily in msg
+      int endPos = -1;
+      QString f = searchSmilyInTree(contentSafe, spos, endPos);
+      if (f != NULL)
+      {
+        //replace
+        newMsg.append(msg.mid(nextToCopyPos, spos-nextToCopyPos) + " <img 
src=\"" + f + "\"/>&nbsp;");
+        nextToCopyPos = endPos + 1;
+        pos = endPos + 1;
+      }
+      else
+      {
+        //it's beginning with a smily symbol but it's no smily
+        pos = spos + 1;
+      }
+    }
+  }
+    
+  if (nextToCopyPos != contentSafe.length())
+  {
+    newMsg.append(msg.right(contentSafe.length() - nextToCopyPos));
+  }
+
+  return newMsg;
+}
+
+
+/*
+ * Parse the msg for content which should not be replaced with smilies
+ */
+QString EmotNode::createSpecialContentSafe(QString msg)
+{
+  QString contentSafe = msg;
+  QString fill;
+  int bpos = 0;
+  int epos = 0;
+  QRegExp 
reURL("(\\b|^)((https?|ftp)://([-a-z0-9]+(:[-a-z0-9]+)?@)?[-a-z0-9.]+[-a-z0-9](:[0-9]+)?(/([-a-z0-9%{}|\\\\^~`;/?:@=&$_.+!*'(),]|\\[|\\])*)?)");
+  reURL.setMinimal(false);
+  reURL.setCaseSensitive(false);
+  do
+  {
+    bpos = contentSafe.find(reURL);
+    if (bpos != -1)
+    {
+      //find end position
+      epos = bpos + reURL.cap(2).length();
+      //replace content area with spaces (mark as content area)
+      contentSafe = contentSafe.replace(bpos, epos - bpos, fill.fill(' ', epos 
- bpos));
+    }
+  }
+  while (bpos != -1);
+  
+  return contentSafe;
+}
+
+
+EmotNode::~EmotNode()
+{
+  for ( node_iter_t i = m_node.begin(); i != m_node.end(); ++i)
+  {
+    delete(i->second.mp_child);
+  }
+}
+
+

Reply via email to