Author: ArcRiley
Date: 2009-02-25 04:55:09 -0500 (Wed, 25 Feb 2009)
New Revision: 1516

Modified:
   trunk/concordance/include/concordance.h
   trunk/concordance/include/concordance.sockets.h
   trunk/concordance/src/sockets/Client.c
   trunk/concordance/src/sockets/Socket.c
Log:
continued refactoring work

Modified: trunk/concordance/include/concordance.h
===================================================================
--- trunk/concordance/include/concordance.h     2009-02-22 22:27:53 UTC (rev 
1515)
+++ trunk/concordance/include/concordance.h     2009-02-25 09:55:09 UTC (rev 
1516)
@@ -44,4 +44,8 @@
   GThread*         threadid;             /* thread ID for mainloop thread */
 } concordGlobals;
 
+typedef struct {
+  guint                 major;
+  guint                 minor;
+} concordVersion;
 #endif

Modified: trunk/concordance/include/concordance.sockets.h
===================================================================
--- trunk/concordance/include/concordance.sockets.h     2009-02-22 22:27:53 UTC 
(rev 1515)
+++ trunk/concordance/include/concordance.sockets.h     2009-02-25 09:55:09 UTC 
(rev 1516)
@@ -28,7 +28,7 @@
 /* concordance.sockets.Socket definition */
 typedef struct {
   PyTypeObject          base;
-  gboolean           (* _listenNew ) (GIOChannel*, GIOCondition, gpointer);
+  gboolean           (* _gioNew )      (GIOChannel*, GIOCondition, gpointer);
 } socketsSocket_TypeObject;
 extern socketsSocket_TypeObject socketsSocket_Type;
 typedef struct {
@@ -45,7 +45,10 @@
 /* concordance.sockets.Client definition */
 typedef struct {
   PyTypeObject          base;
-  gboolean           (* _listenNew ) (GIOChannel*, GIOCondition, gpointer);
+  gboolean           (* _gioNew )      (GIOChannel*, GIOCondition, gpointer);
+  gboolean           (* _gioRead )     (GIOChannel*, GIOCondition, gpointer);
+  gboolean           (* _gioWrite )    (GIOChannel*, GIOCondition, gpointer);
+  
 } socketsClient_TypeObject;
 extern socketsClient_TypeObject  socketsClient_Type;
 typedef struct {
@@ -59,4 +62,30 @@
 } socketsClient_Object;
 
 
+enum socketsClient_State {
+  CONCORD_E_CLOSE = 0,              /* close </stream>           */
+  CONCORD_E_OPEN,                   /* inside <stream>           */
+  CONCORD_E_CLIENT,                 /* <iq> <message> <presence> */
+  CONCORD_E_SASL,                   /* <auth> <response>         */
+};
+
+
+typedef struct {
+  socketsClient_Object  self;          /* the listening socket this belongs */
+  PyObject*             node;          /* Node object for this or NULL */
+  GMutex*               lock;          /* Mutex for self test/add/remove */
+  GIOChannel*           chan;          /* Glib IO channel for this session */
+  Gsasl_session*        sctx;          /* gsasl session context */
+  XML_Parser            pars;          /* expat parser for this session */
+  gchar                 host[256];     /* verified hostname or NULL */
+  concordVersion        vers;          /* XMPP major.minor version */
+  gboolean              tls;           /* flag for whether tls is enabled */
+  gint                  state;         /* current session state */
+  gint                  depth;         /* parser element depth */
+  GString*              wbuff;         /* write buffer */
+  GString*              ebuff;         /* element buffer */
+  GString*              efrom;         /* JID of origin */
+  GString*              eto;           /* JID of destination */
+} socketsClient_Data;
+
 #endif

Modified: trunk/concordance/src/sockets/Client.c
===================================================================
--- trunk/concordance/src/sockets/Client.c      2009-02-22 22:27:53 UTC (rev 
1515)
+++ trunk/concordance/src/sockets/Client.c      2009-02-25 09:55:09 UTC (rev 
1516)
@@ -25,14 +25,23 @@
 cdef class Socket :                                                       \*/
   static char socketsClient_Doc[] = "Test";
 
+  /*
+  #
+  ###########################################################################
+  #
+  # GIOChannel Callbacks
+  #                                                                        */
+
   static gboolean
-  _listenNew(GIOChannel* channel, GIOCondition condition, gpointer s) {   /*\
+  _gioNew(GIOChannel* channel, GIOCondition condition, gpointer s) {      /*\
     cdef :                                                                \*/
       socketsSocket_Object*      self = (socketsSocket_Object*) s;
       gint                       socket;
       struct sockaddr            addr;
       guint                      addrlen = sizeof(addr);
-
+      socketsClient_Data*        session;
+      GSource*                   source;
+    
     /* accept new connection, return if we fail to connect
 
        int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
@@ -43,17 +52,674 @@
       return TRUE;
     }
 
-    /* this is a generic Socket object, just close incoming connections */
-    close(socket);
+    /* create new session, create lock, and store the pointer to parent Core
+
+       gpointer         g_malloc                 (gsize n_bytes);
+       GMutex *         g_mutex_new              ();
+    */
+    session = g_malloc(sizeof(socketsClient_Data));
+    session->self = self;
+    session->node = NULL;
+    session->lock = g_mutex_new();
+
+    /* create a new channel using an OS-dependent function
+
+       GIOChannel*      g_io_channel_win32_new_fd     (gint fd);
+       GIOChannel*      g_io_channel_unix_new         (gint fd);
+    */
+    #ifdef MS_WINDOWS
+      session->chan = g_io_channel_win32_new_socket(socket);
+    #else
+      session->chan = g_io_channel_unix_new(socket);
+    #endif
+
+    /* add a channel to our context watch
+
+       Note that this function is a replacement for g_io_add_watch() which
+       uses our own context rather than the default context.
+
+       GSource*         g_io_create_watch        (GIOChannel *channel,
+                                                  GIOCondition condition);
+       void             g_source_set_callback    (GSource *source,
+                                                  GSourceFunc func,
+                                                  gpointer data,
+                                                  GDestroyNotify notify);
+       guint            g_source_attach          (GSource *source,
+                                                  GMainContext *context);
+    */
+    source = g_io_create_watch(session->chan, G_IO_IN | G_IO_HUP);
+    g_source_set_callback(source, (GSourceFunc)
+                          ((socketsClient_TypeObject*) s->ob_type)->_gioRead,
+                          (gpointer) session, NULL);
+    g_source_attach(source, self->context);
+    g_source_unref(source);
+
+    /* specify "raw" channel by turning off encoding and buffering
+    
+       GIOStatus        g_io_channel_set_encoding(GIOChannel *channel,
+                                                  const gchar *encoding,
+                                                  GError **error);
+       void             g_io_channel_set_buffered(GIOChannel *channel,
+                                                  gboolean buffered);
+    */
+    g_io_channel_set_encoding(session->chan, NULL, NULL);
+    g_io_channel_set_buffered(session->chan, FALSE);
+
+    /* initialize session strings
+
+       GString*         g_string_new             (const gchar *init);
+    */
+    session->wbuff = g_string_new("");      /* write buffer */
+    session->ebuff = g_string_new("");      /* element buffer */
+    session->efrom = g_string_new("");      /* element origin */
+    session->eto   = g_string_new("");      /* element destination */
+
+    /* initialize session state */
+    session->state = CONCORD_E_OPEN;
+    session->depth = 0;
+
+    /* create the XML parser for this session
+
+       XML_Parser       XML_ParserCreateNS       (const XML_Char *encoding
+                                                  XML_Char sep);
+       void             XML_SetUserData          (XML_Parser parser,
+                                                  void *userData);
+       void             XML_SetElementHandler    (XML_Parser parser,
+                                                  XML_StartElementHandler 
start,
+                                                  XML_EndElementHandler end);
+       void             XML_SetCharacterDataHandler
+                                                 (XML_Parser parser,
+                                                  XML_CharacterDataHandler);
+    */
+    session->pars = XML_ParserCreateNS(NULL, 32); /* space is separator*/
+    XML_SetUserData(session->pars, session);
+    XML_SetElementHandler(session->pars, _xmlStart, _xmlEnd);
+    XML_SetCharacterDataHandler(session->pars, _xmlCharData);
+
+    /* lookup hostname - currently unimplemented */
         
     /* return true so GMainLoop will continue watching this channel */
     return TRUE;
   }
 
+  static gboolean
+  _gioRead(GIOChannel* channel, GIOCondition condition, gpointer data) {  /*\
+    cdef :                                                                \*/
+      socketsClient_Data*   session = (socketsClient_Data*) data;
+      GIOStatus             status;
+      gchar                 buff[4096];
+      guint                 buff_len = 0;
+
+    if (condition == G_IO_IN) {
+
+      /* read channel to parser
+
+         GIOStatus      g_io_channel_read_chars  (GIOChannel *channel,
+                                                  gchar *buf,
+                                                  gsize count,
+                                                  gsize *bytes_read,
+                                                  GError **error);
+         XML_Status     XML_Parse                (XML_Parser parser,
+                                                  const char *s,
+                                                  int len,
+                                                  int isFinal);
+      */
+      status = g_io_channel_read_chars(channel, buff, 4096, &buff_len, NULL);
+      if (status == G_IO_STATUS_NORMAL && buff_len > 0) {
+        /* parse XML data
+
+           XML_Parse will execute the appropriate callback(s) found in the
+           "XML Handlers" section below.  If the stream has been closed
+           the session->state will be reset to CONCORD_E_CLOSE (== FALSE)
+           to indicate that the session needs to get wrapped up.
+        */
+        if (XML_Parse(session->pars, buff, buff_len, FALSE) && session->state)
+          /* return true so GMainLoop will continue watching this channel */
+          return TRUE;
+      }
+    }
+
+    /* G_IO_EOF, read EOF, or an unknown channel error has occured
+
+       GIOStatus        g_io_channel_shutdown    (GIOChannel *channel,
+                                                  gboolean flush,
+                                                  GError **err);
+    */
+    g_io_channel_shutdown(channel, FALSE, NULL);
+
+
+    /* close out parser cleanly
+
+       void             XML_ParserFree           (XML_Parser parser);
+    */
+    XML_Parse(session->pars, NULL, 0, TRUE);
+    XML_ParserFree(session->pars);
+
+
+    /* return false so GMainLoop will stop watching this channel */
+    return FALSE;
+  }
+
+
+  static gboolean
+  _gioWrite(GIOChannel* channel, GIOCondition condition, gpointer data) { /*\
+    cdef :                                                                \*/
+      socketsClient_Data*   session = (socketsClient_Data*) data;
+      gint                  sent;
+
+    /* send as much data as the channel will take
+
+       GIOStatus        g_io_channel_write_chars (GIOChannel *channel,
+                                                  const gchar *buf,
+                                                  gssize count,
+                                                  gsize *bytes_written,
+                                                  GError **error);
+    */
+    g_io_channel_write_chars(channel, session->wbuff->str, session->wbuff->len,
+                             &sent, NULL);
+
+    /* erase what we've just written
+
+       GString*         g_string_erase           (GString *string,
+                                                  gssize pos,
+                                                  gssize len);
+    */
+    session->wbuff = g_string_erase(session->wbuff, 0, sent);
+
+    /* keep this event alive if there's more in the buffer to write */
+    return (session->wbuff->len != 0);
+  }
+
   /*
   #
   ###########################################################################
   #
+  # Element responses
+  #                                                                        */
+  static void
+  _reply_streamError(socketsClient_Data* session, gchar* err, gchar* t) { /*\
+    cdef :                                                                \*/
+      GString*              buff;
+
+    /* initialize response buffer
+
+       GString*         g_string_new             (const gchar *init);
+    */
+    buff = g_string_new("");
+
+    /* printf error and send it
+
+       void             g_string_printf          (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+    */
+    g_string_printf(buff,
+                    "<stream:error><%s"
+                    " xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
+                    "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>"
+                    "%s</text></stream:error></stream:stream>",
+                    err, t);
+    _send(session, buff->str, buff->len);
+
+    /* CLOSE the session state so the socket will close properly */
+    session->state = CONCORD_E_CLOSE;
+
+    /* free response buffer before returning
+
+       gchar*           g_string_free            (GString *string,
+                                                  gboolean free_segment);
+    */
+    g_string_free(buff, TRUE);
+  }
+
+
+  static void
+  _reply_stream(concordSession_Data* session, gchar* version) {           /*\
+    cdef :                                                                \*/
+      socketsClient_Object* self = session->self;
+      GString*              buff;
+      guint                 major, minor;
+      gchar**               versions;
+      gchar*                error = NULL;
+
+
+    /* initialize response buffer
+
+       GString*         g_string_new             (const gchar *init);
+    */
+    buff = g_string_new("");
+
+    /* init <stream:stream>, <stream:features>, and <mechanisms>
+
+       void             g_string_printf          (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+    */
+    g_string_printf(buff,
+                    "<?xml version='1.0' encoding='UTF-8'?>"
+                    "<stream:stream xmlns='jabber:client'"
+                    " xmlns:stream='http://etherx.jabber.org/streams'"
+                    " from='%s' id='%s'",
+                    "selket.apogean.org", "concordance-1");
+
+    /* Parse version:
+       * NULL is passed, meaning the version attribute was not found, so:
+         * version is ""
+         * error is "<unsupported-version/>"
+
+       * "1.*" is passed, meaning a version we support, so:
+         * version is " version='1.0'"
+         * error is NULL
+
+       * "2.0" or greater is passed, meaning a version we do not support, so:
+         * version is " version='1.0'"
+         * error is "<unsupported-version/>"
+
+       * something unparsable is passed, so:
+         * version is " version='1.0'"
+         * error is "<bad-format/>"
+    */
+    if (version == NULL) {
+      *error = "<unsupported-version/>";
+      buff = g_string_append(buff, ">");
+    }
+    else if (g_strrstr(version, ".") != NULL) {
+      versions = g_strsplit(version, ".", 2); // Separate Major from minor
+      if (g_strv_length(versions) == 2 &&
+          concordStrToUI(versions[0], &major) &&
+          concordStrToUI(versions[1], &minor)) {
+        g_strfreev(versions);
+        if (major == 1) {
+          buff = g_string_append(buff, " version='1.0'>");
+          
+        }
+        else {
+          *error = "<unsupported-version/>";
+          buff = g_string_append(buff, " version='1.0'>");
+        }
+      }
+      g_strfreev(versions);
+    }
+    else {
+      *error = "<bad-format/>";
+      buff = g_string_append(buff, " version='1.0'>");
+    }
+
+    if (error) {
+      /* a stream error has taken place!
+
+         send the <stream:stream> element we have so far, free the buffer,
+         then pass control over concordSession_reply_streamError for the rest.
+      */
+      _send(session, buff->str, buff->len);
+      g_string_free(buff, TRUE);
+      _reply_streamError(session, error, "");
+      return;
+    }
+
+    /* open stream:features and mechanisms element */
+    buff = g_string_append(buff, "<stream:features><mechanisms"
+                                 " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>");
+
+    /* add a <mechanism> element for each supported SASL mechanism
+
+       int              gsasl_server_support_p   (Gsasl* ctx,
+                                                  const char* name);
+       GString*         g_string_append          (GString *string,
+                                                  const gchar *val);
+    */
+    if (gsasl_server_support_p(core->saslCntx, "DIGEST-MD5"))
+      buff = g_string_append(buff, "<mechanism>DIGEST-MD5</mechanism>");
+    if (gsasl_server_support_p(core->saslCntx, "PLAIN"))
+      buff = g_string_append(buff, "<mechanism>PLAIN</mechanism>");
+
+    /* close <mechanisms> and <stream:features>, then send buffer */
+    buff = g_string_append(buff, "</mechanisms></stream:features>");
+    _send(session, buff->str, buff->len);
+
+    /* free response buffer before returning
+
+       gchar*           g_string_free            (GString *string,
+                                                  gboolean free_segment);
+    */
+    g_string_free(buff, TRUE);
+  }
+
+
+  static void
+  _reply_saslChallenge(concordSession_Data* session) {                    /*\
+    cdef :                                                                \*/
+
+
+    return;
+    /*
+       gchar*           g_base64_encode          (const guchar *data,
+                                                  gsize len);
+    */
+
+
+
+    /*g_string_printf(buff,
+                    "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+                    "%s</challenge>", ""); */
+  }
+
+  static void
+  _reply_saslFailure(socketsClient_Data* session, gchar* failure) {       /*\
+    cdef :                                                                \*/
+      GString* buff;
+
+    /* printf failure to a GString, then send it
+
+       GString*         g_string_new             (const gchar *init);
+       void             g_string_printf          (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+       gchar*           g_string_free            (GString *string,
+                                                  gboolean free_segment);
+    */
+    buff = g_string_new("");
+    g_string_printf(buff, "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
+                          "%s</failure>", failure);
+    concordSession_send(session, buff->str, buff->len);
+    g_string_free(buff, TRUE);
+  }
+
+  /*
+  #
+  ###########################################################################
+  #
+  # XML Callbacks
+  #
+                                                                           */
+  static gchar*
+  _xmlFindAttr(const gchar** attrs, const gchar* key) {                   /*\
+    cdef :                                                                \*/
+      gint i;
+
+    for (i = 0; attrs[i]; i += 2) {
+      /* compare attribute strings case insensitive
+
+         gint           g_ascii_strcasecmp       (const gchar *s1,
+                                                  const gchar *s2);
+      */
+      if (g_ascii_strcasecmp(attrs[i], key) == 0)
+        break;
+    }
+
+    /* return either the found attribute value or NULL */
+    if (attrs[i])
+      return (gchar*) attrs[i+1];
+    else
+      return NULL;
+  }
+
+  static void
+  _xmlStart(gpointer data, const XML_Char* name, const XML_Char** atts) { /*\
+    cdef :                                                                \*/
+      socketsClient_Data*   session = (socketsClient_Data*) data;
+      gchar**               element;
+      gint                  i;
+      gchar*                attr;
+
+    /* split name by namespace and element
+
+    gchar**             g_strsplit               (const gchar *string,
+                                                  const gchar *delimiter,
+                                                  gint max_tokens);
+    */
+    element = g_strsplit(name, " ", 2);
+
+    /* this from http://www.xml.com/pub/a/1999/09/expat/index.html?page=2 */
+    for (i = 0; i < session->depth; i++)
+      printf("  ");
+
+    printf("<%s xmlns='%s'", element[1], element[0]);
+    for (i = 0; atts[i]; i += 2)
+      printf(" %s='%s'", atts[i], atts[i + 1]);
+    printf(">\n");
+
+    switch (session->depth) {
+      /* match element by depth, namespace, and finally element name
+
+         gint           g_ascii_strcasecmp       (const gchar* str1,
+                                                  const gchar* str2);
+         Returns -1, 0 or 1, if str1 is <, == or > than str2.
+      */
+      case 0 : {
+        /* only stream:stream element is valid at depth == 0
+
+           if anything else is sent, session->state will be changed from
+           CONCORD_E_OPEN to CONCORD_E_CLOSE and the session will be closed
+           in the _gioRead function just after the XMLParse call (below).
+        */
+        if (g_ascii_strcasecmp(name,
+                               "http://etherx.jabber.org/streams stream") == 0)
+          _reply_stream(session, _xmlFindAttr(atts, "version"));
+        else
+          session->state = CONCORD_E_CLOSE;
+        break;
+      }
+
+      case 1 : {
+        if (g_ascii_strcasecmp(element[0], "jabber:client") == 0) {
+          /* ensure it's a valid element for the jabber:client namespace
+
+             see http://xmpp.org/rfcs/rfc3920.html#def
+          */
+          if (g_ascii_strcasecmp(element[1], "iq") == 0 ||
+              g_ascii_strcasecmp(element[1], "message") == 0 ||
+              g_ascii_strcasecmp(element[1], "presence") == 0) {
+            /* set the client mode */
+            session->state = CONCORD_E_CLIENT;
+
+            /* check and copy "to" and "from" attributes
+
+               GString* g_string_assign          (GString *string,
+                                                  const gchar *rval);
+            */
+            if (!(attr = _xmlFindAttr(atts, "to")))
+              attr = "";
+            session->eto = g_string_assign(session->eto, attr);
+            if (!(attr = _xmlFindAttr(atts, "from")))
+              attr = "";
+            session->efrom = g_string_assign(session->efrom, attr);
+            printf("--------- from: %s to: %s\n",
+                   session->efrom->str, session->eto->str);
+
+            /* copy element and attributes to ebuff
+
+               void     g_string_printf          (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+               void     g_string_append_printf   (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+            */
+            g_string_printf(session->ebuff, "<%s xmlns='%s'",
+                            element[1], element[0]);
+            for (i = 0; atts[i]; i += 2)
+              g_string_append_printf(session->ebuff, " %s='%s'",
+                                     atts[i], atts[i+1]);
+            g_string_append_printf(session->ebuff, ">");
+          }
+          else
+            _reply_streamError(session, "invalid-xml",
+                               "invalid element for jabber:client namespace");
+        }
+        if (g_ascii_strcasecmp(element[0],
+                               "urn:ietf:params:xml:ns:xmpp-sasl") == 0) {
+          if (g_ascii_strcasecmp(element[1], "auth") == 0) {
+            gchar* mec = _xmlFindAttr(atts, "mechanism");
+            if (mec && gsasl_server_support_p(session->core->saslCntx, mec)) {
+              /* initiate server session
+
+                 int    gsasl_server_start       (Gsasl* ctx,
+                                                  const char* mech,
+                                                  Gsasl_session** sctx);
+              */
+              printf("------ init %s mechanism\n", mec);
+              gsasl_server_start(session->core->saslCntx, mec,
+                                 &session->sctx);
+              session->state = CONCORD_E_SASL;
+            }
+            else {
+              _reply_saslFailure(session, "<invalid-mechanism/>");
+              session->state = CONCORD_E_CLOSE;
+            }
+          }
+
+          /* remaining: response, abort */
+        }
+
+        /* other depth=1 namespaces */
+        break;
+      }
+
+      default : {
+        /* process inner tags depending on state */
+        if (session->state == CONCORD_E_CLIENT) {
+          /* copy element and attributes to ebuff
+
+             void       g_string_append_printf   (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+          */
+          g_string_append_printf(session->ebuff, "<%s xmlns='%s'",
+                                 element[1], element[0]);
+          for (i = 0; atts[i]; i += 2)
+            g_string_append_printf(session->ebuff, " %s='%s'",
+                                   atts[i], atts[i+1]);
+          g_string_append_printf(session->ebuff, ">");
+        }
+        break;
+      }
+    }
+
+    /* increase XML depth regardless of element */
+    session->depth++;
+
+    /* free the element string array
+
+       void             g_strfreev               (gchar **str_array);
+    */
+    g_strfreev(element);
+  }
+
+
+  static void
+  concordSession_xmlEnd(gpointer data, const XML_Char* name) {            /*\
+    cdef :                                                                \*/
+      concordSession_Data*  session = (concordSession_Data*) data;
+      gchar**               element;
+      gint                  i;
+
+    /* decrease XML depth */
+    session->depth--;
+
+
+    /* split name by namespace and element
+
+    gchar**             g_strsplit               (const gchar *string,
+                                                  const gchar *delimiter,
+                                                  gint max_tokens);
+    */
+    element = g_strsplit(name, " ", 2);
+
+    for (i = 0; i < session->depth; i++)
+      printf("  ");
+    printf("</%s>\n", element[1]);
+
+    switch (session->depth) {
+      case 0 : {
+        /* close session when </stream:stream> is sent */
+        session->state = CONCORD_E_CLOSE;
+        break;
+      }
+      case 1 : {
+        switch (session->state) {
+          case CONCORD_E_CLIENT : {
+            /* copy final element close to ebuff
+
+               void     g_string_append_printf   (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+            */
+            g_string_append_printf(session->ebuff, "</%s>", element[1]);
+            concordCore_queuePush(session->core, session);
+            break;
+          }
+          case CONCORD_E_SASL : {
+            concordSession_reply_saslChallenge(session);
+            break;
+          }
+        }
+
+        /* reset the element strings when returning to depth 1
+
+           GString*     g_string_assign          (GString *string,
+                                                  const gchar *rval);
+        */
+        session->ebuff = g_string_assign(session->ebuff, "");
+        session->efrom = g_string_assign(session->efrom, "");
+        session->eto   = g_string_assign(session->eto,   "");
+
+        break;
+      }
+      default : {
+        if (session->state == CONCORD_E_CLIENT) {
+          /* copy element close to ebuff
+
+             void       g_string_append_printf   (GString *string,
+                                                  const gchar *format,
+                                                  ...);
+          */
+          g_string_append_printf(session->ebuff, "</%s>", element[1]);
+        }
+        break;
+      }
+    }
+
+    /* free the element string array before returning
+
+       void             g_strfreev               (gchar **str_array);
+    */
+    g_strfreev(element);
+  }
+
+
+  static void
+  concordSession_xmlCharData(gpointer data, const XML_Char* str,
+                             gint str_len) {                              /*\
+    cdef :                                                                \*/
+      concordSession_Data*  session = (concordSession_Data*) data;
+      gint                  i;
+      gchar*                strn;
+
+    /* output to stdout for debugging */
+    strn = g_strndup(str, str_len);
+    for (i = 0; i < session->depth; i++)
+      printf("  ");
+    printf("\"%s\"\n", strn);
+    g_free(strn);
+
+    if (session->state == CONCORD_E_OPEN)
+      /* character data should be ignored at the stream level */
+      return;
+
+    /* append character data to element buffer
+
+       GString*         g_string_append_len      (GString *string,
+                                                  const gchar *val,
+                                                  gssize len);
+    */
+    session->ebuff = g_string_append_len(session->ebuff, str, str_len);
+  }
+
+  /*
+  #
+  ###########################################################################
+  #
   # object constructor - deconstructor
   #                                                                        */
 
@@ -155,5 +821,7 @@
     0,                                           /*tp_is_gc*/
     },
     /* cdef classes */
