Blame samples/sendmessage.c

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