コード例 #1
0
  public AuthenticatorWindow() {
    SESecurityManager.addPasswordListener(this);

    // System.out.println( "AuthenticatorWindow");

    Map cache = COConfigurationManager.getMapParameter(CONFIG_PARAM, new HashMap());

    try {
      Iterator it = cache.entrySet().iterator();

      while (it.hasNext()) {

        Map.Entry entry = (Map.Entry) it.next();

        String key = (String) entry.getKey();
        Map value = (Map) entry.getValue();

        String user = new String((byte[]) value.get("user"), "UTF-8");
        char[] pw = new String((byte[]) value.get("pw"), "UTF-8").toCharArray();

        auth_cache.put(key, new authCache(key, new PasswordAuthentication(user, pw), true));
      }

    } catch (Throwable e) {

      COConfigurationManager.setParameter(CONFIG_PARAM, new HashMap());

      Debug.printStackTrace(e);
    }
  }
コード例 #2
0
  protected String[] getAuthenticationDialog(final String realm, final String tracker) {
    final Display display = SWTThread.getInstance().getDisplay();

    if (display.isDisposed()) {

      return (null);
    }

    final AESemaphore sem = new AESemaphore("SWTAuth");

    final authDialog[] dialog = new authDialog[1];

    TOTorrent torrent = TorrentUtils.getTLSTorrent();

    final String torrent_name;

    if (torrent == null) {

      torrent_name = null;

    } else {

      torrent_name = TorrentUtils.getLocalisedName(torrent);
    }

    try {
      display.asyncExec(
          new AERunnable() {
            public void runSupport() {
              dialog[0] = new authDialog(sem, display, realm, tracker, torrent_name);
            }
          });
    } catch (Throwable e) {

      Debug.printStackTrace(e);

      return (null);
    }
    sem.reserve();

    String user = dialog[0].getUsername();
    String pw = dialog[0].getPassword();
    String persist = dialog[0].savePassword() ? "true" : "false";

    if (user == null) {

      return (null);
    }

    return (new String[] {user, pw == null ? "" : pw, persist});
  }
コード例 #3
0
  protected void saveAuthCache() {
    try {
      this_mon.enter();

      HashMap map = new HashMap();

      Iterator it = auth_cache.values().iterator();

      while (it.hasNext()) {

        authCache value = (authCache) it.next();

        if (value.isPersistent()) {

          try {
            HashMap entry_map = new HashMap();

            entry_map.put("user", value.getAuth().getUserName().getBytes("UTF-8"));
            entry_map.put("pw", new String(value.getAuth().getPassword()).getBytes("UTF-8"));

            map.put(value.getKey(), entry_map);

          } catch (Throwable e) {

            Debug.printStackTrace(e);
          }
        }
      }

      COConfigurationManager.setParameter(CONFIG_PARAM, map);

    } finally {

      this_mon.exit();
    }
  }
