Code

Extensions. Fix for Bug #668895 (Extensions with <check> tags fail to load).
[inkscape.git] / src / jabber_whiteboard / message-utilities.cpp
1 /**
2  * Message generation utilities
3  * 
4  * Authors:
5  * David Yip <yipdw@rose-hulman.edu>
6  * Jonas Collaros, Stephen Montgomery
7  *
8  * Copyright (c) 2004-2005 Authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
13 #include <glibmm/i18n.h>
15 #include "util/share.h"
16 #include "util/list.h"
17 #include "util/ucompose.hpp"
19 #include "xml/node.h"
20 #include "xml/attribute-record.h"
21 #include "xml/repr.h"
23 #include "jabber_whiteboard/defines.h"
24 #include "jabber_whiteboard/node-utilities.h"
25 #include "jabber_whiteboard/message-utilities.h"
26 #include "jabber_whiteboard/node-tracker.h"
28 #include <iostream>
30 namespace Inkscape {
32 namespace Whiteboard {
34 // This method can be instructed to not build a message string but only collect nodes that _would_ be transmitted
35 // and subsequently added to the tracker.  This can be useful in the case where an Inkboard user is the only one
36 // in a chatroom and therefore needs to fill out the node tracker, but does not need to build the message string.
37 // This can be controlled with the only_collect_nodes flag, which will only create pointers to new XML::Nodes 
38 // in the maps referenced by newidsbuf and newnodesbuf.  Passing NULL as the message buffer has the same effect.
39 //
40 // only_collect_nodes defaults to false because most invocations of this method also use the message string.
42 Glib::ustring
43 MessageUtilities::objectToString(Inkscape::XML::Node *element)
44 {
45     if(element->type() == Inkscape::XML::TEXT_NODE)
46         return String::ucompose("<text>%1</text>",element->content());
48     Glib::ustring attributes;
50     for ( Inkscape::Util::List<Inkscape::XML::AttributeRecord const> 
51         iter = element->attributeList() ; iter ; ++iter )
52     {
53         attributes.append(g_quark_to_string(iter->key));
54         attributes.append("=\"");
55         attributes.append(iter->value);
56         attributes.append("\" ");
57     }
59     return String::ucompose("<%1 %2/>",element->name(),attributes);
60 }
61 /*
62 void
63 MessageUtilities::newObjectMessage(Glib::ustring &msgbuf, 
64                        KeyNodeTable& newnodesbuf,
65                        NewChildObjectMessageList& childmsgbuf, 
66                        XMLNodeTracker* xmt, 
67                        Inkscape::XML::Node const* node,
68                        bool only_collect_nodes,
69                        bool collect_children)
70 {
71         // Initialize pointers
72         Glib::ustring id, refid, parentid;
74         gchar const* name = NULL;
75         XML::Node* parent = NULL;
76         XML::Node* ref = NULL;
78         bool only_add_children = false;
80         //g_log(NULL, G_LOG_LEVEL_DEBUG, "newObjectMessage: processing node %p of type %s", node, NodeUtilities::nodeTypeToString(*node).data());
82         if (node != NULL) {
83                 parent = sp_repr_parent(node);
84                 if (parent != NULL) {
85                         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for parent node %p (on node %p)", parent, node);
86                         parentid = NodeUtilities::findNodeID(*parent, xmt, newnodesbuf);
87                         if (parentid.empty()) {
88                                 g_warning("Parent %p is not being tracked, creating new ID", parent);
89                                 parentid = xmt->generateKey();
90                                 newnodesbuf.put(parentid, parent);
91                         }
93                         if ( node != parent->firstChild() && parent != NULL ) {
94                                 ref = parent->firstChild();
95                                 while (ref->next() != node) {
96                                         ref = ref->next();
97                                 }
98                         }       
99                 }
101                 if (ref != NULL) {
102                         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Attempting to find ID for ref node %p (on %p)", ref, node);
103                         refid = NodeUtilities::findNodeID(*ref, xmt, newnodesbuf);
104                         if (refid.empty() && ref != NULL) {
105                                 g_warning("Ref %p is not being tracked, creating new ID", ref);
106                                 refid = xmt->generateKey();
107                                 newnodesbuf.put(refid, ref);
108                         }
109                 }
111                 name = static_cast< gchar const* >(node->name());
112         }
114         // Generate an id for this object and append it onto the list, if 
115         // it's not already in the tracker
116         if (!xmt->isSpecialNode(node->name())) {
117                 if (!xmt->isTracking(*node)) {
118                         id = xmt->generateKey();        
119                         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Inserting %p with id %s", node, id.c_str());
120                         newnodesbuf.put(id, node);
121                 } else {
122                         id = xmt->get(*node);
123                 //g_log(NULL, G_LOG_LEVEL_DEBUG, "Found id %s for node %p; not inserting into new nodes buffers.", id.c_str(), node);
124                 }
125         } else {
126                 //g_log(NULL, G_LOG_LEVEL_DEBUG, "Processing special node; not generating key");
127                 id = xmt->get(*node);
128                 if (id.empty()) {
129                         g_warning("Node %p (name %s) is a special node, but it could not be found in the node tracker (possible unexpected duplicate?)  Generating unique ID anyway.", node, node->name());
130                         id = xmt->generateKey();
131                         newnodesbuf.put(id, node);
132                 }
133                 only_add_children = true;
134         }
136         // If we're only adding children (i.e. this is a special node)
137         // don't process the given node.
138         if( !only_add_children && !id.empty() && msgbuf != NULL && !only_collect_nodes ) {
139                 // <MESSAGE_NEWOBJ>
140                 msgbuf = msgbuf + "<" + MESSAGE_NEWOBJ + ">";
142                 // <MESSAGE_PARENT>
143                 msgbuf = msgbuf + "<" + MESSAGE_PARENT + ">";
145                 if(!parentid.empty()) {
146                         msgbuf += parentid;
147                 }
149                 // </MESSAGE_NEWOBJ><MESSAGE_CHILD>id</MESSAGE_CHILD>
150                 msgbuf = msgbuf + "</" + MESSAGE_PARENT + ">";
152                 msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">";
153                 msgbuf += id;
155                 msgbuf = msgbuf + "</" + MESSAGE_CHILD + ">";
157                 if(!refid.empty()) {
158                         // <MESSAGE_REF>refid</MESSAGE_REF>
159                         msgbuf = msgbuf + "<" + MESSAGE_REF + ">";
160                         
161                         msgbuf += refid;
163                         msgbuf = msgbuf + "</" + MESSAGE_REF + ">";
164                 }
166                 // <MESSAGE_NODETYPE>*node.type()</MESSAGE_NODETYPE>
167                 msgbuf = msgbuf + "<" + MESSAGE_NODETYPE + ">" + NodeUtilities::nodeTypeToString(*node);
168                 msgbuf = msgbuf + "</" + MESSAGE_NODETYPE + ">";
170                 if (node->content() != NULL) {
171                         // <MESSAGE_CONTENT>node->content()</MESSAGE_CONTENT>
172                         msgbuf = msgbuf + "<" + MESSAGE_CONTENT + ">" + node->content();
173                         msgbuf = msgbuf + "</" + MESSAGE_CONTENT + ">";
174                 }
176                 // <MESSAGE_NAME>name</MESSAGE_NAME>
177                 msgbuf = msgbuf + "<" + MESSAGE_NAME + ">";
179                 if( name != NULL )
180                         msgbuf += name;
182                 msgbuf = msgbuf + "</" + MESSAGE_NAME + ">";
184                 // </MESSAGE_NEWOBJ>
185                 msgbuf = msgbuf + "</" + MESSAGE_NEWOBJ + ">";
186         } else if (id.empty()) {
187                 // if ID is NULL, then we have a real problem -- we were not able to find a key
188                 // nor generate one.  The only thing we can really do here is abort, since we have
189                 // no way to let the other client(s) uniquely identify this object.
190                 g_warning(_("ID for new object is NULL even after generation and lookup attempts: the new object will NOT be sent, nor will any of its child objects!"));
191                 return;
192         } else {
194         }
196         //g_log(NULL, G_LOG_LEVEL_DEBUG, "Generated message");
198         if (!only_collect_nodes && msgbuf != NULL && !id.empty()) {
199                 // Collect new object's attributes and append them onto the msgbuf
200                 Inkscape::Util::List<Inkscape::XML::AttributeRecord const> attrlist = node->attributeList();
202                 for(; attrlist; attrlist++) {
203                         MessageUtilities::objectChangeMessage(msgbuf,
204                          xmt, id, g_quark_to_string(attrlist->key),
205                           NULL, attrlist->value, false);
206                 }
207         }
209         if (!only_collect_nodes)
210                 childmsgbuf.push_back(msgbuf);
212         if (!id.empty() && collect_children) {
213                 Glib::ustring childbuf;
214                 // Collect any child objects of this new object
215                 for ( Inkscape::XML::Node const *child = node->firstChild(); child != NULL; child = child->next() ) {
216                         childbuf.clear();
217                         MessageUtilities::newObjectMessage(childbuf,
218                         newnodesbuf, childmsgbuf, xmt, child, only_collect_nodes);
219                         if (!only_collect_nodes) {
220                                 // we're recursing down the tree, so we're picking up child nodes first
221                                 // and parents afterwards
222 //                              childmsgbuf.push_front(childbuf);
223                         }
225                 }
226         }
229 void
230 MessageUtilities::objectChangeMessage(Glib::ustring &msgbuf, 
231                                     XMLNodeTracker* xmt, 
232                                     const Glib::ustring &id, 
233                                     gchar const* key, 
234                                     gchar const* oldval, 
235                                     gchar const* newval, 
236                                     bool is_interactive)
238     // Construct message
240     // <MESSAGE_CHANGE><MESSAGE_ID>id</MESSAGE_ID>
241     msgbuf = msgbuf + "<" + MESSAGE_CHANGE + ">";
242     msgbuf = msgbuf + "<" + MESSAGE_ID + ">";
243     msgbuf += id;
244     msgbuf = msgbuf + "</" + MESSAGE_ID + ">";
246     // <MESSAGE_KEY>key</MESSAGE_KEY>
247     msgbuf = msgbuf + "<" + MESSAGE_KEY + ">";
248     if (key != NULL) {
249             msgbuf += key;
250     }
251     msgbuf = msgbuf + "</" + MESSAGE_KEY + ">";
253     // <MESSAGE_OLDVAL>oldval</MESSAGE_OLDVAL>
254     msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
255     if (oldval != NULL) {
256             msgbuf += oldval;
257     }
258     msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
260     // <MESSAGE_NEWVAL>newval</MESSAGE_NEWVAL>
261     msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
262     if (newval != NULL) {
263             msgbuf += newval;
264     }
265     msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
267     // <MESSAGE_ISINTERACTIVE>is_interactive</MESSAGE_ISINTERACTIVE>
268     msgbuf = msgbuf + "<" + MESSAGE_ISINTERACTIVE + ">";
269     if (is_interactive) {
270             msgbuf += "true";
271     } else {
272             msgbuf += "false";
273     }
274     msgbuf = msgbuf + "</" + MESSAGE_ISINTERACTIVE + ">";
276     // </MESSAGE_CHANGE>
277     msgbuf = msgbuf + "</" + MESSAGE_CHANGE + ">";
280 void
281 MessageUtilities::objectDeleteMessage(Glib::ustring &msgbuf, 
282                             XMLNodeTracker* xmt,
283                             Inkscape::XML::Node const& parent,
284                             Inkscape::XML::Node const& child,
285                             Inkscape::XML::Node const* prev)
287     /*
288     gchar const* parentid = NULL;
289     gchar const* previd = NULL;
290     gchar const* childid = NULL;
292     childid = child.attribute("id");
293     parentid = parent.attribute("id");
294     if (prev != NULL) {
295             previd = prev->attribute("id");
296     }
298     Glib::ustring parentid, previd, childid;
300     childid = xmt->get(child);
301     parentid = xmt->get(parent);
302     previd = xmt->get(*prev);
304     if (childid.empty())
305         return;
306             
307  
308      // <MESSAGE_DELETE><MESSAGE_PARENT>parentid</MESSAGE_PARENT>
309      msgbuf = msgbuf + "<" + MESSAGE_DELETE + ">" + "<" + MESSAGE_PARENT + ">";
310      if (!parentid.empty()) {
311              msgbuf += parentid;
312      }
313      msgbuf = msgbuf + "</" + MESSAGE_PARENT + ">";
315      // <MESSAGE_CHILD>childid</MESSAGE_CHILD>
316      msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">";
317      if (!childid.empty()) {
318              msgbuf += childid;
319      }
320      msgbuf = msgbuf + "</" + MESSAGE_CHILD + ">";
322      // <MESSAGE_REF>previd</MESSAGE_REF>
323      msgbuf = msgbuf + "<" + MESSAGE_REF + ">";
324      if (!previd.empty()) {
325              msgbuf += previd;
326      }
327      msgbuf = msgbuf + "</" + MESSAGE_REF + ">";
329      // </MESSAGE_DELETE>
330      msgbuf = msgbuf + "</" + MESSAGE_DELETE + ">";
333 void
334 MessageUtilities::contentChangeMessage(Glib::ustring& msgbuf, 
335                        const Glib::ustring &nodeid, 
336                        Util::ptr_shared<char> old_value,
337                        Util::ptr_shared<char> new_value)
339     if (nodeid.empty())
340         return;
341         
342      // <MESSAGE_NODECONTENT>
343      msgbuf = msgbuf + "<" + MESSAGE_NODECONTENT + ">";
345      // <MESSAGE_ID>nodeid</MESSAGE_ID>
346      msgbuf = msgbuf + "<" + MESSAGE_ID + ">";
347      msgbuf += nodeid;
348      msgbuf = msgbuf + "</" + MESSAGE_ID + ">";
350      // <MESSAGE_OLDVAL>old_value</MESSAGE_OLDVAL>
351      msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
352      msgbuf += old_value.pointer();
353      msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
355      // <MESSAGE_NEWVAL>new_value</MESSAGE_NEWVAL>
356      msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
357      msgbuf += new_value.pointer();
358      msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
360      // </MESSAGE_NODECONTENT>
361      msgbuf = msgbuf + "</" + MESSAGE_NODECONTENT + ">";
364 void
365 MessageUtilities::childOrderChangeMessage(Glib::ustring& msgbuf, 
366                           const Glib::ustring &childid, 
367                           const Glib::ustring &oldprevid, 
368                           const Glib::ustring &newprevid)
370     if (childid.empty())
371         return;
372         
373     // <MESSAGE_ORDERCHANGE>
374     msgbuf = msgbuf + "<" + MESSAGE_ORDERCHANGE + ">";
376     // <MESSAGE_ID>nodeid</MESSAGE_ID>
377     msgbuf = msgbuf + "<" + MESSAGE_CHILD + ">";
378     msgbuf += childid;
379     msgbuf = msgbuf + "</" + MESSAGE_CHILD + ">";
381     // <MESSAGE_OLDVAL>oldprevid</MESSAGE_OLDVAL>
382     /*
383     msgbuf = msgbuf + "<" + MESSAGE_OLDVAL + ">";
384     msgbuf += (*oldprevid);
385     msgbuf = msgbuf + "</" + MESSAGE_OLDVAL + ">";
386     
388     // <MESSAGE_NEWVAL>newprevid</MESSAGE_NEWVAL>
389     msgbuf = msgbuf + "<" + MESSAGE_NEWVAL + ">";
390     msgbuf += newprevid;
391     msgbuf = msgbuf + "</" + MESSAGE_NEWVAL + ">";
393     // </MESSAGE_ORDERCHANGE>
394     msgbuf = msgbuf + "</" + MESSAGE_ORDERCHANGE + ">";
399 bool
400 MessageUtilities::getFirstMessageTag(struct Node& buf, const Glib::ustring &msg)
402     if (msg.empty())
403         return false;
405     // See if we have a valid start tag, i.e. < ... >.  If we do,
406     // continue; if not, stop and return NULL.
407     //
408     // find_first_of returns ULONG_MAX when it cannot find the first
409     // instance of the given character.
411     Glib::ustring::size_type startDelim = msg.find_first_of('<');
412     if (startDelim != ULONG_MAX) {
413             Glib::ustring::size_type endDelim = msg.find_first_of('>');
414             if (endDelim != ULONG_MAX) {
415                     if (endDelim > startDelim) {
416                             buf.tag = msg.substr(startDelim+1, (endDelim-startDelim)-1);
417                             if (buf.tag.find_first_of('/') == ULONG_MAX) { // start tags should not be end tags
420                                     // construct end tag (</buf.data>)
421                                     Glib::ustring endTag(buf.tag);
422                                     endTag.insert(0, "/");
424                                     Glib::ustring::size_type endTagLoc = msg.find(endTag, endDelim);
425                                     if (endTagLoc != ULONG_MAX) {
426                                             buf.data = msg.substr(endDelim+1, ((endTagLoc - 1) - (endDelim + 1)));
427                                             buf.next_pos = endTagLoc + endTag.length() + 1;
429                                             return true;
430                                     }
431                             }
432                     }
433             }
434     }
436     return false;
439 bool
440 MessageUtilities::findTag(struct Node& buf, const Glib::ustring &msg)
442     if (msg.empty())
443         return false;
445     // Read desired tag type out of buffer, and append
446     // < > to it 
448     Glib::ustring searchterm("<");
449     searchterm += buf.tag;
450     searchterm + ">";
452     Glib::ustring::size_type tagStart = msg.find(searchterm, 0);
453     if (tagStart != ULONG_MAX) {
454             // Find ending tag starting at the point at the end of
455             // the start tag.
456             searchterm.insert(1, "/");
457             Glib::ustring::size_type tagEnd = msg.find(searchterm, tagStart + searchterm.length());
458             if (tagEnd != ULONG_MAX) {
459                     Glib::ustring::size_type start = tagStart + searchterm.length();
460                     buf.data = msg.substr(start, tagEnd - start);
461                     return true;
462             }
463     }
464     return false;
467 Glib::ustring
468 MessageUtilities::makeTagWithContent(const Glib::ustring &tagname,
469                                      const Glib::ustring &content)
471     Glib::ustring buf = "<" + tagname + ">";
472     buf += content;
473     buf += "</" + tagname + ">";
474     return buf;
476 */
484 /*
485   Local Variables:
486   mode:c++
487   c-file-style:"stroustrup"
488   c-file-offsets:((innamespace . 0)(inline-open . 0))
489   indent-tabs-mode:nil
490   fill-column:99
491   End:
492 */
493 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :