Blame samples/sendmessage.c

Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Meanwhile - Unofficial Lotus Sametime Community Client Library
Packit Service 37472d
  Copyright (C) 2004  Christopher (siege) O'Brien
Packit Service 37472d
  
Packit Service 37472d
  This library is free software; you can redistribute it and/or
Packit Service 37472d
  modify it under the terms of the GNU Library General Public
Packit Service 37472d
  License as published by the Free Software Foundation; either
Packit Service 37472d
  version 2 of the License, or (at your option) any later version.
Packit Service 37472d
  
Packit Service 37472d
  This library is distributed in the hope that it will be useful,
Packit Service 37472d
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 37472d
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 37472d
  Library General Public License for more details.
Packit Service 37472d
  
Packit Service 37472d
  You should have received a copy of the GNU Library General Public
Packit Service 37472d
  License along with this library; if not, write to the Free
Packit Service 37472d
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service 37472d
*/
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#include <stdlib.h>
Packit Service 37472d
#include <stdio.h>
Packit Service 37472d
#include <string.h>
Packit Service 37472d
#include <sys/socket.h>
Packit Service 37472d
#include <sys/types.h>
Packit Service 37472d
#include <netinet/in.h>
Packit Service 37472d
#include <netdb.h>
Packit Service 37472d
Packit Service 37472d
#include <glib.h>
Packit Service 37472d
Packit Service 37472d
#include <mw_common.h>
Packit Service 37472d
#include <mw_error.h>
Packit Service 37472d
#include <mw_service.h>
Packit Service 37472d
#include <mw_session.h>
Packit Service 37472d
#include <mw_srvc_im.h>
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define BUF_LEN 2048
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* client data should be put into a structure and associated with the
Packit Service 37472d
   session. Then it will be available from the many call-backs
Packit Service 37472d
   handling events from the session */
Packit Service 37472d
struct sample_client {
Packit Service 37472d
  struct mwSession *session;  /* the actual meanwhile session */
Packit Service 37472d
  int sock;                   /* the socket connecting to the server */
Packit Service 37472d
  int sock_event;             /* glib event id polling the socket */
Packit Service 37472d
  char *target;
Packit Service 37472d
  char *message;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* handler function for when the session wants to close IO */
Packit Service 37472d
static void mw_session_io_close(struct mwSession *session) {
Packit Service 37472d
  struct sample_client *client;
Packit Service 37472d
Packit Service 37472d
  client = mwSession_getClientData(session);
Packit Service 37472d
  if(client->sock) {    
Packit Service 37472d
    g_source_remove(client->sock_event);
Packit Service 37472d
    close(client->sock);
Packit Service 37472d
    client->sock = 0;
Packit Service 37472d
    client->sock_event = 0;
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* handler function for when the session wants to write data */
Packit Service 37472d
static int mw_session_io_write(struct mwSession *session,
Packit Service 37472d
			       const guchar *buf, gsize len) {
Packit Service 37472d
Packit Service 37472d
  struct sample_client *client;
Packit Service 37472d
  int ret = 0;
Packit Service 37472d
Packit Service 37472d
  client = mwSession_getClientData(session);
Packit Service 37472d
Packit Service 37472d
  /* socket was already closed. */
Packit Service 37472d
  if(client->sock == 0)
Packit Service 37472d
    return 1;
Packit Service 37472d
Packit Service 37472d
  while(len) {
Packit Service 37472d
    ret = write(client->sock, buf, len);
Packit Service 37472d
    if(ret <= 0) break;
Packit Service 37472d
    len -= ret;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(len > 0) {
Packit Service 37472d
    /* stop watching the socket */
Packit Service 37472d
    g_source_remove(client->sock_event);
Packit Service 37472d
Packit Service 37472d
    /* close the socket */
Packit Service 37472d
    close(client->sock);
Packit Service 37472d
Packit Service 37472d
    /* remove traces of socket from client */
Packit Service 37472d
    client->sock = 0;
Packit Service 37472d
    client->sock_event = 0;
Packit Service 37472d
Packit Service 37472d
    /* return error code */
Packit Service 37472d
    return -1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return 0;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* handles when a conversation has been fully established between
Packit Service 37472d
   this client and another. */
Packit Service 37472d
static void mw_im_conversation_opened(struct mwConversation *conv) {
Packit Service 37472d
  struct mwServiceIm *srvc;
Packit Service 37472d
  struct mwSession *session;
Packit Service 37472d
  struct sample_client *client;
Packit Service 37472d
  struct mwIdBlock *idb;
Packit Service 37472d
Packit Service 37472d
  /* get a reference to the client data */
Packit Service 37472d
  srvc = mwConversation_getService(conv);
Packit Service 37472d
  session = mwService_getSession(MW_SERVICE(srvc));
Packit Service 37472d
  client = mwSession_getClientData(session);
Packit Service 37472d
Packit Service 37472d
  /* make sure that it's not someone just randomly IM-ing us... */
Packit Service 37472d
  idb = mwConversation_getTarget(conv);
Packit Service 37472d
  g_return_if_fail(! strcmp(client->target, idb->user));
Packit Service 37472d
Packit Service 37472d
  /* send the message and close the conversation */
Packit Service 37472d
  mwConversation_send(conv, mwImSend_PLAIN, client->message);
Packit Service 37472d
  mwConversation_close(conv, ERR_SUCCESS);
Packit Service 37472d
Packit Service 37472d
  /* the polite way to close everything up. Will call
Packit Service 37472d
     mw_session_stateChange after doing what needs to be done */
Packit Service 37472d
  mwSession_stop(session, ERR_SUCCESS);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mwImHandler mw_im_handler = {
Packit Service 37472d
  .conversation_opened = mw_im_conversation_opened,
Packit Service 37472d
  .conversation_closed = NULL,
Packit Service 37472d
  .conversation_recv = NULL,
Packit Service 37472d
  .clear = NULL,
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void mw_session_stateChange(struct mwSession *session,
Packit Service 37472d
				   enum mwSessionState state,
Packit Service 37472d
				   gpointer info) {
Packit Service 37472d
Packit Service 37472d
  struct sample_client *client;
Packit Service 37472d
  struct mwServiceIm *service;
Packit Service 37472d
  struct mwConversation *conv;
Packit Service 37472d
  struct mwIdBlock idb;
Packit Service 37472d
Packit Service 37472d
  if(state == mwSession_STARTED) {
Packit Service 37472d
    /* session is now fully started */
Packit Service 37472d
Packit Service 37472d
    client = mwSession_getClientData(session);
Packit Service 37472d
    g_return_if_fail(client != NULL);
Packit Service 37472d
Packit Service 37472d
    /* create the im service, add it to the session, and start it up */
Packit Service 37472d
    service = mwServiceIm_new(session,&mw_im_handler);
Packit Service 37472d
    mwSession_addService(session, MW_SERVICE(service));
Packit Service 37472d
    mwService_start(MW_SERVICE(service));
Packit Service 37472d
Packit Service 37472d
    /* obtain a conversation with the specified user */
Packit Service 37472d
    idb.user = client->target;
Packit Service 37472d
    idb.community = NULL;
Packit Service 37472d
    conv = mwServiceIm_getConversation(service, &idb);
Packit Service 37472d
Packit Service 37472d
    /* and open it up. When it's finally opened, the
Packit Service 37472d
       conversation_opened handler for the IM service will be
Packit Service 37472d
       triggered */
Packit Service 37472d
    mwConversation_open(conv);
Packit Service 37472d
Packit Service 37472d
  } else if(state == mwSession_STOPPED) {
Packit Service 37472d
    /* session has stopped */
Packit Service 37472d
    
Packit Service 37472d
    if(info) {
Packit Service 37472d
      /* stopped due to an error */
Packit Service 37472d
      guint32 errcode;
Packit Service 37472d
      char *err;
Packit Service 37472d
Packit Service 37472d
      errcode = GPOINTER_TO_UINT(info);
Packit Service 37472d
      err = mwError(errcode);
Packit Service 37472d
      fprintf(stderr, "meanwhile error %s\n", err);
Packit Service 37472d
      g_free(err);
Packit Service 37472d
Packit Service 37472d
      exit(1);
Packit Service 37472d
Packit Service 37472d
    } else {
Packit Service 37472d
      exit(0);
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* the session handler structure is where you should indicate what
Packit Service 37472d
   functions will perform many of the functions necessary for the
Packit Service 37472d
   session to operate. Among these, only io_write and io_close are
Packit Service 37472d
   absolutely required. */
Packit Service 37472d
static struct mwSessionHandler mw_session_handler = {
Packit Service 37472d
  .io_write = mw_session_io_write,
Packit Service 37472d
  .io_close = mw_session_io_close,
Packit Service 37472d
  .clear = NULL,
Packit Service 37472d
  .on_stateChange = mw_session_stateChange,
Packit Service 37472d
  .on_setPrivacyInfo = NULL,
Packit Service 37472d
  .on_setUserStatus = NULL,
Packit Service 37472d
  .on_admin = NULL,
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** called from read_cb, attempts to read available data from sock and
Packit Service 37472d
    pass it to the session, passing back the return code from the read
Packit Service 37472d
    call for handling in read_cb */
Packit Service 37472d
static int read_recv(struct mwSession *session, int sock) {
Packit Service 37472d
  guchar buf[BUF_LEN];
Packit Service 37472d
  int len;
Packit Service 37472d
Packit Service 37472d
  len = read(sock, buf, BUF_LEN);
Packit Service 37472d
  if(len > 0) mwSession_recv(session, buf, len);
Packit Service 37472d
Packit Service 37472d
  return len;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** callback triggered from gaim_input_add, watches the socked for
Packit Service 37472d
    available data to be processed by the session */
Packit Service 37472d
static gboolean read_cb(GIOChannel *chan,
Packit Service 37472d
			GIOCondition cond,
Packit Service 37472d
			gpointer data) {
Packit Service 37472d
Packit Service 37472d
  struct sample_client *client = data;
Packit Service 37472d
  int ret = 0;
Packit Service 37472d
  int source = g_io_channel_unix_get_fd(chan);
Packit Service 37472d
Packit Service 37472d
  if(cond & G_IO_IN) {
Packit Service 37472d
    ret = read_recv(client->session, client->sock);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* normal operation ends here */
Packit Service 37472d
  if(ret > 0) return TRUE;
Packit Service 37472d
Packit Service 37472d
  /* read problem occured if we're here, so we'll need to take care of
Packit Service 37472d
     it and clean up internal state */
Packit Service 37472d
Packit Service 37472d
  if(client->sock) {
Packit Service 37472d
    g_source_remove(client->sock_event);
Packit Service 37472d
    close(client->sock);
Packit Service 37472d
    client->sock = 0;
Packit Service 37472d
    client->sock_event = 0;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return FALSE;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* address lookup */
Packit Service 37472d
static void init_sockaddr(struct sockaddr_in *addr,
Packit Service 37472d
			  const char *host, int port) {
Packit Service 37472d
Packit Service 37472d
  struct hostent *hostinfo;
Packit Service 37472d
Packit Service 37472d
  addr->sin_family = AF_INET;
Packit Service 37472d
  addr->sin_port = htons (port);
Packit Service 37472d
  hostinfo = gethostbyname(host);
Packit Service 37472d
  if(hostinfo == NULL) {
Packit Service 37472d
    fprintf(stderr, "Unknown host %s.\n", host);
Packit Service 37472d
    exit(1);
Packit Service 37472d
  }
Packit Service 37472d
  addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* open a network socket to host:port */
Packit Service 37472d
static int init_sock(const char *host, int port) {
Packit Service 37472d
  struct sockaddr_in srvrname;
Packit Service 37472d
  int sock;
Packit Service 37472d
Packit Service 37472d
  sock = socket(PF_INET, SOCK_STREAM, 0);
Packit Service 37472d
  if(sock < 0) {
Packit Service 37472d
    perror("socket failure");
Packit Service 37472d
    exit(1);
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  init_sockaddr(&srvrname, host, port);
Packit Service 37472d
  connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
Packit Service 37472d
Packit Service 37472d
  return sock;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* logging is redirected to here */
Packit Service 37472d
static void mw_log_handler(const gchar *domain, GLogLevelFlags flags,
Packit Service 37472d
			   const gchar *msg, gpointer data) {
Packit Service 37472d
#if DEBUG
Packit Service 37472d
  /* ok, debugging is enabled, so let's print it like normal */
Packit Service 37472d
  g_log_default_handler(domain, flags, msg, data);
Packit Service 37472d
#else
Packit Service 37472d
  ; /* nothing! very quiet */
Packit Service 37472d
#endif
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int main(int argc, char *argv[]) {
Packit Service 37472d
Packit Service 37472d
  char *server;
Packit Service 37472d
  int portno;
Packit Service 37472d
  char *sender;
Packit Service 37472d
  char *password;
Packit Service 37472d
  char *recipient;
Packit Service 37472d
  char *message;
Packit Service 37472d
Packit Service 37472d
  /* the meanwhile session itself */
Packit Service 37472d
  struct mwSession *session;
Packit Service 37472d
Packit Service 37472d
  /* client program data */
Packit Service 37472d
  struct sample_client *client;
Packit Service 37472d
Packit Service 37472d
  /* something glib uses to watch the socket for available data */
Packit Service 37472d
  GIOChannel *io_chan;
Packit Service 37472d
  
Packit Service 37472d
  if (argc < 7) {
Packit Service 37472d
    fprintf(stderr,
Packit Service 37472d
	    "usage %s:  server port sender password"
Packit Service 37472d
	    "recipient message\n", argv[0]);
Packit Service 37472d
    exit(0);
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  server = argv[1];
Packit Service 37472d
  portno = atoi(argv[2]);
Packit Service 37472d
  sender = argv[3];
Packit Service 37472d
  password = argv[4];
Packit Service 37472d
  recipient = argv[5];
Packit Service 37472d
  message = argv[6];
Packit Service 37472d
Packit Service 37472d
  /* let's redirect the output of the glib logging facilities */
Packit Service 37472d
  g_log_set_handler("meanwhile",
Packit Service 37472d
		    G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
Packit Service 37472d
		    mw_log_handler, NULL);
Packit Service 37472d
Packit Service 37472d
  /* set up the session stuff */
Packit Service 37472d
  session = mwSession_new(&mw_session_handler);
Packit Service 37472d
  mwSession_setProperty(session, mwSession_AUTH_USER_ID, sender, NULL);
Packit Service 37472d
  mwSession_setProperty(session, mwSession_AUTH_PASSWORD, password, NULL);
Packit Service 37472d
Packit Service 37472d
  mwSession_setProperty(session, mwSession_CLIENT_TYPE_ID,
Packit Service 37472d
			GUINT_TO_POINTER(mwLogin_MEANWHILE), NULL);
Packit Service 37472d
Packit Service 37472d
  /* set up the client data structure with the things we need it to
Packit Service 37472d
     remember */
Packit Service 37472d
  client = g_new0(struct sample_client, 1);
Packit Service 37472d
  client->session = session;
Packit Service 37472d
  client->sock = init_sock(server, portno);
Packit Service 37472d
  client->target = recipient;
Packit Service 37472d
  client->message = message;
Packit Service 37472d
Packit Service 37472d
  /* associate the client data with the session */
Packit Service 37472d
  mwSession_setClientData(session, client, g_free);
Packit Service 37472d
Packit Service 37472d
  /* start the session up */
Packit Service 37472d
  mwSession_start(session);
Packit Service 37472d
Packit Service 37472d
  /* add a watch on the socket */
Packit Service 37472d
  io_chan = g_io_channel_unix_new(client->sock);
Packit Service 37472d
  client->sock_event = g_io_add_watch(io_chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit Service 37472d
				      read_cb, client);
Packit Service 37472d
Packit Service 37472d
  /* ... and start the glib loop */
Packit Service 37472d
  g_main_loop_run(g_main_loop_new(NULL, FALSE));
Packit Service 37472d
}