コード例 #4
0
  public void runSupport() {

    try {
      new URL(url_str); // determine if this is already a proper URL
    } catch (Throwable t) { // it's not

      //  			//check if the string is just a base32/hex-encoded torrent infohash
      //
      //  		String magnet_uri = UrlUtils.normaliseMagnetURI( url_str );
      //
      //  		if ( magnet_uri != null ){
      //
      //  			url_str = magnet_uri;
      //  		}
    }

    try {
      url = AddressUtils.adjustURL(new URL(url_str));

      String protocol = url.getProtocol().toLowerCase();

      // hack here - the magnet download process requires an additional paramter to cause it to
      // stall on error so the error can be reported

      //    	if ( protocol.equals( "magnet" ) || protocol.equals( "dht" )){
      //
      //    		url = AddressUtils.adjustURL( new URL(url_str+"&pause_on_error=true"));
      //    	}

      for (int i = 0; i < 2; i++) {
        try {

          //	      if ( protocol.equals("https")){
          //
          //	      	// see ConfigurationChecker for SSL client defaults
          //
          //	      	HttpsURLConnection ssl_con = (HttpsURLConnection)url.openConnection();
          //
          //	      	// allow for certs that contain IP addresses rather than dns names
          //
          //	      	ssl_con.setHostnameVerifier(
          //	      			new HostnameVerifier()
          //	      			{
          //	      				public boolean
          //	      				verify(
          //	      					String		host,
          //							SSLSession	session )
          //	      				{
          //	      					return( true );
          //	      				}
          //	      			});
          //
          //	      	con = ssl_con;
          //
          //	      }else{
          //
          con = (HttpURLConnection) url.openConnection();

          //	      }

          con.setRequestProperty(
              "User-Agent", Constants.AZUREUS_NAME + " " + Constants.AZUREUS_VERSION);

          if (referrer != null && referrer.length() > 0) {

            con.setRequestProperty("Referer", referrer);
          }

          if (request_properties != null) {

            Iterator it = request_properties.entrySet().iterator();

            while (it.hasNext()) {

              Map.Entry entry = (Map.Entry) it.next();

              String key = (String) entry.getKey();
              String value = (String) entry.getValue();

              // currently this code doesn't support gzip/deflate...

              if (!key.equalsIgnoreCase("Accept-Encoding")) {

                con.setRequestProperty(key, value);
              }
            }
          }

          this.con.connect();

          break;

          //      	}catch( SSLException e ){
          //
          //      		if ( i == 0 ){
          //
          //      			if ( SESecurityManager.installServerCertificates( url ) != null ){
          //
          //      				// certificate has been installed
          //
          //      				continue;	// retry with new certificate
          //      			}
          //      		}
          //
          //      		throw( e );
          //
        } catch (IOException e) {

          if (i == 0) {

            URL retry_url = UrlUtils.getIPV4Fallback(url);

            if (retry_url != null) {

              url = retry_url;

            } else {

              throw (e);
            }
          }
        }
      }

      int response = this.con.getResponseCode();
      if (!ignoreReponseCode) {
        if ((response != HttpURLConnection.HTTP_ACCEPTED)
            && (response != HttpURLConnection.HTTP_OK)) {
          this.error(response, Integer.toString(response) + ": " + this.con.getResponseMessage());
          return;
        }
      }

      /*
           Map headerFields = this.con.getHeaderFields();

           System.out.println("Header of download of " + url_str);
           for (Iterator iter = headerFields.keySet().iterator(); iter.hasNext();) {
      			String s = (String) iter.next();
      			System.out.println(s + ":" + headerFields.get(s));

      		}
      */
      filename = this.con.getHeaderField("Content-Disposition");
      if ((filename != null)
          && filename
              .toLowerCase()
              .matches(".*attachment.*")) // Some code to handle b0rked servers.
      while (filename.toLowerCase().charAt(0) != 'a') filename = filename.substring(1);
      if ((filename == null)
          || !filename.toLowerCase().startsWith("attachment")
          || (filename.indexOf('=') == -1)) {
        String tmp = this.url.getFile();
        if (tmp.length() == 0 || tmp.equals("/")) {
          filename = url.getHost();
        } else if (tmp.startsWith("?")) {

          // probably a magnet URI - use the hash
          // magnet:?xt=urn:sha1:VGC53ZWCUXUWVGX7LQPVZIYF4L6RXSU6

          String query = tmp.toUpperCase();

          int pos = query.indexOf("XT=URN:SHA1:");

          if (pos == -1) {

            pos = query.indexOf("XT=URN:BTIH:");
          }

          if (pos != -1) {

            pos += 12;

            int p2 = query.indexOf("&", pos);

            if (p2 == -1) {

              filename = query.substring(pos);

            } else {

              filename = query.substring(pos, p2);
            }
          } else {

            filename = "Torrent" + (long) (Math.random() * Long.MAX_VALUE);
          }

          filename += ".tmp";

        } else {
          if (tmp.lastIndexOf('/') != -1) tmp = tmp.substring(tmp.lastIndexOf('/') + 1);

          // remove any params in the url

          int param_pos = tmp.indexOf('?');

          if (param_pos != -1) {
            tmp = tmp.substring(0, param_pos);
          }

          filename = URLDecoder.decode(tmp, Constants.DEFAULT_ENCODING);
        }
      } else {
        filename = filename.substring(filename.indexOf('=') + 1);
        if (filename.startsWith("\"") && filename.endsWith("\""))
          filename = filename.substring(1, filename.lastIndexOf('\"'));

        filename = URLDecoder.decode(filename, Constants.DEFAULT_ENCODING);

        // not sure of this piece of logic here but I'm not changing it at the moment

        File temp = new File(filename);
        filename = temp.getName();
      }

      filename = FileUtil.convertOSSpecificChars(filename, false);

      //      directoryname =
      // COConfigurationManager.getDirectoryParameter("General_sDefaultTorrent_Directory");
      //      boolean useTorrentSave = COConfigurationManager.getBooleanParameter("Save Torrent
      // Files");
      directoryname = "D:\\Development\\testDownloads\\";
      boolean useTorrentSave = true;
      if (file_str != null) {
        // not completely sure about the whole logic in this block
        File temp = new File(file_str);

        // if we're not using a default torrent save dir
        if (!useTorrentSave || directoryname.length() == 0) {
          // if it's already a dir
          if (temp.isDirectory()) {
            // use it
            directoryname = temp.getCanonicalPath();
          }
          // it's a file
          else {
            // so use its parent dir
            directoryname = temp.getCanonicalFile().getParent();
          }
        }

        // if it's a file
        if (!temp.isDirectory()) {
          // set the file name
          filename = temp.getName();
        }
      }
      // what would happen here if directoryname == null and file_str == null??

      this.state = STATE_INIT;
      this.notifyListener();
    } catch (java.net.MalformedURLException e) {
      this.error(0, "Exception while parsing URL '" + url + "':" + e.getMessage());
    } catch (java.net.UnknownHostException e) {
      this.error(
          0,
          "Exception while initializing download of '"
              + url
              + "': Unknown Host '"
              + e.getMessage()
              + "'");
    } catch (java.io.IOException ioe) {
      this.error(0, "I/O Exception while initializing download of '" + url + "':" + ioe.toString());
    } catch (Throwable e) {
      this.error(0, "Exception while initializing download of '" + url + "':" + e.toString());
    }

    if (this.state == STATE_ERROR) {

      return;
    }

    try {
      final boolean status_reader_run[] = {true};

      this.state = STATE_START;

      notifyListener();

      this.state = STATE_DOWNLOADING;

      notifyListener();

      Thread status_reader =
          new AEThread("TorrentDownloader:statusreader") {
            public void runSupport() {
              boolean changed_status = false;

              while (true) {

                try {
                  Thread.sleep(100);

                  try {
                    this_mon.enter();

                    if (!status_reader_run[0]) {

                      break;
                    }
                  } finally {

                    this_mon.exit();
                  }

                  String s = con.getResponseMessage();

                  if (!s.equals(getStatus())) {

                    if (!s.toLowerCase().startsWith("error:")) {

                      if (s.toLowerCase().indexOf("alive") != -1) {

                        if (percentDone < 10) {

                          percentDone++;
                        }
                      }

                      int pos = s.indexOf('%');

                      if (pos != -1) {

                        int i;

                        for (i = pos - 1; i >= 0; i--) {

                          char c = s.charAt(i);

                          if (!Character.isDigit(c) && c != ' ') {

                            i++;

                            break;
                          }
                        }

                        try {
                          percentDone = Integer.parseInt(s.substring(i, pos).trim());

                        } catch (Throwable e) {

                        }
                      }

                      setStatus(s);

                    } else {

                      error(con.getResponseCode(), s.substring(6));
                    }

                    changed_status = true;
                  }

                } catch (Throwable e) {

                  break;
                }
              }

              if (changed_status) {

                setStatus("");
              }
            }
          };

      status_reader.setDaemon(true);

      status_reader.start();

      InputStream in;

      try {
        in = this.con.getInputStream();

      } catch (FileNotFoundException e) {
        if (ignoreReponseCode) {

          in = this.con.getErrorStream();
        } else {

          throw e;
        }

      } finally {

        try {
          this_mon.enter();

          status_reader_run[0] = false;

        } finally {

          this_mon.exit();
        }
      }

      // handle some servers that return gzip'd torrents even though we don't request it!

      String encoding = con.getHeaderField("content-encoding");

      if (encoding != null) {

        if (encoding.equalsIgnoreCase("gzip")) {

          in = new GZIPInputStream(in);

        } else if (encoding.equalsIgnoreCase("deflate")) {

          in = new InflaterInputStream(in);
        }
      }

      if (this.state != STATE_ERROR) {

        this.file = new File(this.directoryname, filename);

        boolean useTempFile = false;
        try {
          this.file.createNewFile();
          useTempFile = !this.file.exists();
        } catch (Throwable t) {
          useTempFile = true;
        }

        if (useTempFile) {
          this.file = File.createTempFile("AZU", ".torrent", new File(this.directoryname));
          this.file.createNewFile();
        }

        FileOutputStream fileout = new FileOutputStream(this.file, false);

        bufBytes = 0;

        int size = (int) UrlUtils.getContentLength(con);

        this.percentDone = -1;

        do {
          if (this.cancel) {
            break;
          }

          try {
            bufBytes = in.read(buf);

            this.readTotal += bufBytes;

            if (size != 0) {
              this.percentDone = (100 * this.readTotal) / size;
            }

            notifyListener();

          } catch (IOException e) {
          }

          if (bufBytes > 0) {
            fileout.write(buf, 0, bufBytes);
          }
        } while (bufBytes > 0);

        in.close();

        fileout.flush();

        fileout.close();

        if (this.cancel) {
          this.state = STATE_CANCELLED;
          if (deleteFileOnCancel) {
            this.cleanUpFile();
          }
        } else {
          if (this.readTotal <= 0) {
            this.error(0, "No data contained in '" + this.url.toString() + "'");
            return;
          }

          // if the file has come down with a not-so-useful name then we try to rename
          // it to something more useful

          try {
            if (!filename.toLowerCase().endsWith(".torrent")) {

              TOTorrent torrent = TorrentUtils.readFromFile(file, false);

              String name = TorrentUtils.getLocalisedName(torrent) + ".torrent";

              File new_file = new File(directoryname, name);

              if (file.renameTo(new_file)) {

                filename = name;

                file = new_file;
              }
            }
          } catch (Throwable e) {

            Debug.printStackTrace(e);
          }

          //	          TorrentUtils.setObtainedFrom( file, original_url );

          this.state = STATE_FINISHED;
        }
        this.notifyListener();
      }
    } catch (Exception e) {

      if (!cancel) {

        Debug.out("'" + this.directoryname + "' '" + filename + "'", e);
      }

      this.error(0, "Exception while downloading '" + this.url.toString() + "':" + e.getMessage());
    }
  }
コード例 #5
0
    protected authDialog(
        AESemaphore _sem,
        Display display,
        String realm,
        boolean is_tracker,
        String target,
        String details) {
      sem = _sem;

      if (display.isDisposed()) {

        sem.releaseForever();

        return;
      }

      final String ignore_key = "IgnoreAuth:" + realm + ":" + target + ":" + details;

      if (RememberedDecisionsManager.getRememberedDecision(ignore_key) == 1) {

        Debug.out(
            "Authentication for "
                + realm
                + "/"
                + target
                + "/"
                + details
                + " ignored as told not to ask again");

        sem.releaseForever();

        return;
      }

      shell = ShellFactory.createMainShell(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);

      Utils.setShellIcon(shell);
      Messages.setLanguageText(shell, "authenticator.title");

      GridLayout layout = new GridLayout();
      layout.numColumns = 3;

      shell.setLayout(layout);

      GridData gridData;

      // realm

      Label realm_label = new Label(shell, SWT.NULL);
      Messages.setLanguageText(realm_label, "authenticator.realm");
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 1;
      realm_label.setLayoutData(gridData);

      Label realm_value = new Label(shell, SWT.NULL);
      realm_value.setText(realm.replaceAll("&", "&&"));
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 2;
      realm_value.setLayoutData(gridData);

      // target

      Label target_label = new Label(shell, SWT.NULL);
      Messages.setLanguageText(
          target_label, is_tracker ? "authenticator.tracker" : "authenticator.location");
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 1;
      target_label.setLayoutData(gridData);

      Label target_value = new Label(shell, SWT.NULL);
      target_value.setText(target.replaceAll("&", "&&"));
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 2;
      target_value.setLayoutData(gridData);

      if (details != null) {

        Label details_label = new Label(shell, SWT.NULL);
        Messages.setLanguageText(
            details_label, is_tracker ? "authenticator.torrent" : "authenticator.details");
        gridData = new GridData(GridData.FILL_BOTH);
        gridData.horizontalSpan = 1;
        details_label.setLayoutData(gridData);

        Label details_value = new Label(shell, SWT.NULL);
        details_value.setText(details.replaceAll("&", "&&"));
        gridData = new GridData(GridData.FILL_BOTH);
        gridData.horizontalSpan = 2;
        details_value.setLayoutData(gridData);
      }
      // user

      Label user_label = new Label(shell, SWT.NULL);
      Messages.setLanguageText(user_label, "authenticator.user");
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 1;
      user_label.setLayoutData(gridData);

      final Text user_value = new Text(shell, SWT.BORDER);
      user_value.setText("");
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 2;
      user_value.setLayoutData(gridData);

      user_value.addListener(
          SWT.Modify,
          new Listener() {
            public void handleEvent(Event event) {
              username = user_value.getText();
            }
          });

      // password

      Label password_label = new Label(shell, SWT.NULL);
      Messages.setLanguageText(password_label, "authenticator.password");
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 1;
      password_label.setLayoutData(gridData);

      final Text password_value = new Text(shell, SWT.BORDER);
      password_value.setEchoChar('*');
      password_value.setText("");
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 2;
      password_value.setLayoutData(gridData);

      password_value.addListener(
          SWT.Modify,
          new Listener() {
            public void handleEvent(Event event) {
              password = password_value.getText();
            }
          });

      // persist

      Label blank_label = new Label(shell, SWT.NULL);
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 1;
      blank_label.setLayoutData(gridData);

      final Button checkBox = new Button(shell, SWT.CHECK);
      checkBox.setText(MessageText.getString("authenticator.savepassword"));
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 1;
      checkBox.setLayoutData(gridData);
      checkBox.addListener(
          SWT.Selection,
          new Listener() {
            public void handleEvent(Event e) {
              persist = checkBox.getSelection();
            }
          });

      final Button dontAsk = new Button(shell, SWT.CHECK);
      dontAsk.setText(MessageText.getString("general.dont.ask.again"));
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.horizontalSpan = 1;
      dontAsk.setLayoutData(gridData);
      dontAsk.addListener(
          SWT.Selection,
          new Listener() {
            public void handleEvent(Event e) {
              RememberedDecisionsManager.setRemembered(ignore_key, dontAsk.getSelection() ? 1 : 0);
            }
          });

      // line

      Label labelSeparator = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
      gridData = new GridData(GridData.FILL_HORIZONTAL);
      gridData.horizontalSpan = 3;
      labelSeparator.setLayoutData(gridData);

      // buttons

      new Label(shell, SWT.NULL);

      Button bOk = new Button(shell, SWT.PUSH);
      Messages.setLanguageText(bOk, "Button.ok");
      gridData =
          new GridData(
              GridData.FILL_HORIZONTAL
                  | GridData.HORIZONTAL_ALIGN_END
                  | GridData.HORIZONTAL_ALIGN_FILL);
      gridData.grabExcessHorizontalSpace = true;
      gridData.widthHint = 70;
      bOk.setLayoutData(gridData);
      bOk.addListener(
          SWT.Selection,
          new Listener() {
            public void handleEvent(Event e) {
              close(true);
            }
          });

      Button bCancel = new Button(shell, SWT.PUSH);
      Messages.setLanguageText(bCancel, "Button.cancel");
      gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
      gridData.grabExcessHorizontalSpace = false;
      gridData.widthHint = 70;
      bCancel.setLayoutData(gridData);
      bCancel.addListener(
          SWT.Selection,
          new Listener() {
            public void handleEvent(Event e) {
              close(false);
            }
          });

      shell.setDefaultButton(bOk);

      shell.addListener(
          SWT.Traverse,
          new Listener() {
            public void handleEvent(Event e) {
              if (e.character == SWT.ESC) {
                close(false);
              }
            }
          });

      shell.pack();

      Utils.centreWindow(shell);

      shell.open();
    }
