Author: pnoltes
Date: Wed Oct 22 09:07:10 2014
New Revision: 1633566

URL: http://svn.apache.org/r1633566
Log:
CELIX-172: Initial commit for the bonjour shell.

Added:
    celix/trunk/shell_bonjour/
    celix/trunk/shell_bonjour/CMakeLists.txt
    celix/trunk/shell_bonjour/deploy.cmake
    celix/trunk/shell_bonjour/private/
    celix/trunk/shell_bonjour/private/include/
    celix/trunk/shell_bonjour/private/include/bonjour_shell.h
    celix/trunk/shell_bonjour/private/src/
    celix/trunk/shell_bonjour/private/src/activator.c
    celix/trunk/shell_bonjour/private/src/bonjour_shell.c
Modified:
    celix/trunk/CMakeLists.txt

Modified: celix/trunk/CMakeLists.txt
URL: 
http://svn.apache.org/viewvc/celix/trunk/CMakeLists.txt?rev=1633566&r1=1633565&r2=1633566&view=diff
==============================================================================
--- celix/trunk/CMakeLists.txt (original)
+++ celix/trunk/CMakeLists.txt Wed Oct 22 09:07:10 2014
@@ -58,6 +58,7 @@ add_subdirectory(device_access)
 add_subdirectory(deployment_admin)
 add_subdirectory(remote_services)
 add_subdirectory(remote_shell)
+add_subdirectory(shell_bonjour)
 add_subdirectory(shell_tui)
 add_subdirectory(shell)
 add_subdirectory(log_writer)

