Back to index

im-sdk  12.3.91
IIIMPClient.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.
00003 
00004 Permission is hereby granted, free of charge, to any person obtaining a
00005 copy of this software and associated documentation files (the
00006 "Software"), to deal in the Software without restriction, including
00007 without limitation the rights to use, copy, modify, merge, publish,
00008 distribute, sublicense, and/or sell copies of the Software, and to
00009 permit persons to whom the Software is furnished to do so, subject to
00010 the following conditions: The above copyright notice and this
00011 permission notice shall be included in all copies or substantial
00012 portions of the Software.
00013 
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00016 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00017 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00018 IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
00019 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00020 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
00021 THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
00022 ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
00023 
00024 
00025 Except as contained in this notice, the names of The Open Group and/or
00026 Sun Microsystems, Inc. shall not be used in advertising or otherwise to
00027 promote the sale, use or other dealings in this Software without prior
00028 written authorization from The Open Group and/or Sun Microsystems,
00029 Inc., as applicable.
00030 
00031 
00032 X Window System is a trademark of The Open Group
00033 
00034 OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
00035 logo, LBX, X Window System, and Xinerama are trademarks of the Open
00036 Group. All other trademarks and registered trademarks mentioned herein
00037 are the property of their respective owners. No right, title or
00038 interest in or to any trademark, service mark, logo or trade name of
00039 Sun Microsystems, Inc. or its licensors is granted.
00040 
00041 */
00042 #include "IIIMProtocol.hh"
00043 #include "IIIMPClient.hh"
00044 #include "IMProtoHandler.hh"
00045 #include "IIIMPInputContext.hh"
00046 #include "IMProtocolStructP.hh"
00047 #include "ICAttribute.hh"
00048 #if !defined(USE_FRAMEMGR_ALWAYS)
00049 #else /* USE_FRAMEMGR_ALWAYS */
00050 #include "FrameMgr.h"
00051 #endif /* USE_FRAMEMGR_ALWAYS */
00052 #include "IMTrans.hh"
00053 #include "IMThread.hh"
00054 
00055 IIIMPClient::
00056 IIIMPClient(IIIMProtocol* imp, IMTransAccept* ss) {
00057   accept_fd = ss;
00058   im_id = accept_fd->connection_id();
00059   iiim_protocol = imp;
00060 
00061   being_deleted = False;
00062   respond_keepalive = False;
00063 
00064   application_name = "Unknown"; // get from IMClientName IMAttrib
00065 
00066   // IM Attribute List
00067   alloc_attr = active_attr = 0;
00068   imAttribute_list = 0;
00069 
00070   input_context_list.disable_reordering();
00071 
00072   // start creating a thread
00073   thread = new IMThread(socket_listener, this);
00074   // done creating a thread
00075 }
00076 
00077 IIIMPClient::
00078 ~IIIMPClient() {
00079   // remove self from im client list
00080   iiim_protocol->iiimp_client_list.remove(this);
00081 
00082   // call destory_ic methods for all input contexts
00083   InputContext *ic = &(input_context_list.getFirstItem());
00084   while(ic){
00085     if (ic && ((IIIMPInputContext*)ic)->is_active()) {
00086       input_context_list.remove(ic);
00087       ((IIIMPInputContext*)ic)->unrealize();
00088       iiim_protocol->proto_handler->DestroyIC((InputContext*)ic);
00089       // alive ICs should be delete here
00090       delete ic;
00091     }
00092     ic = &(input_context_list.getNextItem());
00093   }
00094   if(alloc_attr) {
00095        delete [] imAttribute_list;
00096   }
00097   delete accept_fd;
00098   accept_fd = 0;
00099   im_id = 0;
00100   delete thread;
00101 }
00102 
00103 void*
00104 IIIMPClient::socket_listener(void* client_data) {
00105   IIIMPClient *client = (IIIMPClient*)client_data;
00106   unsigned char *message;
00107   int flag = True;
00108 
00109   // wait for IM_CONNECT message
00110   message = client->get_im_connect();
00111   client->dispatch(message, flag);
00112   if (flag == 1) delete message;
00113 
00114   while (1) {
00115     if (client->accept_fd == 0) return 0;
00116     switch (client->Select()) {
00117     case IMTransAccept::Trans_TIMEOUT:
00118       // timeout
00119       if (client->being_deleted) {
00120        delete client;
00121        return 0;
00122       }
00123       continue;
00124       break;
00125     case IMTransAccept::Trans_ACCEPT:
00126       // get a message
00127       client->being_deleted = False;
00128       if ((message = client->get_amessage()) == 0) {
00129        // client dies
00130        delete client;              // kill self
00131        return 0;
00132       }
00133       client->dispatch(message, flag);
00134       if (flag == 1) delete message;
00135       break;
00136     case IMTransAccept::Trans_ERROR:
00137     default:
00138       // error
00139       delete client;
00140       break;
00141     }
00142   }
00143   return 0;
00144 }
00145 
00146 int
00147 IIIMPClient::write_data(const char *buf, int const len) const {
00148   const int max_byte = MAX_RW_DATA_LEN;
00149 #ifdef WIN32
00150   size_t size = 0;
00151 #else
00152   ssize_t size = 0;
00153 #endif
00154   char *bufp = (char *)buf;
00155 
00156   if (accept_fd == 0) return 0;
00157 
00158   for (int rest_len = len; rest_len > 0;
00159        rest_len -= max_byte, bufp += max_byte) {
00160     if (rest_len < max_byte) {
00161       size += accept_fd->write(bufp, rest_len);
00162       break;
00163     } else {
00164       size += accept_fd->write(bufp, max_byte);
00165     }
00166   }
00167   return size;
00168 }
00169 
00170 int
00171 IIIMPClient::read_data(const char *buf, const int len) const {
00172   const int max_byte = MAX_RW_DATA_LEN;
00173 #ifdef WIN32
00174   size_t size = 0;
00175 #else
00176   ssize_t size = 0;
00177 #endif
00178   char *bufp = (char*)buf;
00179   int rest_len = len;
00180 
00181   if (accept_fd == 0) return 0;
00182 
00183   if (len == 0) // this should not happen
00184     return 0;
00185 
00186   // Read until nbytes have been read. We will break out when the following
00187   // two conditions occur:
00188   //  - num_read = 0 ( the connection has probably timed out )
00189   //  - accumulated size = expected nbyte.
00190 
00191   while (1) {
00192     int try_len = (rest_len < max_byte)? rest_len : max_byte;
00193     int num_read = accept_fd->read(bufp, try_len);
00194     if (num_read == 0)
00195       break;
00196     size += num_read;
00197     if (size == len) // we have got our fill.
00198       break;
00199     bufp += num_read;
00200     rest_len -= num_read;
00201   }
00202   if (size == 0) { // lost the connection
00203     // kill the connection 
00204   }
00205   return size;
00206 }
00207 
00208 unsigned char*
00209 IIIMPClient::get_im_connect() {
00210   IIimpProtoHdr hdr;
00211   int header_len = sizeof(IIimpProtoHdr);
00212 #if !defined(USE_FRAMEMGR_ALWAYS)
00213 #else /* USE_FRAMEMGR_ALWAYS */
00214   extern XimFrameRec im_packet_header_fr[];
00215 #endif /* USE_FRAMEMGR_ALWAYS */
00216 
00217   while (1) {
00218     if (header_len != read_data((char *)&hdr, header_len)) {
00219       goto read_error;
00220     }
00221     if (hdr.opcode != IM_CONNECT) {
00222       // can do nothing
00223       continue;
00224     }
00225     int read_len;
00226     if ((read_len = read_data((char *)&byteOrder, sizeof(char)))
00227        != sizeof(char)) {
00228       goto read_error;
00229     }
00230     need_swap = (byteOrder != iiim_protocol->byteOrder());
00231     return get_content((char*)&hdr, True);
00232   }
00233  read_error:
00234   delete accept_fd;
00235   im_id = 0;
00236   accept_fd = 0;
00237   return (unsigned char *)NULL;
00238 }
00239 
00240 unsigned char*
00241 IIIMPClient::get_content(char *packet_header, int isConnect) {
00242 #if !defined(USE_FRAMEMGR_ALWAYS)
00243 #else /* USE_FRAMEMGR_ALWAYS */
00244   extern XimFrameRec im_packet_header_fr[];
00245   FrameMgr fm;
00246 #endif /* USE_FRAMEMGR_ALWAYS */
00247   int total_size;
00248   unsigned char opcode;
00249   unsigned char length[3];
00250   unsigned int data_length = 0;
00251 
00252 #if !defined(USE_FRAMEMGR_ALWAYS)
00253   char *ptr;
00254   ptr = packet_header;
00255   total_size = 4;
00256   /* byte swap is not required */
00257   req_get8(ptr, opcode);
00258   req_get8(ptr, length[2]);
00259   req_get8(ptr, length[1]);
00260   req_get8(ptr, length[0]);
00261 #else /* USE_FRAMEMGR_ALWAYS */
00262   fm = FrameMgrInit(im_packet_header_fr, (char *)packet_header, need_swap);
00263   total_size = FrameMgrGetTotalSize(fm);
00264   /* get data */
00265   FrameMgrGetToken(fm, opcode);
00266   FrameMgrGetToken(fm, length[2]);
00267   FrameMgrGetToken(fm, length[1]);
00268   FrameMgrGetToken(fm, length[0]);
00269   /* free FrameMgr */
00270   FrameMgrFree(fm);
00271 #endif /* USE_FRAMEMGR_ALWAYS */
00272 
00273   /* calculate length */
00274   data_length  = (length[2] << 16);
00275   data_length += (length[1] << 8);
00276   data_length += length[0];
00277 
00278   unsigned char *p = new unsigned char[total_size + data_length * 4];
00279   unsigned char *pp = p;
00280   *pp++ = opcode;
00281   *pp++ = length[2]; *pp++ = length[1]; *pp++ = length[0];
00282 
00283   if (!isConnect) {
00284     if (data_length > 0) {
00285       if ((data_length * 4) != read_data((char *)pp, data_length * 4)) {
00286        goto read_error;
00287       }
00288     }
00289   } else {
00290     *pp++ = byteOrder;
00291     const int to_be_read = data_length * 4 - sizeof(char);
00292     if (to_be_read != read_data((char *)pp, to_be_read)) {
00293       goto read_error;
00294     }
00295   }
00296   return (unsigned char *)p;
00297  read_error:
00298   delete accept_fd;
00299   im_id = 0;
00300   accept_fd = 0;
00301   return (unsigned char *)NULL;
00302 }
00303 
00304 unsigned char*
00305 IIIMPClient::get_amessage() {
00306   IIimpProtoHdr hdr;
00307   int header_len = sizeof(IIimpProtoHdr);
00308 
00309   if (header_len != read_data((char *)&hdr, header_len)) {
00310     delete accept_fd;
00311     im_id = 0;
00312     accept_fd = 0;
00313     return (unsigned char *)NULL;
00314   }
00315   return get_content((char*)&hdr, False);
00316 }
00317 
00318 int
00319 IIIMPClient::Select() {
00320   struct timeval timeout;
00321 
00322   if (being_deleted) {
00323     // wait 10 minutes
00324     timeout.tv_sec  = 600L;
00325     timeout.tv_usec = 0L;
00326   } else {
00327     // wait 1.0 second
00328     timeout.tv_sec  = 1L;
00329     timeout.tv_usec = 0L;
00330   }
00331   return accept_fd->select_fd(timeout);
00332 }
00333 
00334 void
00335 IIIMPClient::dispatch(unsigned char *p, int &flag) {
00336   IMProtocolStruct call_data;
00337   IIimpProtoHdr *hdr = (IIimpProtoHdr*)p;
00338   unsigned char *p1 = (unsigned char *)(hdr + 1);
00339   if (hdr == (IIimpProtoHdr*)NULL) return;
00340 
00341   memset(&call_data, 0, sizeof(IMProtocolStruct));
00342 
00343   call_data.major_code = hdr->opcode;
00344 
00345   switch (call_data.major_code) {
00346   case IM_CONNECT:
00347     connect(&call_data, p1);
00348     break;
00349   case IM_DISCONNECT:
00350     dis_connect(&call_data, p1);
00351     break;
00352   case IM_SETIMVALUES:
00353     set_imvalues(&call_data, p1);
00354     break;
00355   case IM_GETIMVALUES:
00356     get_imvalues(&call_data, p1);
00357     break;
00358   case IM_CREATEIC:
00359     create_ic(&call_data, p1);
00360     break;
00361   case IM_SETICVALUES:
00362     set_icvalues(&call_data, p1);
00363     break;
00364   case IM_GETICVALUES:
00365     get_icvalues(&call_data, p1);
00366     break;
00367   case IM_SETICFOCUS:
00368     set_icfocus(&call_data, p1);
00369     break;
00370   case IM_UNSETICFOCUS:
00371     unset_icfocus(&call_data, p1);
00372     break;
00373   case IM_DESTROYIC:
00374     destroy_ic(&call_data, p1);
00375     break;
00376   case IM_RESETIC:
00377     reset_ic(&call_data, p1);
00378     break;
00379   case IM_FORWARD_EVENT:
00380     forward_event(&call_data, p1);
00381     break;
00382   case IM_TRIGGER_NOTIFY:
00383     trigger_notify(&call_data, p1);
00384     break;
00385   case IM_PREEDIT_START_REPLY:
00386     preedit_start_reply(&call_data, p1);
00387     break;
00388   case IM_PREEDIT_CARET_REPLY:
00389     preedit_caret_reply(&call_data, p1);
00390     break;
00391   case IM_AUX_SETVALUES:
00392     aux_set_values(&call_data, p1);
00393     break;
00394   default:
00395     break;
00396   }
00397 }