コード例 #6
0
  protected String[] getAuthenticationDialog(final String realm, final String location) {
    final Display display = SWTThread.getInstance().getDisplay();

    if (display.isDisposed()) {

      return (null);
    }

    final AESemaphore sem = new AESemaphore("SWTAuth");

    final authDialog[] dialog = new authDialog[1];

    TOTorrent torrent = TorrentUtils.getTLSTorrent();

    final boolean is_tracker;
    final String details;

    if (torrent == null) {

      is_tracker = false;

      details = TorrentUtils.getTLSDescription();

    } else {

      details = TorrentUtils.getLocalisedName(torrent);
      is_tracker = true;
    }

    try {
      if (display.getThread() == Thread.currentThread()) {

        dialog[0] = new authDialog(sem, display, realm, is_tracker, location, details);

        while (!(display.isDisposed() || sem.isReleasedForever())) {

          if (!display.readAndDispatch()) {

            display.sleep();
          }
        }

        if (display.isDisposed()) {

          return (null);
        }
      } else {

        display.asyncExec(
            new AERunnable() {
              public void runSupport() {
                dialog[0] = new authDialog(sem, display, realm, is_tracker, location, details);
              }
            });
      }
    } catch (Throwable e) {

      Debug.printStackTrace(e);

      return (null);
    }

    sem.reserve();

    String user = dialog[0].getUsername();
    String pw = dialog[0].getPassword();
    String persist = dialog[0].savePassword() ? "true" : "false";

    if (user == null) {

      return (null);
    }

    return (new String[] {user, pw == null ? "" : pw, persist});
  }
