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