Added: celix/trunk/shell_bonjour/CMakeLists.txt
URL: 
http://svn.apache.org/viewvc/celix/trunk/shell_bonjour/CMakeLists.txt?rev=1633566&view=auto
==============================================================================
--- celix/trunk/shell_bonjour/CMakeLists.txt (added)
+++ celix/trunk/shell_bonjour/CMakeLists.txt Wed Oct 22 09:07:10 2014
@@ -0,0 +1,44 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+celix_subproject(SHELL_BONJOUR "Option to enable building the Bonjour Shell 
(shell access by chat clients)" OFF DEPS LAUNCHER shell)
+if (SHELL_BONJOUR)
+
+       find_package(LibXml2 REQUIRED)
+       
+       #TODO create/add FindDNS_SD.cmake and use it (with required)
+       find_library(DNS_SD_LIB NAMES dns_sd)
+       
+       set(BUNDLE_SYMBOLICNAME "bonjour_shell")
+       set(BUNDLE_VERSION "0.1.0")
+       set(BUNDLE_NAME "bonjour_shell")
+       
+       include_directories("${PROJECT_SOURCE_DIR}/utils/public/include")
+       include_directories("${PROJECT_SOURCE_DIR}/shell/public/include")
+       include_directories("${LIBXML2_INCLUDE_DIR}")
+       include_directories("private/include")
+       
+       bundle(bonjour_shell
+               SOURCES
+                       private/src/activator.c
+                       private/src/bonjour_shell.c
+       )
+       
+       target_link_libraries(bonjour_shell ${CELIX_LIBRARIES} ${APR_LIBRARIES} 
${LIBXML2_LIBRARIES} ${DNS_SD_LIB})
+
+endif (SHELL_BONJOUR)
+

Added: celix/trunk/shell_bonjour/deploy.cmake
URL: 
http://svn.apache.org/viewvc/celix/trunk/shell_bonjour/deploy.cmake?rev=1633566&view=auto
==============================================================================
--- celix/trunk/shell_bonjour/deploy.cmake (added)
+++ celix/trunk/shell_bonjour/deploy.cmake Wed Oct 22 09:07:10 2014
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+is_enabled(SHELL_BONJOUR)
+if (SHELL_BONJOUR)
+       deploy("bonjour_shell" BUNDLES 
+               shell
+               bonjour_shell
+               PROPERTIES "bonjour.shell.id=Apache Celix"
+       )
+endif (SHELL_BONJOUR)

Added: celix/trunk/shell_bonjour/private/include/bonjour_shell.h
URL: 
http://svn.apache.org/viewvc/celix/trunk/shell_bonjour/private/include/bonjour_shell.h?rev=1633566&view=auto
==============================================================================
--- celix/trunk/shell_bonjour/private/include/bonjour_shell.h (added)
+++ celix/trunk/shell_bonjour/private/include/bonjour_shell.h Wed Oct 22 
09:07:10 2014
@@ -0,0 +1,45 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * bonjour_shell.h
+ *
+ *  \date       Oct 20, 2014
+ *  \author            <a href="mailto:celix-...@incubator.apache.org";>Apache 
Celix Project Team</a>
+ *  \copyright Apache License, Version 2.0
+ */
+
+#ifndef BONJOUR_SHELL_H_
+#define BONJOUR_SHELL_H_
+
+#include <apr_pools.h>
+
+#include <service_reference.h>
+
+#include "celix_errno.h"
+
+typedef struct bonjour_shell *bonjour_shell_pt;
+
+celix_status_t bonjourShell_create(apr_pool_t *pool, char *id, 
bonjour_shell_pt *shell);
+celix_status_t bonjourShell_destroy(bonjour_shell_pt shell);
+
+celix_status_t bonjourShell_addShellService(void * handle, 
service_reference_pt reference, void * service);
+celix_status_t bonjourShell_removeShellService(void * handle, 
service_reference_pt reference, void * service);
+
+
+#endif /* BONJOUR_SHELL_H_ */

Added: celix/trunk/shell_bonjour/private/src/activator.c
URL: 
http://svn.apache.org/viewvc/celix/trunk/shell_bonjour/private/src/activator.c?rev=1633566&view=auto
==============================================================================
--- celix/trunk/shell_bonjour/private/src/activator.c (added)
+++ celix/trunk/shell_bonjour/private/src/activator.c Wed Oct 22 09:07:10 2014
@@ -0,0 +1,119 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * activator.c
+ *
+ *  \date       Oct 20, 2014
+ *  \author            <a href="mailto:celix-...@incubator.apache.org";>Apache 
Celix Project Team</a>
+ *  \copyright Apache License, Version 2.0
+ */
+
+#include <celix_errno.h>
+
+#include <stdlib.h>
+#include <apr_strings.h>
+#include <apr_pools.h>
+
+#include "bundle_activator.h"
+#include "bundle_context.h"
+#include "constants.h"
+
+#include "bonjour_shell.h"
+
+#include <celix_errno.h>
+#include <service_tracker.h>
+#include <shell.h>
+
+struct bundle_instance {
+       apr_pool_t *pool;
+       bonjour_shell_pt shell;
+       service_tracker_pt tracker;
+};
+
+typedef struct bundle_instance *bundle_instance_pt;
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void 
**userData) {
+       celix_status_t status = CELIX_SUCCESS;
+    apr_pool_t *ctxpool;
+    apr_pool_t *pool;
+
+    status = bundleContext_getMemoryPool(context, &ctxpool);
+    apr_pool_create(&pool, ctxpool);
+    if (status == CELIX_SUCCESS) {
+       bundle_instance_pt bi = (bundle_instance_pt) apr_palloc(pool, 
sizeof(struct bundle_instance));
+        if (userData != NULL) {
+               bi->pool = pool;
+               bi->shell = NULL;
+               bi->tracker = NULL;
+               (*userData) = bi;
+        } else {
+               status = CELIX_ENOMEM;
+        }
+    }
+    return status;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt 
context) {
+    celix_status_t status = CELIX_SUCCESS;
+    bundle_instance_pt bi = (bundle_instance_pt)userData;
+
+    char *uuid = NULL;
+    bundleContext_getProperty(context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid);
+    char *hostname = NULL;
+    bundleContext_getProperty(context, "HOSTNAME", &hostname);
+    char *bonjourShellId = NULL;
+    bundleContext_getProperty(context, "bonjour.shell.id", &bonjourShellId);
+
+    char id[128];
+    if (bonjourShellId != NULL) {
+       snprintf(id, 128, bonjourShellId);
+    } else if (hostname != NULL) {
+       snprintf(id, 128, "Celix-%.8s@%s", uuid, hostname);
+    } else {
+       snprintf(id, 128, "Celix-%.8s", uuid);
+    }
+    status = bonjourShell_create(bi->pool, id, &bi->shell);
+
+    service_tracker_customizer_pt cust = NULL;
+    serviceTrackerCustomizer_create(bi->shell,  NULL, 
bonjourShell_addShellService, NULL, bonjourShell_removeShellService, &cust);
+    serviceTracker_create(context, (char *)OSGI_SHELL_SERVICE_NAME, cust, 
&bi->tracker);
+    serviceTracker_open(bi->tracker);
+
+
+    return status;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt 
context) {
+    celix_status_t status = CELIX_SUCCESS;
+    bundle_instance_pt bi = (bundle_instance_pt)userData;
+
+    serviceTracker_close(bi->tracker);
+
+    return status;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt 
context) {
+        celix_status_t status = CELIX_SUCCESS;
+           bundle_instance_pt bi = (bundle_instance_pt)userData;
+
+           serviceTracker_destroy(bi->tracker);
+           bonjourShell_destroy(bi->shell);
+
+           return status;
+}