コード例 #7
0
  public PasswordAuthentication getAuthentication(
      String realm, String protocol, String host, int port) {
    try {
      this_mon.enter();

      String tracker = protocol + "://" + host + ":" + port + "/";

      InetAddress bind_ip = NetworkAdmin.getSingleton().getSingleHomedServiceBindAddress();

      String self_addr;

      // System.out.println( "auth req for " + realm + " - " + tracker );

      if (bind_ip == null || bind_ip.isAnyLocalAddress()) {

        self_addr = "127.0.0.1";

      } else {

        self_addr = bind_ip.getHostAddress();
      }

      // when the tracker is connected to internally we don't want to prompt
      // for the password. Here we return a special user and the password hash
      // which is picked up in the tracker auth code - search for "<internal>"!

      // also include the tracker IP as well as for scrapes these can occur on
      // a raw torrent which hasn't been modified to point to localhost

      if (host.equals(self_addr)
          || host.equals(COConfigurationManager.getStringParameter("Tracker IP", ""))) {

        try {
          byte[] pw = COConfigurationManager.getByteParameter("Tracker Password", new byte[0]);

          String str_pw = new String(Base64.encode(pw));

          return (new PasswordAuthentication("<internal>", str_pw.toCharArray()));

        } catch (Throwable e) {

          Debug.printStackTrace(e);
        }
      }

      String auth_key = realm + ":" + tracker;

      authCache cache = (authCache) auth_cache.get(auth_key);

      if (cache != null) {

        PasswordAuthentication auth = cache.getAuth();

        if (auth != null) {

          return (auth);
        }
      }

      String[] res = getAuthenticationDialog(realm, tracker);

      if (res == null) {

        return (null);

      } else {

        PasswordAuthentication auth = new PasswordAuthentication(res[0], res[1].toCharArray());

        boolean save_pw = res[2].equals("true");

        boolean old_entry_existed =
            auth_cache.put(auth_key, new authCache(auth_key, auth, save_pw)) != null;

        if (save_pw || old_entry_existed) {

          saveAuthCache();
        }

        return (auth);
      }
    } finally {

      this_mon.exit();
    }
  }