Back to index

im-sdk  12.3.91
ProtocolDriver.java
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 
00043  
00044 package sun.awt.im.iiimp;
00045 
00046 import java.net.*;
00047 import java.util.*;
00048 import java.util.jar.*;
00049 import java.io.*;
00050 import java.text.*;
00051 import java.awt.*;
00052 import java.awt.im.*;
00053 import java.awt.event.*;
00054 import java.awt.font.*;
00055 import java.security.*;
00056 import java.text.AttributedCharacterIterator.Attribute;
00057 import com.sun.iiim.*;
00058 
00059 class ProtocolDriver extends IIIMComponent implements IIIMProtocol,
00060                             IIIMActionListener, IMProvider {
00061 
00062     private IMServer imServer = null;
00063     private InputContext inputContext = null;
00064     
00065     private static ProtocolDriver pd = null;
00066     private boolean connected = false;
00067     
00068     private String userName = null;
00069     
00070     private URL url = null;
00071     
00072     private IIIMPURLConnection uc;
00073     
00074     private IIIMPInputStream in;
00075     
00076     private IIIMPOutputStream out;
00077  
00078     private ODClassLoader odLoader = null;
00079 
00080     private int auxIMID = 0;
00081     private int auxICID = 0;
00082     private HashMap auxMap;
00083 
00084     private HashSet doSet;
00085     private HashSet classNameSet;
00086     private boolean download = true;
00087     private HashSet aliveIC;
00088     private int ccdefID = NOID;
00089     private int manageRuleID = NOID;
00090     private Locale prevLocale = null;
00091 
00092     static ProtocolDriver getInstance() {
00093         if (pd == null) {
00094            pd = (ProtocolDriver)AccessController.doPrivileged(new PrivilegedAction() {
00095               public Object run() {
00096                   try {
00097                      return new ProtocolDriver();
00098                   } catch(Exception e) {
00099                      return null;
00100                   }
00101               }
00102            });
00103         }
00104         return pd;
00105     }
00106     
00107     //private 
00108     ProtocolDriver() {
00109         imServer = new IMServer();
00110        doSet = new HashSet();
00111        classNameSet = new HashSet();
00112        aliveIC = new HashSet();
00113        if (System.getSecurityManager() == null) {
00114            download = false;
00115        }
00116        String dl = Manager.getProperty("iiimf.object.download");
00117        if (dl != null && dl.equals("true")) {
00118            download = true;
00119        }
00120        if (download) {
00121            odLoader = new ODClassLoader();
00122            Manager.setLoader(odLoader);
00123        }
00124        Manager.setPD(this);
00125        auxMap = new HashMap();
00126        
00127         // First try to connect with iiim server
00128         try {
00129             connectIM();
00130         } catch(IOException e) {
00131            if (Manager.DEBUG) {
00132               e.printStackTrace();
00133            }
00134         }
00135         pd = this;
00136     }
00137     
00138     boolean isConnected() {
00139        return connected;
00140     }
00141 
00142     boolean connect() {
00143         try {
00144             uc = (IIIMPURLConnection) url.openConnection();
00145             
00146             if(uc.isConnected() == false) {
00147               try {
00148                   AccessController.doPrivileged
00149                      (new PrivilegedExceptionAction() {
00150                          public Object run() throws IOException {
00151                             uc.connect();
00152                             return null;
00153                          }
00154                      });
00155               } catch (PrivilegedActionException pe) {
00156                   throw (IOException)pe.getException();
00157               }
00158 
00159                 if(uc.isConnected() == false) {
00160                     throw new IOException();
00161                 }
00162             }
00163             in = new IIIMPInputStream(this, uc.getInputStream());
00164             out = new IIIMPOutputStream(uc.getOutputStream());
00165        } catch(IOException e) {
00166            if (Manager.DEBUG) {
00167               e.printStackTrace();
00168            }
00169             return false;
00170         }
00171         return true;
00172     }
00173     
00174   
00175     synchronized void lostConnect() {
00176         if (connected == false) {
00177             return;
00178         }
00179        try {
00180             uc.disconnect();
00181         } catch(IOException e) {
00182             connected = false;
00183         }
00184         connected = false;
00185         done();
00186         uc = null;
00187         in = null;
00188         out = null;
00189         inputContext = null;
00190         imServer = new IMServer();
00191     } 
00192     
00193     synchronized void send(Protocol protocol) throws IOException {
00194         protocol.write(out);
00195         out.flush();
00196     }
00197     
00198     public void dispatchEvent(IIIMEvent e) {
00199         AWTEvent event = e.getAWTEvent();
00200 
00201         if(event instanceof KeyEvent && inputContext != null) {
00202             inputContext.dispatchKeyEvent((KeyEvent)event);      
00203        }
00204     }
00205 
00206     synchronized void regularReply(int imID, int icID, int opCode) {
00207         ProtocolData data;
00208         Protocol reply;
00209         
00210         data = new ProtocolData();
00211         try {
00212             data.write2(imID);
00213             data.write2(icID);
00214         } catch(IOException e) {
00215            if (Manager.DEBUG) {
00216               e.printStackTrace();
00217            }
00218        }
00219                 
00220         reply = new Protocol(opCode, data);
00221         try {
00222             send(reply);                 
00223         } catch(IOException e) {
00224            if (Manager.DEBUG) {
00225               e.printStackTrace();
00226            }
00227        }
00228     }
00229     
00230     void getReply(int protocolID) throws IOException {
00231         getReply(0, protocolID);
00232     }
00233     
00234     int nestLevel = 0;
00235     boolean catchedInNest = false;
00236     boolean outSideNestExit = false;
00237     Vector nestVector = new Vector();
00238     int catchedProtocolInNest = IM_NO_PROTOCOL;
00239 
00240     void getReply(int proto1, int proto2) throws IOException {
00241 
00242        nestLevel++;
00243        Integer processProto = new Integer(proto2);
00244        nestVector.add(processProto);
00245         while(true) {
00246            if (outSideNestExit) {
00247               if (catchedProtocolInNest == proto2) {
00248                   catchedInNest = false;
00249                   outSideNestExit = false;
00250                   break;
00251               }
00252            }
00253 
00254             Protocol protocol1 = new Protocol();
00255             protocol1.read(in);
00256 
00257             // If it matches one of the expected reply protocol, return
00258             if((protocol1.getOpCode() == proto1) ) {
00259                 Protocol protocol2 = new Protocol();
00260                 protocol2.read(in);
00261             
00262                 if(protocol2.getOpCode() != proto2) {
00263                     // Received an unexpected protocol
00264                     lostConnect();
00265                     throw new IIIMProtocolException("Unexpected protocol received: "
00266                         + protocol1 + " against: " + proto1);            
00267                 }
00268                 break;
00269             }
00270             else if((protocol1.getOpCode() == proto2)) {
00271                 driveProtocol(protocol1);
00272                 break;
00273             } else {
00274                 //debug("Addtional protocol = " + protocol1.getOpCode());
00275                 driveProtocol(protocol1);
00276               if (nestLevel > 1) {
00277                   int p = protocol1.getOpCode();
00278                   for (int i = 0; i < nestLevel - 1; i++) { 
00279                      if (p == ((Integer)nestVector.get(i)).intValue()) {
00280                          catchedProtocolInNest = p; 
00281                          catchedInNest = true;
00282                      }
00283                   }
00284               }
00285             }
00286        }
00287        if (catchedInNest) {
00288            outSideNestExit = true;
00289        }
00290        nestLevel--;
00291        nestVector.remove(processProto);
00292     }
00293 
00294     void driveProtocol(Protocol protocol) throws IOException {
00295         int opCode = protocol.getOpCode();
00296         ProtocolData data = protocol.getData();
00297         
00298         ProtocolData replyData = new ProtocolData();
00299         Protocol reply;        
00300         int imServerID = data.read2();
00301         int inputContextID = 0;
00302 
00303         AttributedCharacterIterator iterator = null;                
00304         FeedbackText text = null;
00305         int type;
00306         
00307         switch(opCode) {
00308          case IM_PREEDIT_START:
00309            debug("IM_PREEDIT_START");
00310              
00311            inputContextID = data.read2();
00312            replyData.write2(imServerID);
00313            replyData.write2(inputContextID);
00314            replyData.write4(1024);
00315                 
00316            dispatchPreeditEvent(new IIIMPreeditEvent(IIIMPreeditEvent.START));
00317            reply = new Protocol(opCode, replyData);
00318             send(new Protocol(IM_PREEDIT_START_REPLY, replyData));
00319            break;
00320          case IM_PREEDIT_DRAW:
00321            {
00322               debug("IM_PREEDIT_DRAW");
00323               
00324               inputContextID = data.read2();
00325               int caret_position = data.read4();
00326               int first_changed = data.read4();
00327               int length_changed = data.read4();
00328               type = data.read4();
00329                 
00330               InputContext temp = imServer.getInputContext(inputContextID);
00331               Manager manager = Manager.getInstance();
00332               manager.setIIIMPreeditListener(temp.getPreeditListener());
00333               if (type == STRING) {
00334                   //iterator =
00335                   //    (new AttributedString(data.readString())).getIterator();                
00336               } else if (type == TEXT) {
00337                   text = FeedbackText.toFeedbackText(data);
00338               }
00339                 
00340               if(text == null) {
00341                   for (int i = (first_changed + length_changed - 1);
00342                       i >= first_changed; i--) {
00343                      temp.removeContentAt(i);
00344                   }
00345               } else {
00346                   // composedText replace
00347                   if (length_changed > 0) {
00348                      for (int i = (first_changed + length_changed - 1);
00349                           i >= first_changed; i--) {
00350                          temp.removeContentAt(i);
00351                      }
00352                   }
00353                   int len = text.count;
00354                   for (int i = first_changed, j = 0;
00355                       i < (first_changed+len); i++, j++) {
00356                      FeedbackChar c = text.value[j];
00357                      temp.insertContentAt(c, i);
00358                   }
00359               }
00360               
00361               iterator = temp.getAttributedString().getIterator();
00362               
00363               // IIIMPreeditEvent don't include change first, change length
00364               // and FeedbackType information   
00365               IIIMPreeditEvent event =
00366                   new IIIMPreeditEvent(IIIMPreeditEvent.DRAW,
00367                                     iterator, caret_position);
00368               dispatchPreeditEvent(event);
00369               regularReply(imServerID, inputContextID, IM_PREEDIT_DRAW_REPLY);
00370               break;
00371            }
00372          case IM_PREEDIT_DONE:
00373            debug("IM_PREEDIT_DONE");
00374             
00375            // Send event to remove preeditlistener
00376            inputContextID = data.read2();
00377            // For event isn't synchronized, but it have no effect
00378            dispatchPreeditEvent(new IIIMPreeditEvent(IIIMPreeditEvent.DONE));
00379            regularReply(imServerID, inputContextID, IM_PREEDIT_DONE_REPLY);
00380            break;
00381 
00382          case IM_STATUS_START:
00383            debug("IM_STATUS_START");
00384             
00385            inputContextID = data.read2();
00386            
00387            dispatchStatusEvent(new IIIMStatusEvent(IIIMStatusEvent.START));
00388            regularReply(imServerID, inputContextID, IM_STATUS_START_REPLY);
00389            break;
00390 
00391          // Hack to avoid IIIMServer waiting for IM_OPEN_NS_REPLY
00392          // TODO !! Need to add Hotkey and Namespace POSIX I/O 
00393          // Support for Java Clients using IIIM 
00394 
00395          case IM_OPEN_NS:
00396            debug("IM_OPEN_NS");
00397 
00398            data.skipBytes(2);
00399            int flags = data.read4();
00400            int ns_id = data.read4();
00401            String fname = data.readString();
00402 
00403            replyData.write2(imServerID);
00404            replyData.write2(0);
00405            replyData.write4(-1);
00406            replyData.write4(2);
00407            send(new Protocol(IM_OPEN_NS_REPLY, replyData));
00408            break;
00409 
00410          case IM_STATUS_DRAW:
00411            debug("IM_STATUS_DRAW");
00412             
00413            inputContextID = data.read2();
00414            type = data.read4();
00415                 
00416            IIIMStatusEvent statusEvent = null;
00417            if(type == STRING) {
00418               iterator =
00419                   (new AttributedString(data.readString())).getIterator();
00420            } else if(type == TEXT) {
00421               text = FeedbackText.toFeedbackText(data);
00422 
00423               iterator = FeedbackText.toACIterator(text);
00424            }
00425            statusEvent = 
00426               new IIIMStatusEvent(IIIMStatusEvent.DRAW, iterator);                
00427            dispatchStatusEvent(statusEvent);
00428            
00429            regularReply(imServerID, inputContextID, IM_STATUS_DRAW_REPLY);
00430            break;
00431 
00432          case IM_STATUS_DONE:
00433            debug("IM_STATUS_DONE");
00434             
00435            inputContextID = data.read2();
00436            dispatchStatusEvent(new IIIMStatusEvent(IIIMStatusEvent.DONE));
00437            
00438            regularReply(imServerID, inputContextID, IM_STATUS_DONE_REPLY);
00439            break;
00440 
00441          case IM_FORWARD_EVENT:
00442            {
00443               debug("IM_FORWARD_EVENT");
00444 
00445               inputContextID = data.read2();
00446               type = data.read4();
00447               switch(type) {
00448                 case STRING:
00449                   break;
00450                 case TEXT:
00451                   break;
00452                 case KEYEVENT:
00453                   int len = data.read4();
00454                   imServer.getInputContext(inputContextID).setForward();
00455                   if(len > 0) {
00456                      byte[] buf = new byte[len];
00457                      data.read(buf, 0, len);
00458                      KeyData kd = new KeyData(buf, len);
00459                      IIIMPKey[] kev = kd.toKey();
00460                      break;                        
00461                   }
00462                   break;
00463               }
00464               regularReply(imServerID, inputContextID, IM_FORWARD_EVENT_REPLY);
00465               break;
00466            }
00467 
00468          case IM_FORWARD_EVENT_REPLY:
00469            debug("IM_FORWARD_EVENT_REPLY");
00470             
00471            inputContextID = data.read2();
00472            break;
00473 
00474          case IM_FORWARD_EVENT_WITH_OPERATIONS:
00475          case IM_FORWARD_EVENT_WITH_OPERATIONS_REPLY:
00476            debug("IM_FORWARD_EVENT_WITH_OPERATIONS_REPLY");
00477 
00478            // unprocessed operation list processing will be done later
00479 
00480            break;
00481 
00482          case IM_COMMIT_STRING:
00483            debug("IM_COMMIT_STRING");
00484             
00485            inputContextID = data.read2();
00486            type = data.read4();
00487            IIIMCommittedEvent commitedEvent = null;
00488 
00489            {
00490               InputContext temp = imServer.getInputContext(inputContextID);
00491               Manager manager = Manager.getInstance();
00492               manager.setIIIMCommittedListener(temp.getCommittedListener());
00493            }
00494 
00495            if(type == STRING) {
00496               String committed = data.readString();
00497               commitedEvent = new IIIMCommittedEvent(committed);
00498            } else if(type == TEXT) {
00499               text = FeedbackText.toFeedbackText(data);
00500               commitedEvent = new IIIMCommittedEvent(text.toString());                
00501            }
00502            dispatchCommittedEvent(commitedEvent);
00503            // No reply protocol
00504            break;           
00505 
00506          case IM_LOOKUP_CHOICE_START:
00507            {
00508               debug("IM_LOOKUP_CHOICE_START");
00509             
00510               inputContextID = data.read2();
00511            
00512               type = data.read2();
00513                 
00514               int size = data.read2();
00515               int rows = data.read2();
00516               int columns = data.read2();
00517                 
00518               int dir = data.read2();
00519               int labeled = data.read2();
00520                 
00521               IIIMLookupEvent event =
00522                   new IIIMLookupEvent(IIIMLookupEvent.START,
00523                                    type, size,
00524                                    new Dimension(rows, columns),
00525                                    dir, labeled);
00526               dispatchLookupEvent(event);
00527               regularReply(imServerID, inputContextID,
00528                           IM_LOOKUP_CHOICE_START_REPLY);   
00529               break;             
00530            }
00531          case IM_LOOKUP_CHOICE_DRAW:
00532            {
00533               debug("IM_LOOKUP_CHOICE_DRAW");
00534             
00535               inputContextID = data.read2();
00536               int ret_first_index = data.read4();
00537               int ret_last_index = data.read4();
00538               int ret_current_index = data.read4();
00539 
00540               // List of candidates
00541               FeedbackText[] candidates = null;
00542               int len = data.read4();
00543 
00544               byte[] buf;
00545 
00546               if (len > 0) {
00547                   buf = new byte[len];
00548                   data.read(buf, 0, len);
00549                   candidates = FeedbackText.
00550                      toListOfFeedbackText(new ProtocolData(buf, len));
00551               }
00552 
00553               // List of labels
00554               FeedbackText[] labels = null;
00555               len = data.read4();
00556                 if (len > 0) {
00557                     buf =new byte[len];
00558                     data.read(buf, 0, len);
00559                     labels = FeedbackText.
00560                         toListOfFeedbackText(new ProtocolData(buf, len));
00561                 }
00562                 FeedbackText title =
00563                   FeedbackText.toFeedbackText(data);
00564 
00565 
00566               IIIMLookupEvent lookupEvent = null;
00567               if (Manager.COLOR_SUPPORT) {
00568                   AttributedCharacterIterator[] can =
00569                      new AttributedCharacterIterator[candidates.length];
00570                   for (int i = 0; i < can.length; i++) {
00571                      can[i] = FeedbackText.toACIterator(candidates[i]);
00572                   }
00573 
00574                   AttributedCharacterIterator[] lab =
00575                      new AttributedCharacterIterator[labels.length];
00576                   if (labels != null) {
00577                      for (int i = 0; i < lab.length; i++) {
00578                          lab[i] = FeedbackText.toACIterator(labels[i]);
00579                      }
00580                   } else {
00581                      for (int i = 0; i < lab.length; i++) {
00582                          lab[i] = new AttributedString("").getIterator();
00583                      }
00584                   }
00585                   AttributedCharacterIterator titleIterator =
00586                      title == null ?
00587                      new AttributedString("Lookup Window").getIterator() :
00588                   FeedbackText.toACIterator(title);
00589 
00590                   lookupEvent = new IIIMLookupEvent(IIIMLookupEvent.DRAW,
00591                                                 ret_first_index,
00592                                                 ret_last_index,
00593                                                 ret_current_index,
00594                                                 can, lab, titleIterator);
00595               } else {
00596                   String[] can = new String[candidates.length];
00597                   for (int i = 0; i < can.length; i++) {
00598                      can[i] = candidates[i].toString();
00599                   }
00600 
00601                   String[] lab = new String[labels.length];
00602                   if (labels != null) {
00603                      for (int i = 0; i < lab.length; i++) {
00604                          lab[i] = labels[i].toString();                
00605                      }
00606                   } else {
00607                      // In this case, user must select candidate
00608                      // with mouse click.
00609                      for (int i = 0; i < candidates.length; i++) {
00610                          lab[i] = " ";
00611                      }
00612                   }
00613                   String titleString =
00614                      title == null ? "Lookup Window" : title.toString();
00615 
00616                   lookupEvent = new IIIMLookupEvent(IIIMLookupEvent.DRAW,
00617                                                 ret_first_index,
00618                                                 ret_last_index,
00619                                                 ret_current_index,
00620                                                 can, lab, titleString);
00621               }
00622 
00623               dispatchLookupEvent(lookupEvent);
00624                 regularReply(imServerID, inputContextID,
00625                           IM_LOOKUP_CHOICE_DRAW_REPLY);
00626                 break;
00627             }
00628          case IM_LOOKUP_CHOICE_PROCESS:
00629             {
00630                 debug("IM_LOOKUP_CHOICE_PROCESS");
00631             
00632                 inputContextID = data.read2();
00633                 
00634                 type = data.read2();
00635                 
00636                 int val = data.read2();
00637                 
00638                 if(type == 0) {
00639                     // INDEX type, val is selected index
00640                 } else if(type ==  1) {
00641                     // PAGE type, val is page index
00642                 }
00643                 IIIMLookupEvent event = new IIIMLookupEvent(
00644                                         IIIMLookupEvent.PROCESS,
00645                                         type, val
00646                                         );
00647               dispatchLookupEvent(event);
00648                 regularReply(imServerID, inputContextID,
00649                           IM_LOOKUP_CHOICE_PROCESS_REPLY);
00650                 break;
00651             }
00652          case IM_LOOKUP_CHOICE_DONE:
00653             {
00654                 debug("IM_LOOKUP_CHOICE_DONE");
00655             
00656                 inputContextID = data.read2();
00657               dispatchLookupEvent(new IIIMLookupEvent(IIIMLookupEvent.DONE));
00658                 regularReply(imServerID, inputContextID,
00659                           IM_LOOKUP_CHOICE_DONE_REPLY);
00660                 break;
00661             }
00662 
00663          case IM_AUX_START:
00664             {
00665                 debug("IM_AUX_START");
00666                 inputContextID = data.read2();
00667                 auxIMID = imServerID;
00668               auxICID = inputContextID;
00669 
00670                 int index = data.read4();
00671                 String name = data.readString();
00672 
00673               if (odLoader == null) {
00674                   replyData.write2(imServerID);
00675                   replyData.write2(inputContextID);
00676                   replyData.write4(index);
00677                   replyData.writeString(name);
00678                   send(new Protocol(IM_AUX_START_REPLY, replyData));
00679                 break;
00680               }
00681 
00682               try {
00683                   IIIMAuxListener aux =
00684                      (IIIMAuxListener)odLoader.loadClass(name).newInstance();
00685                   auxMap.put(name, aux);
00686                   aux.auxStart(new IIIMAuxEvent(IIIMAuxEvent.START,
00687                                             index, name));
00688               } catch(Exception e) {
00689                   if (Manager.DEBUG) {
00690                      e.printStackTrace();
00691                   }
00692               }
00693 
00694                 replyData.write2(imServerID);
00695                 replyData.write2(inputContextID);
00696                 replyData.write4(index);
00697                 replyData.writeString(name);
00698                 send(new Protocol(IM_AUX_START_REPLY, replyData));
00699                 break;
00700             }
00701          case IM_AUX_DRAW:
00702             {
00703                 debug("IM_AUX_DRAW");
00704             
00705                 inputContextID = data.read2();
00706                 StringData data1 = new StringData(data);
00707                 int index = data1.read4();
00708                 String name = data1.readString();
00709                 int len = data1.read4() / 4;
00710                 int[] idata = new int[len];
00711                 for(int i = 0; i < len; i++) {
00712                     idata[i] = data1.read4();
00713                 }
00714                 
00715                 String[] sdata = data1.toStringArray2();
00716 
00717               IIIMAuxListener aux = (IIIMAuxListener)auxMap.get(name);
00718               if (aux == null) {
00719                 debug(" Unknown aux : " + name);
00720                   replyData.write2(imServerID);
00721                   replyData.write2(inputContextID);
00722                   replyData.write4(index);
00723                   replyData.writeString(name);
00724                   send(new Protocol(IM_AUX_DRAW_REPLY, replyData));                
00725                 break;
00726               }
00727               aux.auxDraw(new IIIMAuxEvent(IIIMAuxEvent.DRAW, index,
00728                                         name, idata, sdata));
00729                 replyData.write2(imServerID);
00730                 replyData.write2(inputContextID);
00731                 replyData.write4(index);
00732                 replyData.writeString(name);
00733                 send(new Protocol(IM_AUX_DRAW_REPLY, replyData));                
00734                 break;
00735             }   
00736          case IM_AUX_DONE:
00737             {
00738                 debug("IM_AUX_DONE");
00739             
00740                 inputContextID = data.read2();
00741                 
00742                 int index = data.read4();
00743                 String name = data.readString();
00744 
00745               IIIMAuxListener aux = (IIIMAuxListener)auxMap.get(name);
00746               if (aux == null) {
00747                   debug(" Unknown aux : " + name);
00748                   break;
00749               }
00750 
00751               aux.auxDone(new IIIMAuxEvent(IIIMAuxEvent.DONE, index, name));
00752                 
00753                 replyData.write2(imServerID);
00754                 replyData.write2(inputContextID);
00755                 replyData.write4(index);
00756                 replyData.writeString(name);
00757                 send(new Protocol(IM_AUX_DONE_REPLY, replyData));                 
00758                 break;
00759             }
00760          case IM_CONNECT_REPLY:
00761            {
00762                 debug("IM_CONNECT_REPLY");
00763                 IIIMPIMValues ret = new IIIMPIMValues();
00764 
00765                 String[] localeNameList = null;
00766                try {
00767                    StringData d = new StringData((ProtocolData) data);
00768                    localeNameList = d.toStringArray();
00769                } catch (Exception e) {
00770                   if (Manager.DEBUG) {
00771                      e.printStackTrace();
00772                   }
00773                }
00774                Locale[] localeList = null;
00775                if (localeNameList != null) {
00776                    int max = localeNameList.length;
00777                    localeList = new Locale[max];
00778                    for (int i = 0; i < max; i++) {
00779                       localeList[i] = toLocale(localeNameList[i]);
00780                    }
00781                }
00782                ret.id = imServerID;
00783                ret.localeList = localeList;
00784                
00785                imServer.setLocaleList(ret);              
00786                break;
00787            }
00788          case IM_REGISTER_TRIGGER_KEYS:
00789            {
00790                debug("IM_REGISTER_TRIGGER_KEYS");
00791                IIIMPIMValues ret = new IIIMPIMValues();
00792 
00793                data.skipBytes(2);
00794                int num_on_keys = (data.read4() / 16); // on keys
00795 
00796                if (num_on_keys > 0) {
00797                  ret.onKey = new IIIMPKey[num_on_keys];
00798                  for (int i = 0; i < num_on_keys; i++) {
00799                    int keycode = data.read4();
00800                    char keychar = (char) data.read4();
00801                    int modifier = data.read4();
00802                    int timestamp = data.read4();
00803                    ret.onKey[i] =
00804                    new IIIMPKey(keycode, keychar, modifier);
00805                  }
00806                }
00807   
00808                int num_off_keys = (data.read4() / 16); // off keys
00809                if (num_off_keys > 0) {
00810                  ret.offKey = new IIIMPKey[num_off_keys];
00811                  for (int i = 0; i < num_off_keys; i++) {
00812                    int keycode = data.read4();
00813                    char keychar = (char) data.read4();
00814                    int modifier = data.read4();
00815                    int timestamp = data.read4();
00816                    ret.offKey[i] = new IIIMPKey(keycode, keychar,modifier);
00817                  }
00818                }
00819 
00820                ret.id = imServerID;
00821                ret.dynamic_event_flow = true;     
00822                imServer.setTriggerKeys(ret);             
00823                break;
00824            } 
00825          case IM_DISCONNECT_REPLY:
00826            {
00827                 debug("IM_DISCONNECT_REPLY");
00828            
00829                //Initialize imServer
00830                imServer = new IMServer();
00831 
00832                break;               
00833            }
00834          case IM_CREATEIC_REPLY:
00835            {
00836                 debug("IM_CREATEIC_REPLY");
00837            
00838                inputContextID = data.read2();
00839               aliveIC.add(new Integer(inputContextID));
00840                if(inputContext != null) // It shouldn't happen
00841                    inputContext.setID(inputContextID);
00842         
00843                // getCurrentInputContext().setID(inputContextID);         
00844                break;
00845            }
00846          case IM_TRIGGER_NOTIFY:
00847            {
00848               debug("IM_TRIGGER_NOTIFY");
00849 
00850               inputContextID = data.read2();
00851               int onOff = data.read2();
00852               data.read2(); // padding
00853 
00854               InputContext ic = imServer.getInputContext(inputContextID);
00855               if (onOff == 1) {
00856                   // this method do not send IM_TRIGGER_NOTIFY
00857                   ic.setConversionModeOff();
00858               }
00859               regularReply(imServerID, inputContextID, IM_TRIGGER_NOTIFY_REPLY);
00860               break;
00861            }
00862          case IM_TRIGGER_NOTIFY_REPLY:
00863            {
00864                 debug("IM_TRIGGER_NOTIFY_REPLY");
00865            
00866                inputContextID = data.read2();
00867                break;        
00868            }
00869          case IM_DESTROYIC_REPLY:
00870            {
00871                 debug("IM_DESTROYIC_REPLY");
00872            
00873                inputContextID = data.read2();
00874                imServer.removeInputContextHandler(
00875                    imServer.getInputContext(inputContextID));
00876                break;
00877            }
00878          case IM_SETICVALUES_REPLY:
00879            {
00880                 debug("IM_SETICVALUES_REPLY");
00881            
00882                inputContextID = data.read2();
00883                break;
00884            }
00885          case IM_GETICVALUES_REPLY:
00886            {
00887                 debug("IM_GETICVALUES_REPLY");
00888            
00889                inputContextID = data.read2();
00890                int len = data.read2(); // byte length
00891                byte[] buf = new byte[len];
00892                data.read(buf, 0 , len);
00893                data.read2(); //pad
00894                
00895                IIIMPICValues value = new IIIMPICValues(buf);
00896                // getInputContext() and set ICValues
00897                break;
00898            }
00899          case IM_SETICFOCUS_REPLY: 
00900          case IM_UNSETICFOCUS_REPLY:
00901            {
00902                 //debug("IM_SETICFOCUS_REPLY or IM_UNSETICFOCUS_REPLY");
00903            
00904                inputContextID = data.read2();
00905                break;
00906            }
00907          case IM_RESETIC_REPLY:
00908            {
00909                debug("IM_RESETIC_REPLY");
00910                
00911                inputContextID = data.read2();
00912                // Reset ic's context
00913                imServer.getInputContext(inputContextID).done();
00914                //done();
00915                break;
00916            }
00917          case IM_AUX_SETVALUES_REPLY:
00918            {
00919                debug("IM_AUX_SETVALUES_REPLY");
00920                inputContextID = data.read2();
00921                int index = data.read4();
00922                String name = data.readString();
00923                
00924               // dispatchAuxEvent(new IIIMAuxEvent(IIIMAuxEvent.SETVALUES, index, 
00925               //                            name, null, null));
00926                break;
00927            }
00928            
00929          case IM_SETIMVALUES:
00930            {
00931               data.read2(); //padding
00932               int length = data.read4();
00933 
00934               if (length > 0) {
00935                   byte[] buf = new byte[length];
00936                   data.read(buf, 0, length);
00937 
00938                   ProtocolData attrs = new ProtocolData(buf, length);
00939 
00940                   while(attrs.available() > 0) {
00941                      type = attrs.read2();
00942                      attrs.read2(); // pad
00943                      int size = attrs.read4();
00944                      ProtocolData adata =
00945                          new ProtocolData(attrs.buf, attrs.pos, size);
00946                      attrs.skipBytes(size);
00947                      switch(type) {
00948                        case INPUTMETHOD_LIST:
00949                          while(adata.available() > 0) {
00950                             String imHRN = adata.readString();
00951                             String imID = adata.readString();
00952                             debug("im = " + imHRN + ":" + imID);
00953                             int len = adata.read4();
00954                             ProtocolData ldata =
00955                                 new ProtocolData(adata.buf, adata.pos, len);
00956                             adata.skipBytes(len);
00957                             while(ldata.available() > 0) {
00958                                 String langHRN = ldata.readString();
00959                                 String langID = ldata.readString();
00960                                 debug(" im lang = " +
00961                                      langHRN + "/" + langID);
00962                             }
00963                          }
00964                          break;
00965                        case OBJECT_DESCRIPTER_LIST:
00966                          while(adata.available() > 0) {
00967                             int objCategory = adata.read2();
00968                             adata.read2(); // pad 
00969                             int objSize = adata.read4();
00970                             int attribID = adata.read2();
00971                             int dattribID = adata.read2();
00972                             if (objCategory == SYNTAX_RULE_CATEGORY) {
00973                                 ccdefID = dattribID;
00974                             } else if (objCategory == MANAGE_RULE_CATEGORY) {
00975                                 manageRuleID = dattribID;
00976                             }
00977                             String objName = adata.readString();
00978                             String objHRN = adata.readString();
00979                             String objSignature = adata.readString();
00980                             String objUser = adata.readString();
00981                             IIIMPObjectDescripter objDesc =
00982                                 new IIIMPObjectDescripter(objCategory,
00983                                                        objSize,
00984                                                        attribID,
00985                                                        dattribID,
00986                                                        objName,
00987                                                        objHRN,
00988                                                        objSignature,
00989                                                        objUser);
00990                             doSet.add(objDesc);
00991                          }
00992                          break;
00993                        default:
00994                          debug(" unknown attribID");
00995                          break;
00996                      }
00997                   }
00998               }
00999               replyData.write2(imServerID);
01000               replyData.write2(0); // pad
01001               send(new Protocol(IM_SETIMVALUES_REPLY, replyData));
01002               break;
01003            }
01004          case IM_SETIMVALUES_REPLY:
01005            debug("IM_SETIMVALUES_REPLY");
01006            
01007            data.read2(); // for pad
01008            break;
01009          
01010          case IM_GETIMVALUES_REPLY:
01011            {
01012                debug("IM_GETIMVALUES_REPLY");
01013            
01014                data.read2(); // for pad
01015               data.read4(); // size , not used
01016                
01017               while(data.available() > 0) {
01018                   debug(" data.available() = " + data.available());
01019                   int attrID = data.read2();
01020                   debug(" attrID = " + attrID);
01021                   
01022                   data.read2(); // for pad
01023                   int size = data.read4();
01024                   debug("attrsize = " + size);
01025 
01026                   // CCDEF & ManageRule object downloading
01027                   if (attrID == ccdefID) {
01028                      String ccdef = data.readString();
01029                      Manager manager = Manager.getInstance();
01030                      manager.setCCDEF(ccdef);
01031                      continue;
01032                   } else if (attrID == manageRuleID) {
01033                      String mr = data.readString();
01034                      Manager manager = Manager.getInstance();
01035                      manager.setManageRule(new ManageRule(mr));
01036                      continue;
01037                   }
01038 
01039                   if (size > 0) {
01040                      int classNameListSize = data.read4();
01041                      debug(" cnls = " + classNameListSize);
01042                      ProtocolData classNameData =
01043                          new ProtocolData(data.buf, data.pos, classNameListSize);
01044                      data.skipBytes(classNameListSize);
01045                      while(classNameData.available() > 0) {
01046                          String className = classNameData.readString();
01047                          classNameSet.add(className);
01048                          debug(" class = " + className);
01049                      }
01050                      int jarSize = data.read4();
01051                      debug(" jar size = " + jarSize);
01052                      byte[] attrval = new byte[jarSize];
01053                      data.read(attrval, 0, jarSize);
01054 
01055                      // FileOutputStream out = new FileOutputStream("/tmp/out");
01056                      // out.write(attrval);
01057                      // out.flush();
01058 
01059                      if (odLoader != null) {
01060                          JarInputStream jis =
01061                             new JarInputStream(new ByteArrayInputStream(attrval));
01062                          odLoader.addJar(jis);
01063                      }
01064 
01065                      int pad = ProtocolData.paddings(size);
01066                      debug(" paddings = " + pad);
01067                      for (int i = 0; i < pad; i++) {
01068                          data.read();
01069                      }
01070                   }
01071               }
01072 
01073               if (classNameSet.size() > 0) {
01074                   // check Preedit/Lookup/Status override object
01075                   Iterator it = classNameSet.iterator();
01076                   try {
01077                      while (it.hasNext()) {
01078                          String name = (String)it.next();
01079                          debug(" name = " + name);
01080                          if (odLoader != null) {
01081                             Class cl = odLoader.findClass(name);
01082                             Object o = cl.newInstance();
01083                             Manager manager = Manager.getInstance();
01084 
01085                             if (o instanceof IIIMLookupListener) {
01086                                 manager.setIIIMLookupListener
01087                                    ((IIIMLookupListener)o);
01088                             } else if (o instanceof IIIMPreeditListener) {
01089                                 manager.setIIIMPreeditListener
01090                                    ((IIIMPreeditListener)o);
01091                             } else if (o instanceof IIIMStatusListener) {
01092                                 manager.setIIIMStatusListener
01093                                    ((IIIMStatusListener)o);
01094                             }
01095                          }
01096                      }
01097                   } catch(Exception e) {
01098                      if (Manager.DEBUG) {
01099                          e.printStackTrace();
01100                      }
01101                   }
01102               }
01103 
01104                 break;
01105            }
01106             default:
01107                 break;
01108         }    
01109     }
01110     
01111     synchronized void connectIM() throws IOException {
01112        // for reconnection...
01113        if (url != null) {
01114            connected = connectIMImpl(url);
01115        }
01116 
01117        String urlAddr = Manager.getProperty("iiimp.server");
01118        if (urlAddr == null) {
01119               urlAddr = "iiimp://localhost:9010";
01120        }
01121        URL tmp = new URL(urlAddr);
01122         url = tmp;
01123        connected = connectIMImpl(tmp);
01124        
01125        if (download) {
01126            // Object Downloading setup
01127            setClientType();
01128            download = false;
01129 
01130            // Object Downloading
01131            downloadObject();
01132            download = false;
01133        }
01134     }
01135     
01136     boolean connectIMImpl(URL url) {
01137        try {
01138            uc = (IIIMPURLConnection) url.openConnection();
01139 
01140            if (uc.isConnected() == false) {
01141               uc.connect();
01142               
01143               if (uc.isConnected() == false) {
01144                   throw new IOException();
01145               }
01146            }
01147            
01148            in = new IIIMPInputStream(this, uc.getInputStream());
01149            out = new IIIMPOutputStream(uc.getOutputStream());
01150            openIM();
01151            return true;
01152        } catch (IOException e) {
01153            debug("IOException = " + e);
01154            return false;
01155        }
01156     }
01157     
01158     synchronized void openIM() throws IOException {
01159        if (userName == null) {
01160            userName = System.getProperty("user.name", null);
01161            String hostName = getHostName();
01162            if (hostName != null) {
01163               userName += "@" + hostName;
01164            }
01165            String passwd = getPasswd();
01166            if (passwd != null) {
01167                userName += "#" + passwd;
01168            }
01169        }
01170        if (userName == null) {
01171            throw new IOException();
01172        } 
01173        
01174        // creates protocol for IM_CONNECT
01175        ProtocolData data = new ProtocolData();
01176        data.write(BIGENDIAN); // endian
01177        data.write(VERSION); //protocol version
01178        data.writeString(userName); // user name and host name
01179        data.write2(0);  //client auth protocol names
01180 
01181        Protocol protocol = new Protocol(IM_CONNECT, data);
01182        send(protocol);
01183        
01184        getReply(IM_CONNECT_REPLY);
01185     }
01186     
01187     void closeIM(int imID) throws IOException {
01188        if (connected == false) {
01189            return;
01190        }
01191        
01192        ProtocolData data = new ProtocolData();
01193        data.write2(imID); // input method id
01194        data.write2(0); //padding
01195        
01196        Protocol protocol = new Protocol(IM_DISCONNECT, data);
01197        
01198        send(protocol);
01199        
01200        getReply(IM_DISCONNECT_REPLY);
01201     }                         
01202     
01203     void createIC(int imID, Locale locale) throws IOException {
01204        if (connected == false) {
01205            return ;
01206        }
01207 
01208        // send IM_SETIMVALUES
01209 
01210        ProtocolData data = new ProtocolData();
01211         data.write2(imID);
01212         IIIMPICValues val = new IIIMPICValues(locale);
01213         byte[] buf = val.getListOfICAttr();
01214         
01215         data.write2(buf.length);
01216         data.writeBytes(buf);    
01217         data.write2(0);
01218         
01219         send(new Protocol(IM_CREATEIC, data));
01220         
01221         getReply(IM_CREATEIC_REPLY);
01222     }
01223     
01224     static ProtocolData getCreateICData(int imID) throws IOException {
01225        ProtocolData data = new ProtocolData();
01226        data.write2(imID);
01227        IIIMPICValues val = new IIIMPICValues(Locale.getDefault());
01228        byte[] buf = val.getListOfICAttr();
01229 
01230        data.write2(buf.length);
01231        data.writeBytes(buf);
01232        data.write2(0);
01233 
01234        return data;
01235     }
01236 
01237     void destroyIC(int imID, int icID) throws IOException {
01238        if (connected == false) {
01239            return;
01240        }
01241 
01242        Object[] intArray = aliveIC.toArray();
01243        for (int i = 0; i < intArray.length; i++) {
01244            if (icID == ((Integer)intArray[i]).intValue()) {
01245               ProtocolData data = new ProtocolData();
01246               data.write2(imID);
01247               data.write2(icID);
01248         
01249               send(new Protocol(IM_DESTROYIC, data));
01250               getReply(IM_DESTROYIC_REPLY);
01251 
01252               aliveIC.remove(intArray[i]);
01253               break;
01254            }
01255        }
01256     }
01257 
01258     void setFocus(int imID, int icID, boolean mode) throws IOException {
01259        if (connected == false) {
01260            return;
01261        }
01262 
01263        ProtocolData data = new ProtocolData();
01264        data.write2(imID);
01265        data.write2(icID);
01266 
01267         send(new Protocol(mode ? IM_SETICFOCUS : IM_UNSETICFOCUS, data));
01268         
01269         getReply(mode ? IM_SETICFOCUS_REPLY : IM_UNSETICFOCUS_REPLY);
01270     }
01271 
01272     void resetIC(int imID, int icID) throws IOException {
01273        if (connected == false) {
01274            return;
01275        }
01276         
01277         ProtocolData data = new ProtocolData();
01278         data.write2(imID);
01279         data.write2(icID);
01280         
01281         send(new Protocol(IM_RESETIC, data));
01282         getReply(IM_RESETIC_REPLY);
01283     }
01284                 
01285     void notifyTrigger(int imID, int icID, boolean mode) throws IOException {
01286         if(connected == false) {
01287             return;
01288         }
01289         
01290         ProtocolData ps = new ProtocolData();
01291         ps.write2(imID);
01292         ps.write2(icID);
01293         ps.write2( (mode == true) ? 0 : 1);
01294         
01295         send(new Protocol(IM_TRIGGER_NOTIFY, ps));
01296         getReply(IM_TRIGGER_NOTIFY_REPLY);
01297     }
01298         
01299     void sendAuxData(IIIMAuxEvent ev) throws IOException {
01300        sendAuxData(auxIMID, auxICID, ev.getIndex(),
01301                   ev.getName(), ev.getIntValues(), ev.getStringValues());
01302     }
01303 
01304     void sendAuxData(int imID, int icID, 
01305                      int index, String name, int[] idata, String[] sdata) 
01306                      throws IOException {
01307         if (connected == false) {
01308             return;
01309         }
01310 
01311         ProtocolData data = new ProtocolData();
01312         data.write2(imID);
01313         data.write2(icID);
01314         data.write4(index); // auxiliary window class index
01315         data.writeString(name); // engine name
01316 
01317        if (idata == null) {
01318            data.write4(0);
01319        } else {
01320            ProtocolData d = new ProtocolData();
01321            for (int i = 0; i < idata.length; i++) {
01322               d.write4(idata[i]);
01323            }
01324            data.write4(d.count); // byte length of integer value list
01325            data.writeBytes(d.buf, d.count); // interger value list
01326        }
01327 
01328        if (sdata == null) {
01329            data.write4(0);
01330        } else {
01331            ProtocolData d = new ProtocolData();
01332            for (int i = 0; i < sdata.length; i++) {
01333               d.writeString(sdata[i]);
01334            }
01335            data.write4(d.count); // byte length of string value list
01336            data.writeBytes(d.buf, d.count); // string value list
01337        }
01338 
01339         send(new Protocol(IM_AUX_SETVALUES, data));
01340         getReply(IM_AUX_SETVALUES_REPLY);        
01341     }
01342 
01347     void setClientType() {
01348        debug(" setClientType");
01349        try {
01350            ProtocolData data = new ProtocolData();
01351            int imID = imServer.getID();
01352            data.write2(imID);
01353            data.write2(0); // pad
01354 
01355            IIIMPClientDescripter desc = new IIIMPClientDescripter();
01356            ProtocolData d = desc.getData();
01357            data.write4(d.count);
01358            data.writeBytes(d.buf, d.count);
01359 
01360            send(new Protocol(IM_SETIMVALUES, data));
01361            getReply(IM_SETIMVALUES_REPLY);
01362        } catch(Exception e) {
01363            if (Manager.DEBUG) {
01364               e.printStackTrace();
01365            }
01366        }
01367     }
01368 
01372     void downloadObject() {
01373        if (doSet.size() == 0) {
01374            return;
01375        }
01376        try {
01377            ProtocolData data = new ProtocolData();
01378            int imID = imServer.getID();
01379            data.write2(imID);
01380            data.write2(0); // pad
01381            data.write4(doSet.size() * 2);
01382 
01383            Iterator it = doSet.iterator();
01384            while (it.hasNext()) { 
01385               IIIMPObjectDescripter desc =
01386                   (IIIMPObjectDescripter)it.next();
01387               data.write2(desc.getDAttribID());
01388               debug(desc.toString());
01389            }
01390               
01391            data.pad();
01392            send(new Protocol(IM_GETIMVALUES, data));
01393            getReply(IM_GETIMVALUES_REPLY);
01394        } catch(Exception e) {
01395            if (Manager.DEBUG) {
01396               e.printStackTrace();
01397            }
01398        }
01399     }
01400 
01401     void processKeyEvent(int imID, int icID, KeyEvent e) throws IOException {
01402        if (connected == false) {
01403            return;
01404        }
01405 
01406         ProtocolData data = new ProtocolData();
01407         data.write2(imID);
01408         data.write2(icID);
01409         data.write4(2); // keyevent type is 2
01410         
01411         KeyData kd = new KeyData(e);
01412         data.writeBytes(kd.toByteStream());
01413 
01414         send(new Protocol(IM_FORWARD_EVENT, data));
01415         
01416         getReply(IM_FORWARD_EVENT_REPLY);
01417     }
01418     
01419     private String getHostName() {
01420        try {
01421            java.net.InetAddress hostAddr =
01422               java.net.InetAddress.getLocalHost();
01423            return hostAddr.getHostName();
01424        } catch (Exception e) {}
01425        return null;
01426     }     
01427     
01428     private String getPasswd() {
01429        return (String)AccessController.doPrivileged(new PrivilegedAction() {
01430            public Object run() {
01431               String userHome = System.getProperty("user.home");
01432               File f = new File(userHome + File.separator + ".iiim" +
01433                                File.separator + "auth" + File.separator +
01434                                "passwd");
01435               try {
01436                   if (f != null && f.canRead()) {
01437                       byte[] ba = new byte[32];
01438                      DataInputStream in =
01439                        new DataInputStream(new FileInputStream(f.getPath()));
01440                      in.readFully(ba);
01441                      in.close();
01442                      return new String(ba);
01443                   }
01444                   return createPasswdFile(f);
01445               } catch(Exception e) {
01446                   return createPasswdFile(f);
01447               }
01448            }
01449        });
01450     }
01451 
01452     private static final String CHMOD_CMD = "/usr/bin/chmod";
01453 
01454     private String createPasswdFile(File f) {
01455        try {
01456            // generate random string and passwd file
01457            File fdir = f.getParentFile();
01458            fdir.mkdirs();
01459             DataOutputStream dos =
01460               new DataOutputStream(new FileOutputStream(f.getPath()));
01461            byte[] ba = genPasswd();
01462            dos.write(ba, 0, 32);
01463            dos.flush();
01464            dos.close();
01465            // protect file so that only owner of passwd file can read
01466            // (Solaris only solution)
01467            String osName = System.getProperty("os.name");
01468            if (osName.startsWith("SunOS")) {
01469              Runtime rt = Runtime.getRuntime();
01470              // $HOME/.iiim/auth
01471              rt.exec(CHMOD_CMD + " 700 " + fdir.getPath());
01472              // $HOME/.iiim/auth/passwd
01473              rt.exec(CHMOD_CMD + " 600 " + f.getPath());
01474            }
01475            return new String(ba);
01476        } catch(Exception e) {      
01477            return null;
01478        }  
01479     }
01480 
01481     /*
01482      * Generate 32 byte random string.
01483      */
01484     private byte[] genPasswd() {
01485        SecureRandom sr;
01486        try {
01487            sr = SecureRandom.getInstance("SHA1PRNG");
01488        } catch(NoSuchAlgorithmException e) {
01489            sr = new SecureRandom();
01490        }
01491     
01492        sr.setSeed(System.currentTimeMillis());
01493        
01494        byte[] ba = new byte[32];
01495        sr.nextBytes(ba);
01496        for (int i = 0; i < 32; i++) {
01497            ba[i] = aa[Math.abs(ba[i] % 62)];
01498        }
01499 
01500        return ba;
01501     }
01502 
01503     static byte[] aa = {
01504        (byte)'0', (byte)'1', (byte)'2', (byte)'3',
01505        (byte)'4', (byte)'5', (byte)'6', (byte)'7',
01506        (byte)'8', (byte)'9', (byte)'A', (byte)'B',
01507        (byte)'C', (byte)'D', (byte)'E', (byte)'F',
01508        (byte)'G', (byte)'H', (byte)'I', (byte)'J',
01509        (byte)'K', (byte)'L', (byte)'M', (byte)'N',
01510        (byte)'O', (byte)'P', (byte)'Q', (byte)'R',
01511        (byte)'S', (byte)'T', (byte)'U', (byte)'V',
01512        (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
01513        (byte)'a', (byte)'b', (byte)'c', (byte)'d',
01514        (byte)'e', (byte)'f', (byte)'g', (byte)'h',
01515        (byte)'i', (byte)'j', (byte)'k', (byte)'l',
01516        (byte)'m', (byte)'n', (byte)'o', (byte)'p',
01517        (byte)'q', (byte)'r', (byte)'s', (byte)'t',
01518        (byte)'u', (byte)'v', (byte)'w', (byte)'x',
01519        (byte)'y', (byte)'z',
01520     };
01521     
01522     public void activate() {
01523         debug("Enter activate");
01524         try {
01525             if(connected == false) connectIM();
01526             if(connected == false) return;
01527             
01528             java.awt.im.InputContext tmp = getInputContext();
01529 
01530             if(tmp == null) return;
01531             
01532             int icID = imServer.getInputContextID(tmp);
01533             Manager manager = Manager.getInstance();
01534 
01535             if(icID == -1) {
01536                 inputContext = new InputContext(tmp, this);
01537                 imServer.addInputContextHandler(inputContext);
01538                 prevLocale = manager.getCurrentLocale();
01539                 inputContext.create(imServer, manager.getCurrentLocale());
01540               inputContext.setPreeditListener(manager.getIIIMPreeditListener());
01541               inputContext.setCommittedListener(manager.getIIIMCommittedListener());
01542             } else {
01543                if (prevLocale.equals(manager.getCurrentLocale())){
01544                  debug("prevLocale and CurrentLocale are the same");
01545                } else {
01546                  prevLocale = manager.getCurrentLocale();
01547                  inputContext.create(imServer, manager.getCurrentLocale());
01548                 inputContext.setPreeditListener(manager.getIIIMPreeditListener());
01549                 inputContext.setCommittedListener(manager.getIIIMCommittedListener());
01550                }
01551             }
01552             if (inputContext != null) {
01553               inputContext.activate();
01554             }
01555         } catch(IOException e) {
01556            if (Manager.DEBUG) {
01557               e.printStackTrace();
01558            }
01559         }
01560         
01561     }
01562     
01563     public void deactivate(boolean isTemporary) {
01564         debug("Enter deactivate");
01565         
01566         if(inputContext != null)
01567             inputContext.deactivate();
01568     }
01569     
01570     public void removeNotify() {
01571        //dispose();
01572     }
01573     
01574     public void endComposition() {
01575         debug("Enter endComposition");
01576         
01577         synchronized(this) {
01578         if(inputContext != null) 
01579             inputContext.reset(false);
01580         }
01581     }
01582     
01583     public void dispose() {
01584         debug("Enter dispose");
01585         if(inputContext != null) 
01586             inputContext.dispose();
01587         done();
01588     }
01589 
01590     private void done() {
01591         dispatchPreeditEvent(new IIIMPreeditEvent(IIIMPreeditEvent.DONE));
01592         dispatchCommittedEvent(new IIIMCommittedEvent(""));
01593         dispatchStatusEvent(new IIIMStatusEvent(IIIMStatusEvent.DONE));
01594         dispatchLookupEvent(new IIIMLookupEvent(IIIMLookupEvent.DONE));
01595     }
01596         
01597     public void actionPerformed(IIIMActionEvent e) {
01598        if (e.getType() == IIIMActionEvent.FORWARD_STRING) {
01599            String[] args = (String[])e.getArg();
01600            if (args.length != 2) {
01601               return;
01602            }
01603 
01604            String action = args[0];
01605            String content = args[1];
01606 
01607            try {
01608               inputContext.deliverStringEvent(action, content);
01609            } catch(Exception ex) {
01610               if (Manager.DEBUG) {
01611                   ex.printStackTrace();
01612               }
01613            }
01614        }
01615     }
01616               
01617     void forwardEventWithOperation(int imID, int icID, String action, String content)
01618        throws IOException {
01619 
01620        ProtocolData data = new ProtocolData();
01621        data.write2(imID);
01622        data.write2(icID);
01623        // PD supports only "convert"/Sting type of operation now.
01624        data.write4(0); // STRING type
01625        data.writeString(content);
01626 
01627        ProtocolData operation = new ProtocolData();
01628        operation.writeString(action);
01629        operation.write2(0); // there is no value associated with "convert" action
01630        operation.pad();
01631 
01632        data.write4(operation.count);
01633        data.writeBytes(operation.buf, operation.count);
01634 
01635        send(new Protocol(IM_FORWARD_EVENT_WITH_OPERATIONS, data));
01636 
01637        getReply(IM_FORWARD_EVENT_WITH_OPERATIONS_REPLY);
01638     }
01639 
01640     public static void main(String[] args) {
01641         try {
01642             ProtocolDriver pd = new ProtocolDriver();
01643             pd.connectIM();
01644         } catch(IOException e) {
01645            if (Manager.DEBUG) {
01646               e.printStackTrace();
01647            }
01648         }
01649 
01650     }
01651 
01652     private static final String IIIMP_PGK_PREFIX = "sun.awt.im";
01653     private static final String JAVA_PROTOCOL_HANDLER_PKGS = 
01654                                           "java.protocol.handler.pkgs";
01655 
01656     static {
01657         // Add sun.awt.im to the java.protocol.handler.pkgs property
01658         // if it is not defined yet.
01659         AccessController.doPrivileged(new PrivilegedAction() {
01660             public Object run() {
01661                 Properties defaults = System.getProperties();
01662                 synchronized (defaults) {
01663                     String pkgs = defaults.getProperty(
01664                                     JAVA_PROTOCOL_HANDLER_PKGS);
01665                     if (pkgs == null) {
01666                         pkgs = IIIMP_PGK_PREFIX;
01667                     } else {
01668                         StringTokenizer pkgPrefixIter = new StringTokenizer(pkgs, "|");
01669                         while (pkgPrefixIter.hasMoreTokens()) {
01670                             if (pkgPrefixIter.nextToken().equals(IIIMP_PGK_PREFIX)) {
01671                                 return null;
01672                             }
01673                         }
01674                         pkgs += "|" + IIIMP_PGK_PREFIX;
01675                     }
01676                     defaults.put(JAVA_PROTOCOL_HANDLER_PKGS, pkgs);
01677                 }
01678                 return null;
01679             }
01680         });
01681     }
01682     
01683     void debug(String string) {
01684         if (Manager.DEBUG) {
01685            System.err.println(string);
01686        }
01687     }
01688 
01689     public String getName() {
01690        return "IIIM ProtocolDriver";
01691     }
01692 
01693     public String[] getEngineScript() {
01694        return null;
01695     }
01696 
01697     public IIIMEvent[] getTriggerEvent() {
01698        return null;
01699     }
01700 
01701     public IIIMEvent[] getTriggerOffEvent() {
01702        return null;
01703     }
01704 
01705     public void setTriggerEvent() {
01706        return;
01707     }
01708 
01709     public void setTriggerOffEvent() {
01710        return;
01711     }
01712 
01713     public Locale[] getSupportLocales() {
01714        return imServer.getAvailableLocales();
01715     }
01716 
01717     static Locale toLocale(String str) {
01718        if (str == null || str.length() == 0) {
01719            return null;
01720        }
01721 
01722        // if str is a locale name that is defined in the spec...
01723        if (str.equals("ja")) {
01724            return Locale.JAPAN;
01725         } else if (str.equals("ko")) {
01726            return Locale.KOREAN;
01727         } else if (str.equals("zh_TW")) {
01728            return Locale.TRADITIONAL_CHINESE;
01729         } else if (str.equals("zh_CN")) {
01730            return Locale.SIMPLIFIED_CHINESE;
01731         } 
01732 
01733        // if str is not in the spec...
01734        int index = str.indexOf('_');
01735        if (index > 0) {
01736            String language = str.substring(0, index);
01737            String country = str.substring(index + 1);
01738            return new Locale(language, country);
01739        }
01740        return new Locale(str, "");
01741     }
01742 
01743     static String toLocaleString(Locale locale) {
01744        if (locale == null) {
01745            return null;
01746        }
01747 
01748         String loc = locale.getLanguage();
01749         String region = locale.getCountry();
01750         String locale_string = "";
01751 
01752        if (loc.equals("ja")) {
01753            return "ja";
01754         } else if (loc.equals("ko")) {
01755            return "ko";
01756         } else if (loc.equals("zh")) {
01757             if (region.equals("TW")) {
01758               return "zh_TW";
01759             } else if (region.equals("CN")){
01760               return "zh_CN";
01761             } else
01762                 return "zh_HK";
01763         } else {
01764            if (region == null || region.length() == 0)
01765              locale_string = loc;
01766            else
01767              locale_string = loc + "_" + region;
01768         }
01769        return locale_string;
01770     }
01771 }
01772 
01773 
01774 class IMServer {
01775     private Vector ichList = new Vector();
01776 
01777     private Locale locale = null;
01778 
01779     private int id = -1;
01780 
01781     private Locale localeList[] = null;
01782 
01783     private IIIMPKey onKey[] = null;
01784 
01785     private IIIMPKey offKey[] = null;
01786 
01787     private boolean dynamic_event_flow = false;
01788 
01789 
01790     IMServer() {
01791     }
01792 
01793     IMServer(int id) {
01794         this.id = id;
01795     }
01796 
01797     boolean open(Locale locale) {
01798        if (isLocaleSupported(locale)) {
01799            this.locale = locale;
01800            return true;
01801        }
01802        return false;
01803     }
01804 
01805     boolean reopen(Locale locale) {
01806         if (isLocaleSupported(locale)) {
01807            this.locale = locale;
01808            return true;
01809        }
01810        return false;
01811     }
01812 
01813     boolean setLocaleList(IIIMPIMValues d) {
01814        if (d == null) {
01815            return false;
01816        }
01817 
01818        // copy IiimpIMValues
01819        id = d.id;
01820        localeList = d.localeList;
01821 
01822        return true;
01823     }
01824 
01825     boolean setTriggerKeys(IIIMPIMValues d) {
01826        if (d == null) {
01827            return false;
01828        }
01829 
01830        // copy IiimpIMValues
01831        id = d.id;
01832        dynamic_event_flow = d.dynamic_event_flow;
01833        onKey = d.onKey;
01834        offKey = d.offKey;
01835 
01836        return true;
01837     }
01838 
01839     public Locale[] getAvailableLocales() {
01840        if (localeList == null) {
01841            return null;
01842        }
01843         Locale[] tmp = new Locale[localeList.length];
01844        System.arraycopy(localeList, 0, tmp, 0, localeList.length);
01845        return tmp;
01846     }
01847 
01848     void addInputContextHandler(InputContext ich) {
01849        ichList.addElement(ich);
01850     }
01851 
01852     void removeInputContextHandler(InputContext ich) {
01853        ichList.removeElement(ich);
01854     }
01855 
01856     InputContext getInputContext(int id) {
01857        for (int i = 0; i < ichList.size(); i++) {
01858            InputContext ic = (InputContext) ichList.elementAt(i);
01859            if (ic.getID() == id) {
01860               return ic;
01861            }
01862        }
01863        return (InputContext) null;
01864     }
01865 
01866     public InputContext[] getInputContext() {
01867        if (ichList.size() == 0) {
01868            return null;
01869        }
01870        InputContext[] ich = new InputContext[ichList.size()];
01871        ichList.copyInto(ich);
01872        return ich;
01873     }
01874 
01875     int getID() {
01876        return id;
01877     }
01878 
01879     int getInputContextID(java.awt.im.InputContext ic) {
01880         InputContext[] inputContext = getInputContext();
01881         
01882         if(inputContext == null) {
01883             debug("InputContext is null, return -1");
01884             return -1; // I don't know -1 is exact
01885         }
01886         for(int i=0; i < inputContext.length; i++) {
01887             if(inputContext[i].isIn(ic)) return inputContext[i].getID();
01888         }
01889         
01890         debug("There are no ic in it, return -1");
01891         return -1;
01892     }
01893     
01894     private void debug(String str) {
01895        if (Manager.DEBUG) {
01896            System.err.println(str);
01897        }
01898     }
01899 
01900     boolean isDynamicEventFlow() {
01901        return dynamic_event_flow;
01902     }
01903 
01904     boolean isConversionOnKey(KeyEvent e) {
01905        int mod = e.getModifiers();
01906        int code = e.getKeyCode();
01907        if (onKey != null) {
01908            for (int i = 0; i < onKey.length; i++) {
01909               if ((mod & onKey[i].modifier) != 0) {
01910                   if (code == onKey[i].keycode) {
01911                      return true;
01912                   }
01913               }
01914            }
01915        }
01916        return false;
01917     }
01918 
01919     boolean isConversionOffKey(KeyEvent e) {
01920        int mod = e.getModifiers();
01921        int code = e.getKeyCode();
01922        if (offKey != null) {
01923            for (int i = 0; i < offKey.length; i++) {
01924               if ((mod & offKey[i].modifier) != 0) {
01925                   if (code == offKey[i].keycode) {
01926                      return true;
01927                   }
01928               }
01929            }
01930        }
01931        return false;
01932     }
01933 
01934     boolean isLocaleSupported(Locale locale) { 
01935         if (localeList != null && localeList.length > 0) {
01936             for (int i = 0; i < localeList.length; i++) {
01937                 if (localeEquals(locale, localeList[i]) == true) {
01938                     return true;
01939                 }
01940             }
01941         }        
01942         return false;
01943     }
01944 
01945     static boolean localeEquals(java.util.Locale loc1, java.util.Locale loc2) {
01946        if (loc1 == null || loc2 == null) {
01947            return false;
01948        }
01949 
01950        String lang = loc1.getLanguage();
01951         if (lang.equals("en") ||
01952            lang.equals("fr") ||
01953            lang.equals("de") ||
01954            lang.equals("it") ||
01955            lang.equals("sv") ||
01956            lang.equals("es") ||
01957            lang.equals("ja") ||
01958            lang.equals("ko")) {
01959            return lang.equals(loc2.getLanguage());
01960        }
01961 
01962        if (lang.equals("zh")) {
01963            if (lang.equals(loc2.getLanguage())) {
01964               String region = loc1.getCountry();
01965               if (region != null && region.length() > 0) {
01966                   return region.equals(loc2.getCountry());
01967               }
01968               return true;
01969            }
01970            return false;
01971         }
01972        
01973        return lang.equals(loc2.getLanguage());
01974     }
01975 
01976 }
01977 
01978 class InputContext {
01979 
01980     private int id = 0;
01981 
01982     private Locale locale = null;
01983 
01984     private boolean active = false;
01985 
01986     private boolean connected = false;
01987     
01988     private boolean convMode = false;
01989 
01990     private boolean isForwardEvent = false;
01991 
01992     private IMServer im = null;
01993     
01994     private ProtocolDriver client = ProtocolDriver.getInstance();
01995     
01996     private java.awt.im.InputContext ic;
01997     
01998     private IIIMPreeditListener preeditListener;
01999 
02000     private IIIMCommittedListener committedListener;
02001 
02002     // Maybe it should be AttrbutedString
02003     // private StringBuffer preeditContent = new StringBuffer();
02004     private class ComposedChar {
02005        char c;
02006        java.awt.im.InputMethodHighlight attr;
02007     }
02008     private Vector composedText = new Vector();
02009     
02010     // It maybe changed
02011     InputContext(java.awt.im.InputContext ic, ProtocolDriver client) {
02012         this.ic = ic;
02013         this.client = client;
02014     }
02015 
02016     void setPreeditListener(IIIMPreeditListener listener) {
02017        preeditListener = listener;
02018     }
02019 
02020     void setCommittedListener(IIIMCommittedListener listener) {
02021        committedListener = listener;
02022     }
02023 
02024     IIIMPreeditListener getPreeditListener() {
02025        return preeditListener;
02026     }
02027 
02028     IIIMCommittedListener getCommittedListener() {
02029        return committedListener;
02030     }
02031 
02032     public IMServer getIMServer() {
02033        return im;
02034     }
02035 
02036     void create(IMServer im, Locale lc) {
02037         this.im = im;
02038        locale = lc;
02039         active = false;
02040 
02041        try {
02042            client.createIC(im.getID(), locale);
02043             if (isConversionMode() == true)
02044               setConversionMode(true); 
02045        } catch (Exception e) {
02046            debug("InputContext createIC: " + e);
02047        }
02048     }
02049 
02050     public void activate() {
02051         if (active == true) {
02052             return;
02053         }
02054         active = true;
02055         setFocus(true);
02056     }
02057 
02058     public void dispose() {
02059         try {
02060             client.destroyIC(im.getID(), id);
02061         } catch (Exception e) {
02062            if (Manager.DEBUG) {
02063               e.printStackTrace();
02064            }
02065        }
02066         im.removeInputContextHandler(this);
02067     }
02068 
02069     public void deactivate() {
02070         if (active == false) {
02071             return;
02072         }
02073         active = false;
02074         setFocus(false);
02075     }
02076 
02077     private boolean beingProcessed = false;
02078 
02079     public void dispatchKeyEvent(KeyEvent kev) {
02080        if (beingProcessed && (kev.getID() == KeyEvent.KEY_TYPED ||
02081                        kev.getID() == KeyEvent.KEY_RELEASED)) {
02082            kev.consume();
02083            return;
02084        }
02085        beingProcessed  = dispatchKeyEventImpl(kev);
02086        if (beingProcessed == true) {
02087            kev.consume();
02088        }
02089     }
02090     
02091     private boolean isUninterestingModifiers(KeyEvent kev) {
02092         switch (kev.getKeyCode()) {
02093         case KeyEvent.VK_CONTROL:
02094         case KeyEvent.VK_CAPS_LOCK:
02095         case KeyEvent.VK_ALT:
02096         case KeyEvent.VK_META:
02097         case KeyEvent.VK_SHIFT:
02098             return true;
02099         }
02100         return false;
02101     }
02102 
02103     private boolean dispatchKeyEventImpl(KeyEvent kev) {
02104         if (isConversionMode() == true) {
02105             if (isUninterestingModifiers(kev) == true) {
02106                 return true;
02107             }
02108             if (kev.getID() == KeyEvent.KEY_TYPED) {
02109                 return (isForwardEvent == true) ? false : true;
02110             }
02111             if (kev.getID() == KeyEvent.KEY_RELEASED) {
02112                 return (isForwardEvent == true) ? false : true;
02113             }
02114         } else {
02115             if (isUninterestingModifiers(kev) == true) {
02116                 return false;
02117             }
02118         }
02119 
02120         if (connected == false) {
02121             if (im.isConversionOnKey(kev) == true) {
02122                 if (im.reopen(locale) == true) {
02123                     if (reconnect() == true) {
02124                         activate();
02125                         setConversionMode(true);
02126                     }
02127                 } 
02128                 return true;
02129             }
02130             return false;
02131         }
02132         if (isForwardEvent == true) {
02133             isForwardEvent = false;
02134         }
02135 
02136         if (im.isDynamicEventFlow() == true) {
02137             // conversion on
02138             if (isConversionMode() == true) {
02139                 // turn off the conversion if the conversion mode is on
02140                 if (im.isConversionOffKey(kev) == true) {
02141                     setConversionMode(false);
02142                     return true;
02143                 }
02144                 return deliverKeyEvent(kev);
02145             }
02146             // conversion off
02147             else {
02148                 // turn on the conversion if the conversion mode is off
02149                 if (im.isConversionOnKey(kev) == true) {
02150                     setConversionMode(true);
02151                     return true;
02152                 }
02153             }
02154             return false;
02155         } 
02156 
02157         return deliverKeyEvent(kev);
02158     }
02159 
02160     void setForward() {
02161        isForwardEvent = true;
02162     }
02163 
02164     private boolean deliverKeyEvent(KeyEvent kev) {
02165         try {
02166             client.processKeyEvent(im.getID(), id, kev);
02167             if (isForwardEvent == true) {
02168                 return false;
02169             }
02170             return true;
02171         } catch (Exception e) {
02172            if (Manager.DEBUG) {
02173               e.printStackTrace();
02174            }
02175         }
02176         return false;
02177     }
02178 
02179     void deliverStringEvent(String action, String content) throws IOException {
02180        client.forwardEventWithOperation(im.getID(), id, action, content);
02181     }
02182 
02183     public void reset(boolean state_is_preserved) {
02184         try {
02185             client.resetIC(im.getID(), id);
02186         } catch (Exception e) {
02187            if (Manager.DEBUG) { 
02188               e.printStackTrace();
02189            }
02190        }
02191         if (state_is_preserved == false) {
02192             setConversionMode(false);
02193         }
02194     }
02195 
02196     void setID(int id) {
02197         this.id = id;
02198         connected = true;
02199     }
02200     
02201     int getID() {
02202         return id;
02203     }
02204 
02205     private void setConversionMode(boolean mode) {
02206         try {
02207             client.notifyTrigger(im.getID(), id, mode);
02208         } catch (Exception e) {
02209            if (Manager.DEBUG) {
02210               e.printStackTrace();
02211            }
02212        }
02213         convMode = mode;
02214     }    
02215 
02216     // This method will be called when IM_TRIGGER_NOTIRY comes from server side
02217     void setConversionModeOff() {
02218        convMode = false;
02219     }
02220 
02221     private boolean reconnect() {
02222         if (connected == true) {
02223             return true;
02224         }
02225         try {
02226             client.createIC(im.getID(), locale);
02227         } catch (Exception e) {
02228            if (Manager.DEBUG) {
02229               e.printStackTrace();
02230            }
02231             return false;
02232         }
02233         connected = true;
02234         return true;
02235     }
02236     
02237     private void setFocus(boolean mode) {
02238         try {
02239             client.setFocus(im.getID(), id, mode);
02240         } catch (Exception e) {
02241            if (Manager.DEBUG) {
02242               e.printStackTrace();
02243            }
02244        }
02245     }
02246 
02247     private boolean isConversionMode() {
02248         return (connected == false) ? false : convMode;
02249     
02250         //return convMode;
02251     }
02252     
02253     public boolean isIn(java.awt.im.InputContext ic) {
02254         if(this.ic == ic) return true;
02255         else return false;
02256     }
02257     
02258     public void removeContentAt(int index) {
02259        if (composedText.size() > index) {
02260            composedText.removeElementAt(index);
02261        }
02262     }
02263     
02264     public void insertContentAt(FeedbackChar c, int index) {
02265         ComposedChar comp = new ComposedChar();
02266         comp.c = c.c;
02267         comp.attr = convertVisualFeedbackToHighlight(c.fd[0].value);
02268         composedText.insertElementAt(comp, index);
02269     }
02270     
02271     AttributedString getAttributedString() {
02272        if (composedText.isEmpty() == true) {
02273            return new AttributedString("");
02274        }
02275 
02276        ComposedChar[] c = new ComposedChar[composedText.size()];
02277        composedText.copyInto(c);
02278 
02279        StringBuffer buf = new StringBuffer();
02280        for (int i = 0; i < c.length; i++) {
02281            buf.append(c[i].c);
02282        }
02283        AttributedString attrstr = new AttributedString(buf.toString());
02284            
02285        int start = 0;
02286        int i = 0;
02287        InputMethodHighlight cur = c[0].attr;
02288        for (; i < c.length; i++) {
02289            InputMethodHighlight next = c[i].attr;
02290            if (next != cur) {
02291               if (cur != null) {
02292                   attrstr.
02293                   addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
02294                              cur, start, i);
02295               }
02296               cur = next;
02297               start = i;
02298            }
02299        }
02300        if (cur != null) {
02301            attrstr.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
02302                           cur, start, i);
02303        }
02304 
02305        return attrstr;
02306     }
02307     
02308     
02309     private InputMethodHighlight convertVisualFeedbackToHighlight(int
02310                                                           feedback) {
02311        InputMethodHighlight h;
02312        switch (feedback) {
02313        case sun.awt.im.iiimp.FeedbackType.UNDERLINE:
02314            h = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
02315            break;
02316        case sun.awt.im.iiimp.FeedbackType.REVERSE:
02317            h = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
02318            break;
02319        case sun.awt.im.iiimp.FeedbackType.HIGHLIGHT:
02320            h = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT;
02321            break;
02322        case sun.awt.im.iiimp.FeedbackType.PRIMARY:
02323            h = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
02324            break;
02325        case sun.awt.im.iiimp.FeedbackType.SECONDARY:
02326            h = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
02327            break;
02328        case sun.awt.im.iiimp.FeedbackType.TERTIARY:
02329        default:
02330            h = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT;
02331            break;
02332        }
02333        return h;
02334     }    
02335     
02336     public void done() {
02337         active = false;
02338         convMode = false;
02339         isForwardEvent = false;    
02340         composedText = new Vector();
02341     }
02342 
02343     private void debug(String str) {
02344        if (Manager.DEBUG) {
02345            System.err.println(str);
02346        }
02347     }
02348 }
02349 
02350 
02351 class FeedbackChar {
02352 
02353     char c;
02354 
02355     FeedbackType fd[];
02356 
02357     FeedbackChar() {
02358         c = 0;
02359         fd = null;
02360     }
02361 
02362     void addFeedbackType(int i, int j) {
02363         if(fd == null) {
02364             fd = new FeedbackType[1];
02365             fd[0] = new FeedbackType(i, j);
02366             return;
02367         }
02368 
02369         FeedbackType inputmethodfeedback = null;
02370         for(int l = 0; l < fd.length; l++) {
02371             if(fd[l].id != i)
02372                 continue;
02373             inputmethodfeedback = fd[l];
02374             break;
02375         }
02376 
02377         if(inputmethodfeedback != null) {
02378             inputmethodfeedback.value &= j;
02379             return;
02380         } else {
02381             int k = fd.length;
02382             FeedbackType ainputmethodfeedback[] =
02383               new FeedbackType[k + 1];
02384             System.arraycopy(fd, 0, ainputmethodfeedback, 0, k);
02385             fd = ainputmethodfeedback;
02386             fd[k] = new FeedbackType(i, j);
02387             return;
02388         }
02389     }
02390 }
02391 
02392 class FeedbackText implements IIIMProtocol {
02393 
02394     int count;
02395     FeedbackChar value[];
02396 
02397     public String toString() {
02398        if (count == 0) {
02399            return null;
02400        }
02401        StringBuffer sb = new StringBuffer();
02402        for (int i = 0; i < count; i++) {
02403            sb.append(value[i].c);
02404        }
02405        return sb.toString();
02406     }
02407 
02408     FeedbackText() {
02409        super();
02410        count = 0;
02411        value = new FeedbackChar[8];
02412     }
02413 
02414     void append(FeedbackChar c) {
02415        ensureCapacity(count + 1);
02416        value[count++] = c;
02417     }
02418 
02419     void ensureCapacity(int minimumNum) {
02420        int maxNum = value.length;
02421        if (minimumNum > maxNum) {
02422            int newNum = (maxNum + 1) * 2;
02423            if (minimumNum > newNum) {
02424               newNum = minimumNum;
02425            }
02426            FeedbackChar newValue[] = new FeedbackChar[newNum];
02427            System.arraycopy(value, 0, newValue, 0, count);
02428            value = newValue;
02429        }
02430     }
02431 
02432     static FeedbackText toFeedbackText(ProtocolData d) throws IOException {
02433        int len = d.read4();
02434        if (len == 0) {
02435            return (FeedbackText) null;
02436        }
02437        return toFeedbackTextImpl(d, len);
02438     }
02439 
02440     static AttributedCharacterIterator toACIterator(FeedbackText text) {
02441        AttributedString as = new AttributedString(text.toString());
02442 
02443        if (Manager.COLOR_SUPPORT) {
02444            for (int i = 0; i < text.count; i++) {
02445               for (int j = 0; j < text.value[i].fd.length; j++) {
02446                   switch(text.value[i].fd[j].id) {
02447                     case DECORATION_FEEDBACK:
02448                      switch(text.value[i].fd[j].value) {
02449                        case FeedbackType.REVERSE:
02450                          as.addAttribute(TextAttribute.SWAP_COLORS,
02451                                        TextAttribute.SWAP_COLORS_ON,
02452                                        i, i + 1);
02453                          break;
02454                        case FeedbackType.UNDERLINE:
02455                          as.addAttribute(TextAttribute.UNDERLINE,
02456                                        TextAttribute.UNDERLINE_ON,
02457                                        i, i + 1);
02458                        case FeedbackType.NORMAL:
02459                        default:
02460                      }
02461                      break;
02462                     case FOREGROUND_RGB_FEEDBACK:
02463                      as.addAttribute(TextAttribute.FOREGROUND,
02464                                    new Color(text.value[i].fd[j].value),
02465                                    i, i + 1);
02466                      break;
02467                     case BACKGROUND_RGB_FEEDBACK:
02468                      as.addAttribute(TextAttribute.BACKGROUND,
02469                                    new Color(text.value[i].fd[j].value),
02470                                    i, i + 1);
02471                      break;
02472                     case UNDERLINE_RGB_FEEDBACK:
02473                      as.addAttribute(TextAttribute.FOREGROUND,
02474                                    new Color(text.value[i].fd[j].value),
02475                                    i, i + 1);
02476                      break;
02477                     default:
02478                   }
02479               }
02480            }
02481        }
02482 
02483        AnnotationValue[] ava = text.getAnnotation();
02484        if (ava != null) {
02485            for (int i = 0; i < ava.length; i++) {
02486               as.addAttribute(ava[i].getAttribute(),
02487                             ava[i].getValue(),
02488                             ava[i].getStart(),
02489                             ava[i].getEnd());
02490            }
02491        }
02492 
02493        return as.getIterator();
02494     }
02495 
02496     static private FeedbackText toFeedbackTextImpl(
02497        ProtocolData d, int len) throws IOException {
02498        FeedbackText im = new FeedbackText();
02499 
02500        int upto = d.pos + len;
02501        while (d.pos < upto) {
02502            FeedbackChar ic = new FeedbackChar();
02503            ic.c = (char) d.read2();
02504            int fb_len = d.read2();
02505            for (int i = 0; i < fb_len; i += 8) {
02506               int id = d.read4();
02507               int val = d.read4();
02508               ic.addFeedbackType(id, val);
02509            }
02510 
02511            im.append(ic);
02512        }
02513 
02514        // read Annotation information and set to FeedbackText
02515        //
02516        // Now only READING/AttributedCharacterIterator.Attribute.READING
02517        // and CLAUSE/AttributedCharacterIterator.Attribute.INPUT_METHOD_SEGMENGT
02518        // annotation (is implemented as referennce for
02519        // future implementation. Other annotation will be implemented
02520        // when server side will implement these features.
02521        //
02522        int atLen = d.read4();
02523        if (atLen != 0) {
02524            while (d.available() > 0) {
02525               int attrID = d.read4();
02526               int size = 0;
02527               AnnotationValue[] ava = null;
02528               switch (attrID) {
02529                 case INPUT_STRING:
02530                   size = d.read4();
02531                   d.skipBytes(size);
02532                   break;
02533                 case READING:
02534                   ava = d.readTextAnnotationValues(Attribute.READING);
02535                   im.setAnnotation(ava);
02536                   break;
02537                 case PART_OF_SPEECH:
02538                   size = d.read4();
02539                   d.skipBytes(size);
02540                   break;
02541                 case CLAUSE:
02542                   ava = 
02543                      d.readStringAnnotationValues(Attribute.INPUT_METHOD_SEGMENT);
02544                   im.setAnnotation(ava);
02545                   d.skipBytes(size);
02546                   break;
02547                 default:
02548               }
02549            }
02550        }
02551 
02552        return (FeedbackText) im;
02553     }
02554 
02555     static FeedbackText[] toListOfFeedbackText(ProtocolData d)
02556        throws IOException {
02557        final int thread = 26; // number of alphabets
02558 
02559        int num_ret = thread;
02560        FeedbackText[] ret = new FeedbackText[thread];
02561 
02562        int num = 0;
02563        for (;; num++) {
02564            if (d.available() == 0) {
02565               break;
02566            }
02567            int len = d.read4();
02568            if (len == 0) {
02569               break;
02570            }
02571            if (num == num_ret) {
02572               FeedbackText[] tmp =
02573                   new FeedbackText[num_ret + thread];
02574               System.arraycopy(ret, 0, tmp, 0, num_ret);
02575               ret = tmp;
02576               num_ret += thread;
02577            }
02578            ret[num] = toFeedbackTextImpl(d, len);
02579        }
02580 
02581        if (num > 0) {
02582            FeedbackText[] tmp = new FeedbackText[num];
02583            System.arraycopy(ret, 0, tmp, 0, num);
02584            return tmp;
02585        }
02586 
02587        return (FeedbackText[]) null;
02588     }
02589 
02590     private AnnotationValue[] annotations = null;
02591 
02592     void setAnnotation(AnnotationValue[] annotations) {
02593        this.annotations = annotations;
02594     }
02595     
02596     AnnotationValue[] getAnnotation() {
02597        return annotations;
02598     }
02599 }
02600 
02601 class FeedbackType {
02602 
02603     public final static int NORMAL               = 0;
02604     public final static int REVERSE              = (1 << 0);
02605     public final static int UNDERLINE            = (1 << 1);
02606     public final static int HIGHLIGHT            = (1 << 2);
02607     public final static int PRIMARY              = (1 << 5);
02608     public final static int SECONDARY            = (1 << 6);
02609     public final static int TERTIARY             = (1 << 7);
02610 
02614     public int id;
02615 
02619     public int value;
02620 
02621     public FeedbackType() {
02622        this(0, 0);
02623     }
02624 
02625     public FeedbackType(int id, int value) {
02626        this.id = id;
02627        this.value = value;
02628     }
02629 }
02630 
02632 
02633 class IIIMPIMValues {
02634     int id;
02635     IIIMPKey onKey[];
02636     IIIMPKey offKey[];
02637     Locale localeList[];
02638     boolean dynamic_event_flow;
02639 }
02640 
02646 class IIIMPICValues implements IIIMProtocol {
02647 
02648     Locale locale;
02649 
02650     IIIMPICValues(Locale locale) {
02651        this.locale = locale;
02652     }
02653 
02654     IIIMPICValues(byte[] buf) throws IOException {
02655        ProtocolData d = new ProtocolData(buf, buf.length);
02656 
02657        while (d.available() > 0) {
02658            int id = d.read2();
02659 
02660            int len = d.read2(); // byte length of attr
02661 
02662            byte[] attr = new byte[len]; // attribute array
02663            d.read(attr, 0, len);
02664 
02665            int pad = d.paddings(len); // number of pad
02666            d.skipBytes(pad); // skip pad
02667 
02668            /*
02669             * Currently only InputLanguage is supported.
02670             */
02671            if (id == IC_INPUT_LANGUAGE) {
02672               setInputLanguage(attr);
02673            }
02674 
02675            /*
02676             * switch (id) {
02677             * case IC_INPUT_LANGUAGE:
02678             * getInputLocale(attr);
02679             * break;
02680             * }
02681             */
02682        }
02683     }
02684 
02685     byte[] getListOfICAttrId() throws IOException {
02686        ProtocolData d = new ProtocolData();
02687 
02688        // byte length of attr id
02689        int len = 1 * 2;
02690        d.write2(len);
02691 
02692        // IC_INPUT_LANGUAGE
02693        d.write2(IC_INPUT_LANGUAGE);
02694 
02695        // pad it
02696        d.pad();
02697 
02698        byte[] ret = new byte[d.count];
02699        System.arraycopy(d.buf, 0, ret, 0, d.count);
02700 
02701        return ret;
02702     }
02703 
02704     byte[] getListOfICAttr() throws IOException {
02705        byte[] ret = getInputLanguage();
02706        return ret;
02707     }
02708 
02709     void setInputLanguage(byte[] buf) throws IOException {
02710        ProtocolData d = new ProtocolData(buf, buf.length);
02711 
02712        // The locale names are defined in the IIIMP spec.
02713        String str = d.readString();
02714        locale = ProtocolDriver.toLocale(str);
02715     }
02716 
02717     byte[] getInputLanguage() throws IOException {
02718        ProtocolData d = new ProtocolData();
02719 
02720        // attribute id
02721        d.write2(IC_INPUT_LANGUAGE);
02722 
02723        // input langauge value.
02724        ProtocolData val = new ProtocolData();
02725        String lang = ProtocolDriver.toLocaleString(locale);
02726        val.writeString(lang);
02727        
02728        // value length
02729        d.write2(val.count);
02730        // value
02731        d.writeBytes(val.buf, val.count);
02732        // pad it
02733        d.pad();
02734 
02735        byte[] ret = new byte[d.count];
02736        System.arraycopy(d.buf, 0, ret, 0, d.count);
02737        return ret;
02738     }
02739 }
02740 
02741 class StringData extends ProtocolData {
02742 
02743     StringData(byte b[], int len) {
02744        super(b, len);
02745     }
02746 
02747     StringData(String str) throws IOException {
02748        super();
02749        writeString(str);
02750     }
02751 
02752     StringData(ProtocolData d) {
02753        super(d);
02754     }
02755 
02756     String[] toStringArray() throws IOException {
02757        final int MAX = 8;
02758 
02759        // reads the length of string to follow
02760        int len = read2();
02761        if (len == 0) {
02762            return (String[]) null;
02763        }
02764 
02765        int upto = pos + len;
02766 
02767        int num = 0;
02768        int num_array = MAX;
02769        String[] array = new String[num_array];
02770 
02771        for (; pos < upto; num++) {
02772            if (num == num_array) {
02773               num_array += MAX;
02774               String[] tmp = new String[num_array];
02775               System.arraycopy(array, 0, tmp, 0, num);
02776               array = tmp;
02777            }
02778            array[num] = readString();
02779        }
02780 
02781        // Shrink array to make the right size
02782        if (array.length != num) {
02783            String tmp[] = new String[num];
02784            System.arraycopy(array, 0, tmp, 0, num);
02785            array = tmp;
02786        }
02787 
02788        return array;
02789     }
02790 
02791     String[] toStringArray2() throws IOException {
02792        final int MAX = 8;
02793 
02794        // reads the length of string to follow
02795        int len = read4();
02796        if (len == 0) {
02797            return (String[]) null;
02798        }
02799 
02800        int upto = pos + len;
02801 
02802        int num = 0;
02803        int num_array = MAX;
02804        String[] array = new String[num_array];
02805 
02806        for (; pos < upto; num++) {
02807            if (num == num_array) {
02808               num_array += MAX;
02809               String[] tmp = new String[num_array];
02810               System.arraycopy(array, 0, tmp, 0, num);
02811               array = tmp;
02812            }
02813            array[num] = readString();
02814        }
02815 
02816        // Shrink array to make the right size
02817        if (array.length != num) {
02818            String tmp[] = new String[num];
02819            System.arraycopy(array, 0, tmp, 0, num);
02820            array = tmp;
02821        }
02822 
02823        return array;
02824     }
02825 }
02826 
02827 class KeyData extends ProtocolData {
02828 
02829     KeyData(KeyEvent kev) throws IOException {
02830        super();
02831        int code = kev.getKeyCode();
02832        char c = kev.getKeyChar();
02833        int mod = kev.getModifiers();
02834        long when = kev.getWhen();
02835 
02836        write4(code);
02837        write4((int) c);
02838        write4(mod);
02839        write4((int) when);
02840     }
02841 
02842     KeyData(byte b[], int len) {
02843        super(b, len);
02844     }
02845 
02846     KeyData(ProtocolData d) {
02847        super(d);
02848     }
02849 
02850     IIIMPKey[] toKey() throws IOException {
02851        IIIMPKey[] kev = null;
02852 
02853        int num_kev = (count / 16);
02854        if (num_kev > 0) {
02855            kev = new IIIMPKey[num_kev];
02856            for (int i = 0; i < num_kev; i++) {
02857               int keycode = read4();
02858               char keychar = (char) read4();
02859               int modifier = read4();
02860               int timestamp = read4();
02861               kev[i] = new IIIMPKey(keycode, keychar, modifier);
02862            }
02863        }
02864 
02865        return kev;
02866     }
02867 
02871     byte[] toByteStream() throws IOException {
02872        // reserved 2 bytes space at the head of the stream.
02873        final int RESERVED = 4;
02874 
02875        if (count == 0) {
02876            return null;
02877        }
02878 
02879        int pad = paddings(count);
02880        int total = count + pad;
02881        int real_total = RESERVED + count + pad;
02882 
02883        byte newBuf[] = new byte[real_total];
02884        System.arraycopy(buf, 0, newBuf, RESERVED, count);
02885 
02886        newBuf[0] = (byte) ((count >>> 24) & 0xFF);
02887        newBuf[1] = (byte) ((count >>> 16) & 0xFF);
02888        newBuf[2] = (byte) ((count >>> 8) & 0xFF);
02889        newBuf[3] = (byte) ((count >>> 0) & 0xFF);
02890 
02891        // padd to 0 just in case
02892        for (int i = (RESERVED + count); i < real_total; i++) {
02893            newBuf[i] = 0;
02894        }
02895 
02896        // proceed the position to the end
02897        pos = count;
02898 
02899        return newBuf;
02900     }
02901 }
02902 
02903 class IIIMPKey {
02904     int keycode;
02905     char keychar;
02906     int modifier;
02907 
02908     IIIMPKey(int keycode, char keychar, int modifier) {
02909        this.keycode = keycode;
02910        this.keychar = keychar;
02911        this.modifier = modifier;
02912     }
02913 
02914     public String toString() {
02915        return "code = " + keycode + ", char = " + keychar + 
02916            ", modifier = " + modifier;
02917     }
02918 }
02919