-    _listenNew,
+    _gioNew,
+    _gioRead,
+    _gioWrite,
   };

Modified: trunk/concordance/src/sockets/Socket.c
===================================================================
--- trunk/concordance/src/sockets/Socket.c      2009-02-22 22:27:53 UTC (rev 
1515)
+++ trunk/concordance/src/sockets/Socket.c      2009-02-25 09:55:09 UTC (rev 
1516)
@@ -21,9 +21,6 @@
 
 #include "concordance.sockets.h"
 
-static gboolean
-_listenNew(GIOChannel* channel, GIOCondition condition, gpointer s);
-  
                                                                           /*\
 cdef class Socket :                                                       \*/
   static char socketsSocket_Doc[] = "Test";
@@ -174,7 +171,7 @@
         source = g_io_create_watch(self->chan, G_IO_IN);
         g_source_set_callback(source, (GSourceFunc)
                               ((socketsSocket_TypeObject*) s->ob_type)->
-                              _listenNew,
+                              _gioNew,
                               (gpointer) self, NULL);
         g_source_attach(source, self->context);
         g_source_unref(source);
@@ -213,7 +210,7 @@
   }
 
   static gboolean
-  _listenNew(GIOChannel* channel, GIOCondition condition, gpointer s) {   /*\
+  _gioNew(GIOChannel* channel, GIOCondition condition, gpointer s) {      /*\
     cdef :                                                                \*/
       socketsSocket_Object*      self = (socketsSocket_Object*) s;
       gint                       socket;
@@ -363,7 +360,7 @@
     0,                                           /*tp_is_gc*/
     },
     /* cdef classes */
-    _listenNew,
+    _gioNew,
   };
   
   

_______________________________________________
PySoy-SVN mailing list
PySoy-SVN@pysoy.org
http://www.pysoy.org/mailman/listinfo/pysoy-svn

Reply via email to