Added: celix/trunk/shell_bonjour/private/src/bonjour_shell.c
URL: 
http://svn.apache.org/viewvc/celix/trunk/shell_bonjour/private/src/bonjour_shell.c?rev=1633566&view=auto
==============================================================================
--- celix/trunk/shell_bonjour/private/src/bonjour_shell.c (added)
+++ celix/trunk/shell_bonjour/private/src/bonjour_shell.c Wed Oct 22 09:07:10 
2014
@@ -0,0 +1,420 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * activator.c
+ *
+ *  \date       Oct 20, 2014
+ *  \author            <a href="mailto:celix-...@incubator.apache.org";>Apache 
Celix Project Team</a>
+ *  \copyright Apache License, Version 2.0
+ */
+
+#include "bonjour_shell.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <dns_sd.h>
+#include <libxml/xmlreader.h>
+#include <libxml/xmlwriter.h>
+#include <celixbool.h>
+#include <shell.h>
+
+#define MAX_BUFFER_SIZE 5120
+
+//static xmlBufferPtr buf; //FOR DEBUG
+
+struct bonjour_shell {
+       char *id;
+       volatile bool running;
+
+       //service member and mutex
+       pthread_mutex_t mutex;
+       shell_service_pt service;
+
+       //tcp socket members
+       pthread_t listenThread;
+       int listenSocket;
+       uint16_t portInNetworkByteOrder;
+
+       //dns_sd registration
+       DNSServiceRef sdRef;
+       TXTRecordRef txtRecord;
+
+};
+
+struct connection_context {
+       bool gotCommand;
+       bool running;
+       int sockfd;
+       bonjour_shell_pt shell;
+       xmlTextWriterPtr writer;
+       xmlTextReaderPtr reader;
+       pthread_t sendThread;
+       pthread_mutex_t mutex;
+       pthread_cond_t dataAvailCond;
+       array_list_pt dataList; //protected by mutex
+       struct timeval lastUpdated; //protected by mutex
+};
+
+static struct connection_context *currentContext = NULL; //TODO update shell 
to accept void * data next to callback
+
+static void bonjourShell_addDataToCurrentContext(char *buff);
+static void bonjourShell_sendData(struct connection_context *context);
+
+static celix_status_t bonjourShell_register(bonjour_shell_pt shell);
+static celix_status_t bonjourShell_listen(bonjour_shell_pt shell);
+
+static void bonjourShell_acceptConnection(bonjour_shell_pt shell, int 
connectionFd);
+
+static void bonjourShell_parse(bonjour_shell_pt shell, struct 
connection_context *context);
+static void bonjourShell_parseXmlNode(bonjour_shell_pt shell, struct 
connection_context *context);
+
+static void bonjourShell_parseStream(bonjour_shell_pt shell, struct 
connection_context *context);
+static void bonjourShell_parseCommand(bonjour_shell_pt shell, struct 
connection_context *context);
+
+celix_status_t bonjourShell_create(apr_pool_t *parentPool, char *id, 
bonjour_shell_pt *result) {
+       celix_status_t status = CELIX_SUCCESS;
+       bonjour_shell_pt shell = (bonjour_shell_pt) malloc(sizeof(struct 
bonjour_shell));
+       if (shell != NULL) {
+               shell->id = strdup(id);
+               shell->running = true;
+               shell->listenSocket = 0;
+               shell->service = NULL;
+
+               pthread_mutex_init(&shell->mutex, NULL);
+
+               pthread_create(&shell->listenThread, NULL, (void 
*)bonjourShell_listen, shell);
+
+               (*result) = shell;
+       } else {
+               status = CELIX_ENOMEM;
+       }
+       return status;
+}
+
+static celix_status_t bonjourShell_register(bonjour_shell_pt shell) {
+       celix_status_t status = CELIX_SUCCESS;
+
+       uint16_t portInNetworkByteOrder = shell->portInNetworkByteOrder;
+       char *srvName = shell->id;
+       char portStr[64];
+       sprintf(portStr, "%i", ntohs(portInNetworkByteOrder));
+
+       TXTRecordCreate(&shell->txtRecord, 256, NULL);
+
+       TXTRecordSetValue(&shell->txtRecord, "txtver", 1, "1");
+       TXTRecordSetValue(&shell->txtRecord, "version", 1, "1");;
+       TXTRecordSetValue(&shell->txtRecord, "1st", strlen(shell->id), 
shell->id);
+       TXTRecordSetValue(&shell->txtRecord, "port.p2pj", 5, portStr);
+       TXTRecordSetValue(&shell->txtRecord, "status", 5, "avail");
+
+       DNSServiceRegister(&shell->sdRef, 0, 0,
+       srvName, /* may be NULL */
+       "_presence._tcp",
+       NULL, /* may be NULL */
+       NULL, /* may be NULL */
+       portInNetworkByteOrder, /* In network byte order */
+       TXTRecordGetLength(&shell->txtRecord), 
TXTRecordGetBytesPtr(&shell->txtRecord), /* may be NULL */
+       NULL, /* may be NULL */
+       NULL /* may be NULL */
+       );
+
+       //DNSServiceProcessResult(shell->sdRef);
+
+       return status;
+}
+
+static celix_status_t bonjourShell_listen(bonjour_shell_pt shell) {
+       celix_status_t status = CELIX_SUCCESS;
+
+
+       shell->listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (shell->listenSocket < 0) {
+               printf("error opening socket\n");
+               return CELIX_START_ERROR;
+       }
+
+       struct sockaddr_in serv_addr;
+       memset(&serv_addr, 0, sizeof(serv_addr));       /* Clear struct */
+       serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  /* Incoming addr */
+       serv_addr.sin_family = AF_INET;                 /* Internet/IP */
+       serv_addr.sin_port = 0;                                    /* server 
port, don't specify let os decide */
+
+       if (bind(shell->listenSocket, (struct sockaddr *) &serv_addr, 
sizeof(struct sockaddr_in)) < 0) {
+               printf("error binding\n");
+               return CELIX_START_ERROR;
+       }
+
+       if (listen(shell->listenSocket, 1) < 0) {
+               printf("error listening");
+               return CELIX_START_ERROR;
+       }
+
+       struct sockaddr_in sin;
+       socklen_t len = sizeof(sin);
+       if (getsockname(shell->listenSocket, (struct sockaddr *)&sin, &len) == 
-1) {
+           perror("getsockname");
+               return CELIX_START_ERROR;
+       } else {
+               shell->portInNetworkByteOrder = sin.sin_port;
+       }
+
+       status = bonjourShell_register(shell);
+       if (status != CELIX_SUCCESS) {
+               return status;
+       }
+
+       struct sockaddr_in connect_addr;
+       socklen_t slen = sizeof(struct sockaddr_in);
+       while (shell->running) {
+               int connectionSocket = accept(shell->listenSocket, (struct 
sockaddr *) &connect_addr, &slen);
+               if (connectionSocket < 0) {
+                       printf("error accepting connection\n");
+                       return CELIX_START_ERROR;
+               } else {
+                       bonjourShell_acceptConnection(shell, connectionSocket);
+               }
+       }
+
+       return status;
+}
+
+static void bonjourShell_acceptConnection(bonjour_shell_pt shell, int 
connectionFd) {
+       //printf("setting up parser\n");
+
+       struct connection_context context;
+       context.gotCommand = false;
+       context.running = true;
+       context.sockfd = connectionFd;
+       context.shell = shell;
+
+       context.reader = xmlReaderForFd(context.sockfd, NULL, NULL, 0);
+
+       xmlOutputBufferPtr outputBuff = xmlOutputBufferCreateFd(context.sockfd,
+                       NULL);
+       context.writer  = xmlNewTextWriter(outputBuff);
+
+       //buf = xmlBufferCreate();
+       //xmlTextWriterPtr writer = xmlNewTextWriterMemory(buf, 0);
+
+       //init send thread and needed data types.
+       arrayList_create(&context.dataList);
+       pthread_cond_init(&context.dataAvailCond, NULL); //TODO destroy
+       pthread_mutex_init(&context.mutex, NULL); //TODO destroy
+       pthread_create(&context.sendThread, NULL, (void 
*)bonjourShell_sendData, &context);
+
+       int sockStatus = 0;
+       if (context.reader != NULL && context.writer != NULL) {
+               while (sockStatus == 0 && shell->running && context.running) {
+                       bonjourShell_parse(shell, &context);
+
+                       //check if socket is closed
+                       int error = 0;
+                       socklen_t len = sizeof(error);
+                       sockStatus = getsockopt(context.sockfd, SOL_SOCKET, 
SO_ERROR,
+                                       &error, &len);
+                       if (sockStatus != 0) {
+                               printf("Got error from socket error is %i", 
error);
+                       }
+               }
+
+               if (sockStatus == 0) { //shell stopped still connected
+                       usleep(1500); //wait untill all data is send
+                       xmlTextWriterEndElement(context.writer); //end stream
+                       xmlTextWriterEndDocument(context.writer);
+                       close(context.sockfd);
+                       xmlFreeTextReader(context.reader);
+                       xmlFreeTextWriter(context.writer);
+               }
+               //printf("after close + free of xml parser & socker\n");
+
+               context.running = false;
+               pthread_cond_signal(&context.dataAvailCond);
+
+               pthread_join(context.sendThread, NULL);
+               pthread_mutex_destroy(&context.mutex);
+               pthread_cond_destroy(&context.dataAvailCond);
+       } else {
+               if (context.reader != NULL) {
+                       xmlFreeTextReader(context.reader);
+               }
+               if (context.writer != NULL) {
+                       xmlFreeTextWriter(context.writer);
+               }
+       }
+
+
+}
+
+static void bonjourShell_parse(bonjour_shell_pt shell, struct 
connection_context *context) {
+       xmlTextReaderRead(context->reader);
+       bonjourShell_parseXmlNode(shell, context);
+}
+
+static void bonjourShell_parseXmlNode(bonjour_shell_pt shell, struct 
connection_context *context) {
+          xmlChar *name;
+
+          int nodeType = xmlTextReaderNodeType(context->reader);
+
+          if (nodeType == XML_READER_TYPE_ELEMENT) {
+                  name = xmlTextReaderLocalName(context->reader);
+                  //printf("found element with name %s\n", name);
+                  if (strcmp((char *)name, "stream") == 0) {
+                          bonjourShell_parseStream(shell, context);
+                  } else if (strcmp((char *)name, "body") == 0 && 
context->gotCommand == false) {
+                          bonjourShell_parseCommand(shell, context); 
//assuming first body element is command
+                  } else if (strcmp((char *)name, "message") == 0) {
+                          context->gotCommand = false;
+                  }
+                  xmlFree(name);
+          } else if (nodeType == XML_READER_TYPE_END_ELEMENT /*end element*/ ) 
{
+                  name = xmlTextReaderLocalName(context->reader);
+                  //printf("found END element with name %s\n", name);
+                  if (strcmp((char *)name, "stream") == 0) {
+                         context->running = false;
+                  }
+                  xmlFree(name);
+          } else {
+                  //printf("found node type %i\n", nodeType);
+          }
+}
+
+static void bonjourShell_parseStream(bonjour_shell_pt shell, struct 
connection_context *context) {
+       xmlChar *to = xmlTextReaderGetAttribute(context->reader, (xmlChar 
*)"from");
+       xmlChar *from = xmlTextReaderGetAttribute(context->reader, (xmlChar 
*)"to");
+
+       xmlTextWriterStartDocument(context->writer, NULL, NULL, NULL);
+       xmlTextWriterStartElementNS(context->writer, (xmlChar *)"stream", 
(xmlChar *)"stream", (xmlChar *)"http://etherx.jabber.org/streams";);
+       xmlTextWriterWriteAttribute(context->writer, (xmlChar *)"xmlns", 
(xmlChar *)"jabber:client"); //TODO should use namespace method/
+       xmlTextWriterWriteAttribute(context->writer, (xmlChar *)"to", to);
+       xmlTextWriterWriteAttribute(context->writer, (xmlChar *)"from", from);
+       xmlTextWriterWriteAttribute(context->writer, (xmlChar *)"version", 
(xmlChar *)"1.0");
+
+       xmlTextWriterWriteString(context->writer, (xmlChar *)"\n"); //Needed to 
flush to writer
+       xmlTextWriterFlush(context->writer);
+       //printf("current context buf: %s\n", (char *)buf->content);
+
+       if (from != NULL) {
+               xmlFree(from);
+       }
+       if (to != NULL) {
+               xmlFree(to);
+       }
+}
+
+
+static void bonjourShell_parseCommand(bonjour_shell_pt shell, struct 
connection_context *context)  {
+    xmlChar *command = xmlTextReaderReadString(context->reader);
+
+       if (command != NULL) {
+               context->gotCommand = true;
+               currentContext = context;
+               pthread_mutex_lock(&shell->mutex);
+               if (shell->service != NULL) {
+                       shell->service->executeCommand(shell->service->shell, 
(char *)command, bonjourShell_addDataToCurrentContext, 
bonjourShell_addDataToCurrentContext);
+               }
+               pthread_mutex_unlock(&shell->mutex);
+       } 
+
+       if (command != NULL) {
+               xmlFree(command);
+       }
+}
+
+static void bonjourShell_addDataToCurrentContext(char *buff) {
+       pthread_mutex_lock(&currentContext->mutex);
+       arrayList_add(currentContext->dataList, strdup(buff));
+       gettimeofday(&currentContext->lastUpdated, NULL);
+       pthread_mutex_unlock(&currentContext->mutex);
+       pthread_cond_signal(&currentContext->dataAvailCond);
+}
+
+static void bonjourShell_sendData(struct connection_context *context) {
+       while (context->running == true ) {
+               pthread_mutex_lock(&context->mutex);
+               pthread_cond_wait(&context->dataAvailCond, &context->mutex); 
//wait till some data is ready.
+
+               struct timeval now;
+               while (context->running) {
+                       gettimeofday(&now, NULL);
+                       long elapsed = (now.tv_sec * 1000000 + now.tv_usec) - 
(context->lastUpdated.tv_sec * 1000000 + context->lastUpdated.tv_usec);
+                       if (elapsed > 1000) { //usec passed without update of 
data.
+                               break;
+                       }
+                       pthread_mutex_unlock(&context->mutex);
+                       usleep(1000);
+                       pthread_mutex_lock(&context->mutex);
+               }
+
+               if (context->running) {
+                       xmlTextWriterStartElement(currentContext->writer, 
(xmlChar *)"message");
+                       xmlTextWriterWriteAttribute(currentContext->writer, 
(xmlChar *)"type", (xmlChar *)"chat");
+                       xmlTextWriterStartElement(currentContext->writer, 
(xmlChar *)"body");
+                       xmlTextWriterWriteString(currentContext->writer, 
(xmlChar *)"\n");
+                       int i;
+                       int size = arrayList_size(context->dataList);
+                       for ( i = 0 ; i < size ; i += 1) {
+                               char *entry = arrayList_get(context->dataList, 
i);
+                               
xmlTextWriterWriteString(currentContext->writer, (xmlChar *)entry);
+                               
//xmlTextWriterWriteString(currentContext->writer, (xmlChar *)"\r"); //needed 
for adium to create new line in UI
+                               free(entry);
+                       }
+                       arrayList_clear(context->dataList);
+                       xmlTextWriterEndElement(currentContext->writer); //end 
body
+                       xmlTextWriterEndElement(currentContext->writer); //end 
message
+                       xmlTextWriterWriteString(currentContext->writer, 
(xmlChar *)"\n"); //flush
+                       xmlTextWriterFlush(currentContext->writer);
+               }
+               pthread_mutex_unlock(&context->mutex);
+       }
+}
+
+
+celix_status_t bonjourShell_destroy(bonjour_shell_pt shell) {
+       DNSServiceRefDeallocate(shell->sdRef);
+       TXTRecordDeallocate(&shell->txtRecord);
+
+       close(shell->listenSocket);
+       pthread_join(shell->listenThread, NULL);
+
+       free(shell);
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bonjourShell_addShellService(void * handle, 
service_reference_pt reference, void * service) {
+       bonjour_shell_pt shell = handle;
+       pthread_mutex_lock(&shell->mutex);
+       shell->service = service;
+       pthread_mutex_unlock(&shell->mutex);
+       return CELIX_SUCCESS;
+}
+
+celix_status_t bonjourShell_removeShellService(void * handle, 
service_reference_pt reference, void * service) {
+       bonjour_shell_pt shell = handle;
+       pthread_mutex_lock(&shell->mutex);
+       if (shell->service == service) {
+               shell->service = NULL;
+       }
+       pthread_mutex_unlock(&shell->mutex);
+       return CELIX_SUCCESS;
+}


Reply via email to