text:
package org.apache.james.transport.mailets;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;
import javax.mail.internet.ParseException;

import org.apache.geronimo.javamail.transport.smtp.SMTPTransport;
import org.apache.james.dnsservice.api.DNSService;
import org.apache.james.dnsservice.api.TemporaryResolutionException;
import org.apache.james.dnsservice.library.MXHostAddressIterator;
import org.apache.james.domainlist.api.DomainList;
import org.apache.james.domainlist.api.DomainListException;
import org.apache.james.lifecycle.api.LifecycleUtil;
import org.apache.james.queue.api.MailPrioritySupport;
import org.apache.james.queue.api.MailQueue;
import org.apache.james.queue.api.MailQueue.MailQueueException;
import org.apache.james.queue.api.MailQueue.MailQueueItem;
import org.apache.james.queue.api.MailQueueFactory;
import org.apache.james.transport.util.MailetContextLog;
import org.apache.james.transport.util.Patterns;
import org.apache.james.util.TimeConverter;
import org.apache.mailet.HostAddress;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;
import org.apache.mailet.base.GenericMailet;

/**
 *
The RemoteDelivery mailet delivers messages to a remote SMTP server able to deliver or forward messages to their final
 * destination.
 *

 *
The remote SMTP server through which each mail is delivered is resolved using MX lookup for each message destination
 * unless the <gateway/&gt parameter is set. The <gateway/&gt parameter enables the
 * definition of one or more gateway servers through which all messages are sent.
 *

 *
If an attempt to deliver a message fails, a redelivery attempt is scheduled according to the scheme defined
 * by the <delayTime/&gt parameter, retrying up to the limit defined
 * by the <maxRetries/&gt parameter. When the retry limit is exceeded, delivery failure is processed
 * according to the setting of the <bounceProcessor/&gt parameter.
 *

 *
These are the parameters that control the operation of the RemoteDelivery mailet:
 *

 *

 *
deliveryThreads (required) - an Integer for the number of threads this mailet will use to deliver mail.

 *
outgoing (required) - a String containing the name of the queue that will hold messages being processed by this mailet.

 *
bind (optional) - a String describing the local IP address to which the mailet should be bound while delivering
 * emails. This tag is useful for multihomed machines. Default is to bind to the default local address of the machine.

 * Note: The same IP address must be used for all of those RemoteDelivery instances where you explicitly supply a bind address.
 *
delayTime (optional> a String containing a comma separated list of patterns defining the number of and delays between delivery
 * attempts. The pattern is [attempts\*]delay [unit] where:
 *

 *
attempts (optional) - an Integer for the number of delivery attempts. Default is 1.

 *
delay (required) - a Long for the delay between attempts.

 *
unit (optional) - a String with the value of one of 'msec', 'sec', 'minute', 'hour', or 'day'. Default is msec.

 *

 * Default is one attempt after 6 hours, which if explicitly declared would be written as <delayTime>1 * 6 hour</delayTime>

 *
maxRetries (optional) an Integer for the number of times an attempt is made to deliver a particular mail.
 * Default is the greater of five and the sum of the attempts for each <delayTime/> specified.
 *
maxDnsProblemRetries (optional) - an Integer for the number of times to retry if DNS problems for a domain occur.
 * Default is 0.
 *
timeout (optional) - an Integer for the Socket I/O timeout in milliseconds. Default is 180000

 *
connectionTimeout (optional) - an Integer for the Socket connection timeout in milliseconds. Default is 60000

 *
bounceProcessor (optional) - a String containing the name of the mailet processor to pass messages that cannot
 * be delivered to for DSN bounce processing. Default is to send a traditional message containing the bounce details.

 *
startTLS (optional) - a Boolean (true/false) indicating whether the STARTTLS command (if supported by the server)
 * to switch the connection to a TLS-protected connection before issuing any login commands. Default is false.

 *
sslEnable (optional) - a Boolean (true/false) indicating whether to use SSL to connect and use the SSL port unless
 * explicitly overridden. Default is false.

 *
gateway (optional) - a String containing a comma separated list of patterns defining the gateway servers to be used to
 * deliver mail regardless of the recipient address. If multiple gateway servers are defined, each will be tried in definition order
 * until delivery is successful. If none are successful, the mail is bounced. The pattern is host[:port] where:
 *

 *
host (required) - the FQN of the gateway server.

 *
port (optional) - the port of the gateway server. Default is the value defined in the <gatewayPort/>
 * parameter if set, else the default port for the specified connection type.

 *

 * Default is to resolve the destination SMTP server for each mail using MX lookup.
 *

 *
gatewayPort (optional) - an Integer for the gateway port to be used for each defined gateway server for which a
 * port is not explicitly defined in the <gateway/> parameter. Default is the default port for the specified connection type.

 *
gatewayUsername (optional) - a String containing the user name to be used to authenticate the user using the
 * AUTH command. Default is not to issue the AUTH command.
 *
gatewayPassword (required if gatewayUsername) is set - a String representing the password to be used
 * to authenticate the user using the AUTH command.
 *
heloName (optional) - a String containing the name used in the SMTP HELO and EHLO commands. Default is the default domain,
 * which is typically localhost.

 *
mail.* (optional) - Any property beginning with mail. described in the Javadoc for package
 * com.sun.mail.smtp
 * can be set with a parameter of the corresponding name. For example the parameter
 * <mail.smtp.ssl.enable>true</mail.smtp.ssl.enable> is equivalent to the Java code
 * props.put("mail.smtp.ssl.enable", "true");. Properties set by this facility override settings made
 * within the mailet code.

 * Note: This facility should be used with extreme care by expert users with a thorough knowledge of the relevant RFCs and
 * the ability to perform their own problem resolutions.

 *
debug (optional) - a Boolean (true/false) indicating whether debugging is on. Default is false.

 *

 */
public class RemoteDelivery extends GenericMailet implements Runnable {

    /**
     * Default Delay Time (Default is 6*60*60*1000 Milliseconds (6 hours)).
     */
    private static final long DEFAULT_DELAY_TIME = 21600000;

    /**
     * Pattern to match [attempts*]delay[units].
     */
    private static final String PATTERN_STRING = "\\s*([0-9]*\\s*[\\*])?\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*";

    private static final Pattern PATTERN = Patterns.compilePatternUncheckedException(PATTERN_STRING);

    @Inject
    @Named("dnsservice")
    @Resource
    private DNSService dnsServer;

    /**
     * Flag to define verbose logging messages.
     */
    private boolean isDebug = false;

    /**
     * List of Delay Times. Controls frequency of retry attempts.
     */
    private long[] delayTimes;

    /**
     * Maximum no. of retries (Defaults to 5).
     */
    private int maxRetries = 5;

    /**
     * Default number of ms to timeout on smtp delivery
     */
    private long smtpTimeout = 180000;

    /**
     * If false then ANY address errors will cause the transmission to fail
     */
    private boolean sendPartial = false;

    /**
     * The amount of time JavaMail will wait before giving up on a socket
     * connect()
     */
    private int connectionTimeout = 60000;

    /**
     * No. of threads used to process messages that should be retried.
     */
    private int workersThreadCount = 1;

    /**
     * The server(s) to send all email to
     */
    private Collection<String> gatewayServer = null;

    /**
     * Auth for gateway server
     */
    private String authUser = null;

    /**
     * Password for gateway server
     */
    private String authPass = null;

    /**
     * True, if the bind configuration parameter is supplied,
     * RemoteDeliverySocketFactory will be used in this case.
     */
    private boolean isBindUsed = false;

    /**
     * Collection that stores all worker threads.
     */
    private final Collection<Thread> workersThreads = new Vector<Thread>();

    /**
     * Flag used by 'run' method to end itself.
     */
    private volatile boolean destroyed = false;

    /**
     * the processor for creating Bounces
     */
    private String bounceProcessor = null;

    /**
     * Default properties for the JavaMail Session
     */
    private final Properties defprops = new Properties();

    /**
     * The retry count dnsProblemErrors
     */
    private int dnsProblemRetry = 0;

    private MailQueueFactory queueFactory;

    private MailQueue queue;

    private String heloName;

    private MailetContextLog logAdapter;

    private boolean usePriority;

    private DomainList domainList;

    private boolean startTLS = false;

    private boolean isSSLEnable = false;

    @Inject
    public void setDomainList(@Named("domainlist") DomainList domainList) {
        this.domainList = domainList;
    }

    @Inject
    public void setMailQueueFactory(@Named("mailqueuefactory") MailQueueFactory queueFactory) {
        this.queueFactory = queueFactory;
    }

    /**
     * Initializes all arguments based on configuration values specified in the
     * James configuration file.
     *
     * @throws MessagingException on failure to initialize attributes.
     */
    public void init() throws MessagingException {
        // Set isDebug flag.
        isDebug = (getInitParameter("debug") == null) ? false : Boolean.valueOf(getInitParameter("debug"));

        logAdapter = new MailetContextLog(getMailetContext(), isDebug);

        // Create list of Delay Times.
        ArrayList<Delay> delayTimesList = new ArrayList<Delay>();
        try {
            if (getInitParameter("delayTime") != null) {

                // parses delayTimes specified in config file.
                String delayTimesParm = getInitParameter("delayTime");

                // Split on commas
                StringTokenizer st = new StringTokenizer(delayTimesParm, ",");
                while (st.hasMoreTokens()) {
                    String delayTime = st.nextToken();
                    delayTimesList.add(new Delay(delayTime));
                }
            } else {
                // Use default delayTime.
                delayTimesList.add(new Delay());
            }
        } catch (Exception e) {
            log("Invalid delayTime setting: " + getInitParameter("delayTime"));
        }

        try {
            // Get No. of Max Retries.
            if (getInitParameter("maxRetries") != null) {
                maxRetries = Integer.parseInt(getInitParameter("maxRetries"));
            }

            // Check consistency of 'maxRetries' with delayTimesList attempts.
            int totalAttempts = calcTotalAttempts(delayTimesList);

            // If inconsistency found, fix it.
            if (totalAttempts > maxRetries) {
                log("Total number of delayTime attempts exceeds maxRetries specified. " + " Increasing maxRetries from " + maxRetries + " to " + totalAttempts);
                maxRetries = totalAttempts;
            } else {
                int extra = maxRetries - totalAttempts;
                if (extra != 0) {
                    log("maxRetries is larger than total number of attempts specified.  " + "Increasing last delayTime with " + extra + " attempts ");

                    // Add extra attempts to the last delayTime.
                    if (delayTimesList.size() != 0) {
                        // Get the last delayTime.
                        Delay delay = delayTimesList.get(delayTimesList.size() - 1);

                        // Increase no. of attempts.
                        delay.setAttempts(delay.getAttempts() + extra);
                        log("Delay of " + delay.getDelayTime() + " msecs is now attempted: " + delay.getAttempts() + " times");
                    } else {
                        throw new MessagingException("No delaytimes, cannot continue");
                    }
                }
            }
            delayTimes = expandDelays(delayTimesList);

        } catch (Exception e) {
            log("Invalid maxRetries setting: " + getInitParameter("maxRetries"));
        }
        // Get the path for the 'Outgoing' repository. This is the place on the
        // file system where Mail objects will be saved during the 'delivery'
        // processing. This can be changed to a repository on a database (e.g.
        // db://maildb/spool/retry).
        String outgoing = getInitParameter("outgoing");
        if (outgoing == null) {
            outgoing = "outgoing";
        }
        queue = queueFactory.getQueue(outgoing);

        try {
            if (getInitParameter("timeout") != null) {
                smtpTimeout = Integer.parseInt(getInitParameter("timeout"));
            }
        } catch (Exception e) {
            log("Invalid timeout setting: " + getInitParameter("timeout"));
        }

        try {
            if (getInitParameter("connectiontimeout") != null) {
                connectionTimeout = Integer.parseInt(getInitParameter("connectiontimeout"));
            }
        } catch (Exception e) {
            log("Invalid timeout setting: " + getInitParameter("timeout"));
        }

        sendPartial = (getInitParameter("sendpartial") == null) ? false : Boolean.valueOf(getInitParameter("sendpartial"));

        bounceProcessor = getInitParameter("bounceProcessor");

        String sTLS = getInitParameter("startTLS");
        if (sTLS != null) {
            startTLS = Boolean.valueOf(sTLS);
        }

        isSSLEnable = (getInitParameter("sslEnable") == null) ? false : Boolean.valueOf(getInitParameter("sslEnable"));

        String gateway = getInitParameter("gateway");
        String gatewayPort = getInitParameter("gatewayPort");

        if (gateway != null) {
            gatewayServer = new ArrayList<String>();
            StringTokenizer st = new StringTokenizer(gateway, ",");
            while (st.hasMoreTokens()) {
                String server = st.nextToken().trim();
                if (server.indexOf(':') < 0 && gatewayPort != null) {
                    server += ":";
                    server += gatewayPort;
                }

                if (isDebug)
                    log("Adding SMTP gateway: " + server);
                gatewayServer.add(server);
            }
            authUser = getInitParameter("gatewayUsername");
            // backward compatibility with 2.3.x
            if (authUser == null) {
                authUser = getInitParameter("gatewayusername");
            }
            authPass = getInitParameter("gatewayPassword");
        }

        /*
      JavaMail delivery socket binds to this local address. If null the
      JavaMail default will be used.
     */
        String bindAddress = getInitParameter("bind");
        isBindUsed = bindAddress != null;
        try {
            if (isBindUsed)
                RemoteDeliverySocketFactory.setBindAdress(bindAddress);
        } catch (UnknownHostException e) {
            log("Invalid bind setting (" + bindAddress + "): " + e.toString());
        }

        // deal with <mail.*> attributes, passing them to javamail
        Iterator<String> i = getInitParameterNames();
        while (i.hasNext()) {
            String name = i.next();
            if (name.startsWith("mail.")) {
                defprops.put(name, getInitParameter(name));
            }

        }

        String dnsRetry = getInitParameter("maxDnsProblemRetries");
        if (dnsRetry != null && !dnsRetry.equals("")) {
            dnsProblemRetry = Integer.parseInt(dnsRetry);
        }

        heloName = getInitParameter("heloName");

        String prio = getInitParameter("usePriority");
        if (prio != null) {
            usePriority = Boolean.valueOf(prio);
        }

        // Start Workers Threads.
        workersThreadCount = Integer.parseInt(getInitParameter("deliveryThreads"));
        initDeliveryThreads();
    }

    private void initDeliveryThreads() {
        for (int a = 0; a < workersThreadCount; a++) {
            String threadName = "Remote delivery thread (" + a + ")";
            Thread t = new Thread(this, threadName);
            t.start();
            workersThreads.add(t);
        }
    }

    /**
     * Calculates Total no. of attempts for the specified delayList.
     *
     * @param delayList list of 'Delay' objects
     * @return total no. of retry attempts
     */
    private int calcTotalAttempts(ArrayList<Delay> delayList) {
        int sum = 0;
        for (Delay delay : delayList) {
            sum += delay.getAttempts();
        }
        return sum;
    }

    /**
     *

     * This method expands an ArrayList containing Delay objects into an array
     * holding the only delaytime in the order.
     *

     *

     * So if the list has 2 Delay objects the first having attempts=2 and
     * delaytime 4000 the second having attempts=1 and delaytime=300000 will be
     * expanded into this array:
     *

     *

     * long[0] = 4000
     * long[1] = 4000
     * long[2] = 300000
     *

     *
     * @param list the list to expand
     * @return the expanded list
     */
    private long[] expandDelays(ArrayList<Delay> list) {
        long[] delays = new long[calcTotalAttempts(list)];
        Iterator<Delay> i = list.iterator();
        int idx = 0;
        while (i.hasNext()) {
            Delay delay = i.next();
            for (int j = 0; j < delay.getAttempts(); j++) {
                delays[idx++] = delay.getDelayTime();
            }
        }
        return delays;
    }

    /**
     * This method returns, given a retry-count, the next delay time to use.
     *
     * @param retry_count the current retry_count.
     * @return the next delay time to use, given the retry count
     */
    private long getNextDelay(int retry_count) {
        if (retry_count > delayTimes.length) {
            return DEFAULT_DELAY_TIME;
        }
        return delayTimes[retry_count - 1];
    }

    /**
     * This class is used to hold a delay time and its corresponding number of
     * retries.
     */
    private final static class Delay {
        private int attempts = 1;

        private long delayTime = DEFAULT_DELAY_TIME;

        /**
         *

         * This constructor expects Strings of the form
         * "[attempt\*]delaytime[unit]".
         *

         *

         * The optional attempt is the number of tries this delay should be used
         * (default = 1). The unit, if present, must be one of
         * (msec,sec,minute,hour,day). The default value of unit is 'msec'.
         *

         *

         * The constructor multiplies the delaytime by the relevant multiplier
         * for the unit, so the delayTime instance variable is always in msec.
         *

         *
         * @param initString the string to initialize this Delay object from
         */
        public Delay(String initString) throws MessagingException {
            // Default unit value to 'msec'.
            String unit = "msec";

            Matcher res = PATTERN.matcher(initString);
            if (res.matches()) {
                // The capturing groups will now hold:
                // at 1: attempts * (if present)
                // at 2: delaytime
                // at 3: unit (if present)
                if (res.group(1) != null && !res.group(1).equals("")) {
                    // We have an attempt *
                    String attemptMatch = res.group(1);

                    // Strip the * and whitespace.
                    attemptMatch = attemptMatch.substring(0, attemptMatch.length() - 1).trim();
                    attempts = Integer.parseInt(attemptMatch);
                }

                delayTime = Long.parseLong(res.group(2));

                if (!res.group(3).equals("")) {
                    // We have a value for 'unit'.
                    unit = res.group(3).toLowerCase(Locale.US);
                }
            } else {
                throw new MessagingException(initString + " does not match " + PATTERN_STRING);
            }

            // calculate delayTime.
            try {
                delayTime = TimeConverter.getMilliSeconds(delayTime, unit);
            } catch (NumberFormatException e) {
                throw new MessagingException(e.getMessage());
            }
        }

        /**
         * This constructor makes a default Delay object with attempts = 1 and
         * delayTime = DEFAULT_DELAY_TIME.
         */
        public Delay() {
        }

        /**
         * @return the delayTime for this Delay
         */
        public long getDelayTime() {
            return delayTime;
        }

        /**
         * @return the number attempts this Delay should be used.
         */
        public int getAttempts() {
            return attempts;
        }

        /**
         * Set the number attempts this Delay should be used.
         */
        public void setAttempts(int value) {
            attempts = value;
        }

        /**
         * Pretty prints this Delay
         */
        @Override
        public String toString() {
            return getAttempts() + "*" + getDelayTime() + "msecs";
        }
    }

    @Override
    public String getMailetInfo() {
        return "RemoteDelivery Mailet";
    }

    /**
     * For this message, we take the list of recipients, organize these into
     * distinct servers, and duplicate the message for each of these servers,
     * and then call the deliver (messagecontainer) method for each
     * server-specific messagecontainer ... that will handle storing it in the
     * outgoing queue if needed.
     *
     * @param mail org.apache.mailet.Mail
     */
    @Override
    public void service(Mail mail) throws MessagingException {
        // Do I want to give the internal key, or the message's Message ID
        if (isDebug) {
            log("Remotely delivering mail " + mail.getName());
        }
        Collection<MailAddress> recipients = mail.getRecipients();

        if (usePriority) {

            // Use highest prio for new emails. See JAMES-1311
            mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY);
        }
        if (gatewayServer == null) {
            // Must first organize the recipients into distinct servers (name
            // made case insensitive)
            Hashtable<String, Collection<MailAddress>> targets = new Hashtable<String, Collection<MailAddress>>();
            for (MailAddress target : recipients) {
                String targetServer = target.getDomain().toLowerCase(Locale.US);
                Collection<MailAddress> temp = targets.get(targetServer);
                if (temp == null) {
                    temp = new ArrayList<MailAddress>();
                    targets.put(targetServer, temp);
                }
                temp.add(target);
            }

            // We have the recipients organized into distinct servers... put
            // them into the
            // delivery store organized like this... this is ultra inefficient I
            // think...

            // Store the new message containers, organized by server, in the
            // outgoing mail repository
            String name = mail.getName();
            for (Map.Entry<String, Collection<MailAddress>> entry : targets.entrySet()) {
                if (isDebug) {
                    String logMessageBuffer = "Sending mail to " + entry.getValue() + " on host " + entry.getKey();
                    log(logMessageBuffer);
                }
                mail.setRecipients(entry.getValue());
                String nameBuffer = name + "-to-" + entry.getKey();
                mail.setName(nameBuffer);
                try {
                    queue.enQueue(mail);
                } catch (MailQueueException e) {
                    log("Unable to queue mail " + mail.getName() + " for recipients + " + mail.getRecipients().toString(), e);
                }
            }
        } else {
            // Store the mail unaltered for processing by the gateway server(s)
            if (isDebug) {
                String logMessageBuffer = "Sending mail to " + mail.getRecipients() + " via " + gatewayServer;
                log(logMessageBuffer);
            }

            // Set it to try to deliver (in a separate thread) immediately
            // (triggered by storage)
            try {
                queue.enQueue(mail);
            } catch (MailQueueException e) {
                log("Unable to queue mail " + mail.getName() + " for recipients + " + mail.getRecipients().toString(), e);
            }
        }
        mail.setState(Mail.GHOST);
    }

    /**
     * Stops all the worker threads that are waiting for messages. This method
     * is called by the Mailet container before taking this Mailet out of
     * service.
     */
    @Override
    public synchronized void destroy() {
        // Mark flag so threads from this Mailet stop themselves
        destroyed = true;

        // Wake up all threads from waiting for an accept
        for (Thread t : workersThreads) {
            t.interrupt();
        }
        notifyAll();
    }

    /**
     * Handles checking the outgoing spool for new mail and delivering them if
     * there are any
     */
    @Override
    public void run() {

        // Checks the pool and delivers a mail message
        Properties props = new Properties();
        // Not needed for production environment
        props.put("mail.debug", "false");
        // Reactivated: javamail 1.3.2 should no more have problems with
        // "250 OK"
        // messages (WAS "false": Prevents problems encountered with 250 OK
        // Messages)
        props.put("mail.smtp.ehlo", "true");
        // By setting this property to true the transport is allowed to
        // send 8 bit data to the server (if it supports the 8bitmime
        // extension).
        // 2006/03/01 reverted to false because of a javamail bug converting to
        // 8bit
        // messages created by an inputstream.
        props.setProperty("mail.smtp.allow8bitmime", "true");
        // Sets timeout on going connections
        props.put("mail.smtp.timeout", smtpTimeout + "");

        props.put("mail.smtp.connectiontimeout", connectionTimeout + "");
        props.put("mail.smtp.sendpartial", String.valueOf(sendPartial));

        props.put("mail.smtp.localhost", getHeloName());

        // handle starttls
        props.put("mail.smtp.starttls.enable", String.valueOf(startTLS));

        // handle SSLEnable
        props.put("mail.smtp.ssl.enable", String.valueOf(isSSLEnable));

        if (isBindUsed) {
            // undocumented JavaMail 1.2 feature, smtp transport will use
            // our socket factory, which will also set the local address
            props.put("mail.smtp.socketFactory.class", RemoteDeliverySocketFactory.class.getClass());
            // Don't fallback to the standard socket factory on error, do throw
            // an exception
            props.put("mail.smtp.socketFactory.fallback", "false");
        }

        if (authUser != null) {
            props.put("mail.smtp.auth", "true");
        }

        props.putAll(defprops);

        final Session session = obtainSession(props);
        try {
            while (!Thread.interrupted() && !destroyed) {
                try {
                    // Get the 'mail' object that is ready for deliverying. If
                    // no
                    // message is
                    // ready, the 'accept' will block until message is ready.
                    // The amount
                    // of time to block is determined by the 'getWaitTime'
                    // method of the
                    // MultipleDelayFilter.
                    MailQueueItem queueItem = queue.deQueue();
                    Mail mail = queueItem.getMail();

                    String key = mail.getName();

                    try {
                        if (isDebug) {
                            String message = Thread.currentThread().getName() + " will process mail " + key;
                            log(message);
                        }

                        // Deliver message
                        if (deliver(mail, session)) {
                            // Message was successfully delivered/fully
                            // failed...
                            // delete it
                            LifecycleUtil.dispose(mail);
                            // workRepository.remove(key);
                        } else {
                            // Something happened that will delay delivery.
                            // Store it back in the retry repository.
                            // workRepository.store(mail);
                            int retries = 0;
                            try {
                                retries = Integer.parseInt(mail.getErrorMessage());
                            } catch (NumberFormatException e) {
                                // Something strange was happen with the
                                // errorMessage..
                            }

                            long delay = getNextDelay(retries);

                            if (usePriority) {
                                // Use lowest priority for retries. See JAMES-1311
                                mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
                            }
                            queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
                            LifecycleUtil.dispose(mail);

                            // This is an update, so we have to unlock and
                            // notify or this mail is kept locked by this
                            // thread.
                            // workRepository.unlock(key);

                            // Note: We do not notify because we updated an
                            // already existing mail and we are now free to
                            // handle
                            // more mails.
                            // Furthermore this mail should not be processed now
                            // because we have a retry time scheduling.
                        }

                        // Clear the object handle to make sure it recycles
                        // this object.
                        mail = null;
                        queueItem.done(true);
                    } catch (Exception e) {
                        // Prevent unexpected exceptions from causing looping by
                        // removing message from outgoing.
                        // DO NOT CHANGE THIS to catch Error! For example, if
                        // there were an OutOfMemory condition caused because
                        // something else in the server was abusing memory, we
                        // would
                        // not want to start purging the retrying spool!
                        log("Exception caught in RemoteDelivery.run()", e);
                        LifecycleUtil.dispose(mail);
                        // workRepository.remove(key);
                        queueItem.done(false);
                        throw new MailQueueException("Unable to perform dequeue", e);
                    }

                } catch (Throwable e) {
                    if (!destroyed) {
                        log("Exception caught in RemoteDelivery.run()", e);
                    }
                }
            }
        } finally {
            // Restore the thread state to non-interrupted.
            Thread.interrupted();
        }
    }

    /**
     * We can assume that the recipients of this message are all going to the
     * same mail server. We will now rely on the DNS server to do DNS MX record
     * lookup and try to deliver to the multiple mail servers. If it fails, it
     * should throw an exception.
     *
     * @param mail    org.apache.james.core.MailImpl
     * @param session javax.mail.Session
     * @return boolean Whether the delivery was successful and the message can
     *         be deleted
     */
    private boolean deliver(Mail mail, Session session) {
        try {
            if (isDebug) {
                log("Attempting to deliver " + mail.getName());
            }
            MimeMessage message = mail.getMessage();

            // Create an array of the recipients as InternetAddress objects
            Collection<MailAddress> recipients = mail.getRecipients();
            InternetAddress addr[] = new InternetAddress[recipients.size()];
            int j = 0;
            for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
                MailAddress rcpt = i.next();
                addr[j] = rcpt.toInternetAddress();
            }

            if (addr.length <= 0) {
                log("No recipients specified... not sure how this could have happened.");
                return true;
            }

            // Figure out which servers to try to send to. This collection
            // will hold all the possible target servers
            Iterator<HostAddress> targetServers;
            if (gatewayServer == null) {
                MailAddress rcpt = recipients.iterator().next();
                String host = rcpt.getDomain();

                // Lookup the possible targets
                try {
                    targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logAdapter);
                } catch (TemporaryResolutionException e) {
                    log("Temporary problem looking up mail server for host: " + host);
                    String exceptionBuffer = "Temporary problem looking up mail server for host: " + host + ".  I cannot determine where to send this message.";

                    // temporary problems
                    return failMessage(mail, new MessagingException(exceptionBuffer), false);
                }
                if (!targetServers.hasNext()) {
                    log("No mail server found for: " + host);
                    String exceptionBuffer = "There are no DNS entries for the hostname " + host + ".  I cannot determine where to send this message.";

                    int retry = 0;
                    try {
                        retry = Integer.parseInt(mail.getErrorMessage());
                    } catch (NumberFormatException e) {
                        // Unable to parse retryCount
                    }
                    if (retry == 0 || retry > dnsProblemRetry) {
                        // The domain has no dns entry.. Return a permanent
                        // error
                        return failMessage(mail, new MessagingException(exceptionBuffer), true);
                    } else {
                        return failMessage(mail, new MessagingException(exceptionBuffer), false);
                    }
                }
            } else {
                targetServers = getGatewaySMTPHostAddresses(gatewayServer);
            }

            MessagingException lastError = null;

            while (targetServers.hasNext()) {
                try {

                    Properties props = session.getProperties();
                    if (mail.getSender() == null) {
                        props.put("mail.smtp.from", "<>");
                    } else {
                        String sender = mail.getSender().toString();
                        props.put("mail.smtp.from", sender);
                    }

                    HostAddress outgoingMailServer = targetServers.next();
                    StringBuilder logMessageBuffer = new StringBuilder(256).append("Attempting delivery of ").append(mail.getName()).append(" to host ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from"))
                            .append(" for addresses ").append(Arrays.asList(addr));
                    log(logMessageBuffer.toString());

                    // Many of these properties are only in later JavaMail
                    // versions
                    // "mail.smtp.ehlo" //default true
                    // "mail.smtp.auth" //default false
                    // "mail.smtp.dsn.ret" //default to nothing... appended as
                    // RET= after MAIL FROM line.
                    // "mail.smtp.dsn.notify" //default to nothing...appended as
                    // NOTIFY= after RCPT TO line.

                    SMTPTransport transport = null;
                    try {
                        transport =  (SMTPTransport) session.getTransport(outgoingMailServer);
                        transport.setLocalHost( props.getProperty("mail.smtp.localhost", heloName) );
                        try {
                            if (authUser != null) {
                                transport.connect(outgoingMailServer.getHostName(), authUser, authPass);
                            } else {
                                transport.connect();
                            }
                        } catch (MessagingException me) {
                            // Any error on connect should cause the mailet to
                            // attempt
                            // to connect to the next SMTP server associated
                            // with this
                            // MX record. Just log the exception. We'll worry
                            // about
                            // failing the message at the end of the loop.

                            // Also include the stacktrace if debug is enabled. See JAMES-1257
                            if (isDebug) {
                                log(me.getMessage(), me.getCause());
                            } else {
                                log(me.getMessage());
                            }
                            continue;
                        }
                        // if the transport is a SMTPTransport (from sun) some
                        // performance enhancement can be done.
                        if (transport.getClass().getName().endsWith(".SMTPTransport")) {
                            boolean supports8bitmime = false;
                            try {
                                Method supportsExtension = transport.getClass().getMethod("supportsExtension", new Class[]{String.class});
                                supports8bitmime = (Boolean) supportsExtension.invoke(transport, "8BITMIME");
                            } catch (NoSuchMethodException nsme) {
                                // An SMTPAddressFailedException with no
                                // getAddress method.
                            } catch (IllegalAccessException iae) {
                            } catch (IllegalArgumentException iae) {
                            } catch (InvocationTargetException ite) {
                                // Other issues with getAddress invokation.
                            }

                            // if the message is alredy 8bit or binary and the
                            // server doesn't support the 8bit extension it has
                            // to be converted to 7bit. Javamail api doesn't
                            // perform
                            // that conversion, but it is required to be a
                            // rfc-compliant smtp server.

                            // Temporarily disabled. See JAMES-638
                            if (!supports8bitmime) {
                                try {
                                    convertTo7Bit(message);
                                } catch (IOException e) {
                                    // An error has occured during the 7bit
                                    // conversion.
                                    // The error is logged and the message is
                                    // sent anyway.

                                    log("Error during the conversion to 7 bit.", e);
                                }
                            }
                        } else {
                            // If the transport is not the one
                            // developed by Sun we are not sure of how it
                            // handles the 8 bit mime stuff,
                            // so I convert the message to 7bit.
                            try {
                                convertTo7Bit(message);
                            } catch (IOException e) {
                                log("Error during the conversion to 7 bit.", e);
                            }
                        }
                        transport.sendMessage(message, addr);
                    } finally {
                        if (transport != null) {
                            try {
                                // James-899: transport.close() sends QUIT to
                                // the server; if that fails
                                // (e.g. because the server has already closed
                                // the connection) the message
                                // should be considered to be delivered because
                                // the error happened outside
                                // of the mail transaction (MAIL, RCPT, DATA).
                                transport.close();
                            } catch (MessagingException e) {
                                log("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
                                        + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
                            }
                            transport = null;
                        }
                    }
                    logMessageBuffer = new StringBuilder(256).append("Mail (").append(mail.getName()).append(") sent successfully to ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from")).append(" for ")
                            .append(mail.getRecipients());
                    log(logMessageBuffer.toString());
                    return true;
                } catch (SendFailedException sfe) {
                    logSendFailedException(sfe);

                    if (sfe.getValidSentAddresses() != null) {
                        Address[] validSent = sfe.getValidSentAddresses();
                        if (validSent.length > 0) {
                            String logMessageBuffer = "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent);
                            log(logMessageBuffer);
                        }
                    }

                    /*
                     * SMTPSendFailedException introduced in JavaMail 1.3.2, and
                     * provides detailed protocol reply code for the operation
                     */
                    if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
                        try {
                            int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
                            // if 5xx, terminate this delivery attempt by
                            // re-throwing the exception.
                            if (returnCode >= 500 && returnCode <= 599)
                                throw sfe;
                        } catch (ClassCastException cce) {
                        } catch (IllegalArgumentException iae) {
                        }
                    }

                    if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
                        if (isDebug)
                            log("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
                        lastError = sfe;
                    } else {
                        // There are no valid addresses left to send, so rethrow
                        throw sfe;
                    }
                } catch (MessagingException me) {
                    // MessagingException are horribly difficult to figure out
                    // what actually happened.
                    String exceptionBuffer = "Exception delivering message (" + mail.getName() + ") - " + me.getMessage();
                    log(exceptionBuffer);
                    if ((me.getNextException() != null) && (me.getNextException() instanceof java.io.IOException)) {
                        // This is more than likely a temporary failure

                        // If it's an IO exception with no nested exception,
                        // it's probably
                        // some socket or weird I/O related problem.
                        lastError = me;
                        continue;
                    }
                    // This was not a connection or I/O error particular to one
                    // SMTP server of an MX set. Instead, it is almost certainly
                    // a protocol level error. In this case we assume that this
                    // is an error we'd encounter with any of the SMTP servers
                    // associated with this MX record, and we pass the exception
                    // to the code in the outer block that determines its
                    // severity.
                    throw me;
                }
            } // end while
            // If we encountered an exception while looping through,
            // throw the last MessagingException we caught. We only
            // do this if we were unable to send the message to any
            // server. If sending eventually succeeded, we exit
            // deliver() though the return at the end of the try
            // block.
            if (lastError != null) {
                throw lastError;
            }
        } catch (SendFailedException sfe) {
            logSendFailedException(sfe);

            // Copy the recipients as direct modification may not be possible
            Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());

            boolean deleteMessage = false;

            /*
             * If you send a message that has multiple invalid addresses, you'll
             * get a top-level SendFailedException that that has the valid,
             * valid-unsent, and invalid address lists, with all of the server
             * response messages will be contained within the nested exceptions.
             * [Note: the content of the nested exceptions is implementation
             * dependent.]
             *
             * sfe.getInvalidAddresses() should be considered permanent.
             * sfe.getValidUnsentAddresses() should be considered temporary.
             *
             * JavaMail v1.3 properly populates those collections based upon the
             * 4xx and 5xx response codes to RCPT TO. Some servers, such as
             * Yahoo! don't respond to the RCPT TO, and provide a 5xx reply
             * after DATA. In that case, we will pick up the failure from
             * SMTPSendFailedException.
             */

            /*
             * SMTPSendFailedException introduced in JavaMail 1.3.2, and
             * provides detailed protocol reply code for the operation
             */
            try {
                if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
                    int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
                    // If we got an SMTPSendFailedException, use its RetCode to
                    // determine default permanent/temporary failure
                    deleteMessage = (returnCode >= 500 && returnCode <= 599);
                } else {
                    // Sometimes we'll get a normal SendFailedException with
                    // nested SMTPAddressFailedException, so use the latter
                    // RetCode
                    MessagingException me = sfe;
                    Exception ne;
                    while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
                        me = (MessagingException) ne;
                        if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
                            int returnCode = (Integer) invokeGetter(me, "getReturnCode");
                            deleteMessage = (returnCode >= 500 && returnCode <= 599);
                        }
                    }
                }
            } catch (IllegalStateException ise) {
                // unexpected exception (not a compatible javamail
                // implementation)
            } catch (ClassCastException cce) {
                // unexpected exception (not a compatible javamail
                // implementation)
            }

            // log the original set of intended recipients
            if (isDebug)
                log("Recipients: " + recipients);

            if (sfe.getInvalidAddresses() != null) {
                Address[] address = sfe.getInvalidAddresses();
                if (address.length > 0) {
                    recipients.clear();
                    for (Address addres : address) {
                        try {
                            recipients.add(new MailAddress(addres.toString()));
                        } catch (ParseException pe) {
                            // this should never happen ... we should have
                            // caught malformed addresses long before we
                            // got to this code.
                            log("Can't parse invalid address: " + pe.getMessage());
                        }
                    }
                    // Set the recipients for the mail
                    mail.setRecipients(recipients);

                    if (isDebug)
                        log("Invalid recipients: " + recipients);
                    deleteMessage = failMessage(mail, sfe, true);
                }
            }

            if (sfe.getValidUnsentAddresses() != null) {
                Address[] address = sfe.getValidUnsentAddresses();
                if (address.length > 0) {
                    recipients.clear();
                    for (Address addres : address) {
                        try {
                            recipients.add(new MailAddress(addres.toString()));
                        } catch (ParseException pe) {
                            // this should never happen ... we should have
                            // caught malformed addresses long before we
                            // got to this code.
                            log("Can't parse unsent address: " + pe.getMessage());
                        }
                    }
                    // Set the recipients for the mail
                    mail.setRecipients(recipients);
                    if (isDebug)
                        log("Unsent recipients: " + recipients);
                    if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
                        int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
                        deleteMessage = failMessage(mail, sfe, returnCode >= 500 && returnCode <= 599);
                    } else {
                        deleteMessage = failMessage(mail, sfe, false);
                    }
                }
            }

            return deleteMessage;
        } catch (MessagingException ex) {
            // We should do a better job checking this... if the failure is a
            // general
            // connect exception, this is less descriptive than more specific
            // SMTP command
            // failure... have to lookup and see what are the various Exception
            // possibilities

            // Unable to deliver message after numerous tries... fail
            // accordingly

            // We check whether this is a 5xx error message, which
            // indicates a permanent failure (like account doesn't exist
            // or mailbox is full or domain is setup wrong).
            // We fail permanently if this was a 5xx error
            return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0)));
        } catch (Exception ex) {
            // Generic exception = permanent failure
            return failMessage(mail, ex, true);
        }

        /*
         * If we get here, we've exhausted the loop of servers without sending
         * the message or throwing an exception. One case where this might
         * happen is if we get a MessagingException on each transport.connect(),
         * e.g., if there is only one server and we get a connect exception.
         */
        return failMessage(mail, new MessagingException("No mail server(s) available at this time."), false);
    }

    /**
     * Try to return a usefull logString created of the Exception which was
     * given. Return null if nothing usefull could be done
     *
     * @param e The MessagingException to use
     * @return logString
     */
    private String exceptionToLogString(Exception e) {
        if (e.getClass().getName().endsWith(".SMTPSendFailedException")) {
            return "RemoteHost said: " + e.getMessage();
        } else if (e instanceof SendFailedException) {
            SendFailedException exception = (SendFailedException) e;

            // No error
            if (exception.getInvalidAddresses().length == 0 && exception.getValidUnsentAddresses().length == 0)
                return null;

            Exception ex;
            StringBuilder sb = new StringBuilder();
            boolean smtpExFound = false;
            sb.append("RemoteHost said:");

            if (e instanceof MessagingException)
                while ((ex = ((MessagingException) e).getNextException()) != null && ex instanceof MessagingException) {
                    e = ex;
                    if (ex.getClass().getName().endsWith(".SMTPAddressFailedException")) {
                        try {
                            InternetAddress ia = (InternetAddress) invokeGetter(ex, "getAddress");
                            sb.append(" ( ").append(ia).append(" - [").append(ex.getMessage().replaceAll("\\n", "")).append("] )");
                            smtpExFound = true;
                        } catch (IllegalStateException ise) {
                            // Error invoking the getAddress method
                        } catch (ClassCastException cce) {
                            // The getAddress method returned something
                            // different than InternetAddress
                        }
                    }
                }
            if (!smtpExFound) {
                boolean invalidAddr = false;
                sb.append(" ( ");

                if (exception.getInvalidAddresses().length > 0) {
                    sb.append(Arrays.toString(exception.getInvalidAddresses()));
                    invalidAddr = true;
                }
                if (exception.getValidUnsentAddresses().length > 0) {
                    if (invalidAddr)
                        sb.append(" ");
                    sb.append(Arrays.toString(exception.getValidUnsentAddresses()));
                }
                sb.append(" - [");
                sb.append(exception.getMessage().replaceAll("\\n", ""));
                sb.append("] )");
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * Utility method used to invoke getters for javamail implementation
     * specific classes.
     *
     * @param target the object whom method will be invoked
     * @param getter the no argument method name
     * @return the result object
     * @throws IllegalStateException on invocation error
     */
    private Object invokeGetter(Object target, String getter) {
        try {
            Method getAddress = target.getClass().getMethod(getter, null);
            return getAddress.invoke(target, null);
        } catch (NoSuchMethodException nsme) {
            // An SMTPAddressFailedException with no getAddress method.
        } catch (IllegalAccessException iae) {
        } catch (IllegalArgumentException iae) {
        } catch (InvocationTargetException ite) {
            // Other issues with getAddress invokation.
        }
        return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
    }

    /*
     * private method to log the extended SendFailedException introduced in
     * JavaMail 1.3.2.
     */
    private void logSendFailedException(SendFailedException sfe) {
        if (isDebug) {
            MessagingException me = sfe;
            if (me.getClass().getName().endsWith(".SMTPSendFailedException")) {
                try {
                    String command = (String) invokeGetter(sfe, "getCommand");
                    Integer returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
                    log("SMTP SEND FAILED:");
                    log(sfe.toString());
                    log("  Command: " + command);
                    log("  RetCode: " + returnCode);
                    log("  Response: " + sfe.getMessage());
                } catch (IllegalStateException ise) {
                    // Error invoking the getAddress method
                    log("Send failed: " + me.toString());
                } catch (ClassCastException cce) {
                    // The getAddress method returned something different than
                    // InternetAddress
                    log("Send failed: " + me.toString());
                }
            } else {
                log("Send failed: " + me.toString());
            }
            Exception ne;
            while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
                me = (MessagingException) ne;
                if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
                    try {
                        String action = me.getClass().getName().endsWith(".SMTPAddressFailedException") ? "FAILED" : "SUCCEEDED";
                        InternetAddress address = (InternetAddress) invokeGetter(me, "getAddress");
                        String command = (String) invokeGetter(me, "getCommand");
                        Integer returnCode = (Integer) invokeGetter(me, "getReturnCode");
                        log("ADDRESS " + action + ":");
                        log(me.toString());
                        log("  Address: " + address);
                        log("  Command: " + command);
                        log("  RetCode: " + returnCode);
                        log("  Response: " + me.getMessage());
                    } catch (IllegalStateException ise) {
                        // Error invoking the getAddress method
                    } catch (ClassCastException cce) {
                        // A method returned something different than expected
                    }
                }
            }
        }
    }

    /**
     * Converts a message to 7 bit.
     *
     * @param part
     */
    private void convertTo7Bit(MimePart part) throws MessagingException, IOException {
        if (part.isMimeType("multipart/*")) {
            MimeMultipart parts = (MimeMultipart) part.getContent();
            int count = parts.getCount();
            for (int i = 0; i < count; i++) {
                convertTo7Bit((MimePart) parts.getBodyPart(i));
            }
        } else if ("8bit".equals(part.getEncoding())) {
            // The content may already be in encoded the form (likely with mail
            // created from a
            // stream). In that case, just changing the encoding to
            // quoted-printable will mangle
            // the result when this is transmitted. We must first convert the
            // content into its
            // native format, set it back, and only THEN set the transfer
            // encoding to force the
            // content to be encoded appropriately.

            // if the part doesn't contain text it will be base64 encoded.
            String contentTransferEncoding = part.isMimeType("text/*") ? "quoted-printable" : "base64";
            part.setContent(part.getContent(), part.getContentType());
            part.setHeader("Content-Transfer-Encoding", contentTransferEncoding);
            part.addHeader("X-MIME-Autoconverted", "from 8bit to " + contentTransferEncoding + " by " + getMailetContext().getServerInfo());
        }
    }

    /**
     * Insert the method's description here.
     *
     * @param mail      org.apache.james.core.MailImpl
     * @param ex        javax.mail.MessagingException
     * @param permanent
     * @return boolean Whether the message failed fully and can be deleted
     */
    private boolean failMessage(Mail mail, Exception ex, boolean permanent) {
        StringWriter sout = new StringWriter();
        PrintWriter out = new PrintWriter(sout, true);
        if (permanent) {
            out.print("Permanent");
        } else {
            out.print("Temporary");
        }

        String exceptionLog = exceptionToLogString(ex);

        StringBuilder logBuffer = new StringBuilder(64).append(" exception delivering mail (").append(mail.getName());

        if (exceptionLog != null) {
            logBuffer.append(". ");
            logBuffer.append(exceptionLog);
        }

        logBuffer.append(": ");
        out.print(logBuffer.toString());
        if (isDebug)
            ex.printStackTrace(out);
        log(sout.toString());
        if (!permanent) {
            if (!mail.getState().equals(Mail.ERROR)) {
                mail.setState(Mail.ERROR);
                mail.setErrorMessage("0");
                mail.setLastUpdated(new Date());
            }

            int retries = 0;
            try {
                retries = Integer.parseInt(mail.getErrorMessage());
            } catch (NumberFormatException e) {
                // Something strange was happen with the errorMessage..
            }

            if (retries < maxRetries) {
                logBuffer = new StringBuilder(128).append("Storing message ").append(mail.getName()).append(" into outgoing after ").append(retries).append(" retries");
                log(logBuffer.toString());
                ++retries;
                mail.setErrorMessage(retries + "");
                mail.setLastUpdated(new Date());
                return false;
            } else {
                logBuffer = new StringBuilder(128).append("Bouncing message ").append(mail.getName()).append(" after ").append(retries).append(" retries");
                log(logBuffer.toString());
            }
        }

        if (mail.getSender() == null) {
            log("Null Sender: no bounce will be generated for " + mail.getName());
            return true;
        }

        if (bounceProcessor != null) {
            // do the new DSN bounce
            // setting attributes for DSN mailet
            String cause;
            if (ex instanceof MessagingException) {
                cause = getErrorMsg((MessagingException) ex);
            } else {
                cause = ex.getMessage();
            }
            mail.setAttribute("delivery-error", cause);
            mail.setState(bounceProcessor);
            // re-insert the mail into the spool for getting it passed to the
            // dsn-processor
            MailetContext mc = getMailetContext();
            try {
                mc.sendMail(mail);
            } catch (MessagingException e) {
                // we shouldn't get an exception, because the mail was already
                // processed
                log("Exception re-inserting failed mail: ", e);
            }
        } else {
            // do an old style bounce
            bounce(mail, ex);
        }
        return true;
    }

    /**
     * Utility method for getting the error message from the (nested) exception.
     *
     * @param me MessagingException
     * @return error message
     */
    protected String getErrorMsg(MessagingException me) {
        if (me.getNextException() == null) {
            return me.getMessage().trim();
        } else {
            Exception ex1 = me.getNextException();
            return ex1.getMessage().trim();
        }
    }

    private void bounce(Mail mail, Exception ex) {
        StringWriter sout = new StringWriter();
        PrintWriter out = new PrintWriter(sout, true);
        String machine;
        try {
            machine = getHeloName();

        } catch (Exception e) {
            machine = "[address unknown]";
        }
        String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
        out.println(bounceBuffer);
        out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
        out.println("This is a permanent error; I've given up. Sorry it didn't work out.  Below");
        out.println("I include the list of recipients and the reason why I was unable to deliver");
        out.println("your message.");
        out.println();
        for (MailAddress mailAddress : mail.getRecipients()) {
            out.println(mailAddress);
        }
        if (ex instanceof MessagingException) {
            if (((MessagingException) ex).getNextException() == null) {
                out.println(ex.getMessage().trim());
            } else {
                Exception ex1 = ((MessagingException) ex).getNextException();
                if (ex1 instanceof SendFailedException) {
                    out.println("Remote mail server told me: " + ex1.getMessage().trim());
                } else if (ex1 instanceof UnknownHostException) {
                    out.println("Unknown host: " + ex1.getMessage().trim());
                    out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
                } else if (ex1 instanceof ConnectException) {
                    // Already formatted as "Connection timed out: connect"
                    out.println(ex1.getMessage().trim());
                } else if (ex1 instanceof SocketException) {
                    out.println("Socket exception: " + ex1.getMessage().trim());
                } else {
                    out.println(ex1.getMessage().trim());
                }
            }
        }
        out.println();

        log("Sending failure message " + mail.getName());
        try {
            getMailetContext().bounce(mail, sout.toString());
        } catch (MessagingException me) {
            log("Encountered unexpected messaging exception while bouncing message: " + me.getMessage());
        } catch (Exception e) {
            log("Encountered unexpected exception while bouncing message: " + e.getMessage());
        }
    }

    /**
     * Returns the javamail Session object.
     *
     * @param props
     * @return the java mail session
     */
    protected Session obtainSession(Properties props) {
        return Session.getInstance(props);
    }

    /**
     * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
     * subclass of javax.mail.URLName, which provides location information for
     * servers that are specified as mail handlers for the given hostname. If no
     * host is found, the Iterator returned will be empty and the first call to
     * hasNext() will return false. The Iterator is a nested iterator: the outer
     * iteration is over each gateway, and the inner iteration is over
     * potentially multiple A records for each gateway.
     *
     * @param gatewayServers - Collection of host[:port] Strings
     * @return an Iterator over HostAddress instances, sorted by priority
     * @since v2.2.0a16-unstable
     */
    private Iterator<HostAddress> getGatewaySMTPHostAddresses(final Collection<String> gatewayServers) {
        Iterator<String> gateways = gatewayServers.iterator();

        return new MXHostAddressIterator(gateways, dnsServer, false, logAdapter);
    }

    protected String getHeloName() {
        if (heloName == null) {
            // TODO: Maybe we should better just lookup the hostname via dns
            try {
                return domainList.getDefaultDomain();
            } catch (DomainListException e) {
                log("Unable to access DomainList", e);
                return "localhost";
            }
        } else {
            return heloName;
        }
    }

}


text:
import React, { Component } from 'react';

//funcional component
/*const SearchBar = () => {
  return <input />
}*/

//object component
class SearchBar extends Component{
  constructor(props){
    super(props);

    this.state = {term: ''};
  }
  render(){
    return (
      <div>
        <input
        value = {this.state.term}
        onChange = { event => this.onInputChange(event.target.value) } />

      </div>
    );
  }

  onInputChange(term){
    this.setState({term});
    this.props.onSearchTermChange(term);
  }
}

export default SearchBar;

redpajama_set_name: RedPajamaGithub


text:
package av.is.leveledstorage.storages.bukkit.meta;

import org.bukkit.Color;
import org.bukkit.inventory.meta.MapMeta;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/**
 * Created by Avis Network on 2017-11-05.
 */
public class MapMetaStorage extends ItemMetaStorage<MapMeta> {

    public MapMetaStorage(MapMeta meta) {
        super(meta);
    }

    @Override
    public void read(DataInputStream input) throws IOException {
        super.read(input);

        getValue().setScaling(input.readBoolean());

        boolean hasLocationName = input.readBoolean();
        if(hasLocationName) {
            getValue().setLocationName(input.readUTF());
        }

        boolean hasColor = input.readBoolean();
        if(hasColor) {
            getValue().setColor(Color.fromRGB(input.readInt(), input.readInt(), input.readInt()));
        }
    }

    @Override
    public void write(DataOutputStream output) throws IOException {
        super.write(output);

        output.writeBoolean(getValue().isScaling());
        output.writeBoolean(getValue().hasLocationName());
        if(getValue().hasLocationName()) {
            output.writeUTF(getValue().getLocationName());
        }
        output.writeBoolean(getValue().hasColor());
        if(getValue().hasColor()) {
            output.writeInt(getValue().getColor().getRed());
            output.writeInt(getValue().getColor().getGreen());
            output.writeInt(getValue().getColor().getBlue());
        }
    }
}


text:
package biz.paluch.spinach.commands.rx;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import rx.Observable;
import biz.paluch.spinach.api.DisqueConnection;
import biz.paluch.spinach.api.sync.DisqueCommands;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.reflect.AbstractInvocationHandler;

public class RxSyncInvocationHandler<K, V> extends AbstractInvocationHandler {

    private final DisqueConnection<?, ?> connection;
    private final Object rxApi;

    public RxSyncInvocationHandler(DisqueConnection<?, ?> connection, Object rxApi) {
        this.connection = connection;
        this.rxApi = rxApi;
    }

    /**
     *
     * @see AbstractInvocationHandler#handleInvocation(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
     */
    @Override
    @SuppressWarnings("unchecked")
    protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {

        try {

            Method targetMethod = rxApi.getClass().getMethod(method.getName(), method.getParameterTypes());

            Object result = targetMethod.invoke(rxApi, args);

            if (result == null || !(result instanceof Observable<?>)) {
                return result;
            }
            Observable<?> observable = (Observable<?>) result;

            Iterable<?> objects = observable.toBlocking().toIterable();

            if (method.getReturnType().equals(List.class)) {
                return Lists.newArrayList(objects);
            }

            if (method.getReturnType().equals(Set.class)) {
                return Sets.newHashSet(objects);
            }

            Iterator<?> iterator = objects.iterator();

            if (iterator.hasNext()) {
                return iterator.next();
            }

            return null;

        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

    public static <K, V> DisqueCommands<K, V> sync(DisqueConnection<K, V> connection) {

        RxSyncInvocationHandler<K, V> handler = new RxSyncInvocationHandler<K, V>(connection, connection.reactive());
        return (DisqueCommands<K, V>) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                new Class<?>[] { DisqueCommands.class }, handler);
    }
}


text:
namespace EraFileCreator.Service.Messaging
{
    public class SaveFileMessage
    {
    }
}


text:
var when = require("when");
var request = require('request');

var getApiRoot = require('../../config').getApiRoot;
var BLUEPRINT_BASE_URL = getApiRoot('xively.services.blueprint');

var getAccountUsers = function(accountId, jwt, userId) {
    return when.promise(function(resolve) {
        request.get({
          url: BLUEPRINT_BASE_URL+'account-users',
          headers: {
            Authorization: "Bearer "+ jwt
          },
          qs:{
            accountId: accountId,
            userId: userId

          }
        },
        function(err,httpResponse,body){
          var resp = JSON.parse(body);
          resolve(resp);
        });
  });
};

var postAccountUsers = function(accountId, jwt, userId) {
    //creates an account user
    return when.promise(function(resolve) {
        request.post({
          url: BLUEPRINT_BASE_URL+'account-users',
          headers: {
            Authorization: "Bearer "+ jwt
          },
          form:{
            accountId: accountId,
            userId: userId
          }
        },
        function(err,httpResponse,body){
          var resp = JSON.parse(body);
          resolve(resp);
        });
  });
};

var putAccountUsers = function(id, userId, etag) {
    //updates an account user
    return when.promise(function(resolve) {
        request.put({
          url: BLUEPRINT_BASE_URL+'account-users/'+id,
          headers: {
            AccessToken: accesstoken
          },
          form:{
            emailAddress: email,
            accountId: accountid,
            password: password
          }
        },
        function(err,httpResponse,body){
          var resp = JSON.parse(body);
          resolve(resp);
        });
  });
};

module.exports = {
    get: getAccountUsers,
    post: postAccountUsers,
  	put: putAccountUsers
};


text:
/*
 * The Plaid API
 * The Plaid REST API. Please see https://plaid.com/docs/api for more details.
 *
 * The version of the OpenAPI document: 2020-09-14_1.205.3
 *
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

package com.plaid.client.model;

import java.util.Objects;
import java.util.Arrays;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.plaid.client.model.WalletTransactionCounterpartyNumbers;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;

/**
 * An object representing the e-wallet transaction's counterparty
 */
@ApiModel(description = "An object representing the e-wallet transaction's counterparty")
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2022-11-17T17:52:41.932844Z[Etc/UTC]")
public class WalletTransactionCounterparty {
  public static final String SERIALIZED_NAME_NAME = "name";
  @SerializedName(SERIALIZED_NAME_NAME)
  private String name;

  public static final String SERIALIZED_NAME_NUMBERS = "numbers";
  @SerializedName(SERIALIZED_NAME_NUMBERS)
  private WalletTransactionCounterpartyNumbers numbers;

  public WalletTransactionCounterparty name(String name) {

    this.name = name;
    return this;
  }

   /**
   * The name of the counterparty
   * @return name
  **/
  @ApiModelProperty(required = true, value = "The name of the counterparty")

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public WalletTransactionCounterparty numbers(WalletTransactionCounterpartyNumbers numbers) {

    this.numbers = numbers;
    return this;
  }

   /**
   * Get numbers
   * @return numbers
  **/
  @ApiModelProperty(required = true, value = "")

  public WalletTransactionCounterpartyNumbers getNumbers() {
    return numbers;
  }

  public void setNumbers(WalletTransactionCounterpartyNumbers numbers) {
    this.numbers = numbers;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    WalletTransactionCounterparty walletTransactionCounterparty = (WalletTransactionCounterparty) o;
    return Objects.equals(this.name, walletTransactionCounterparty.name) &&
        Objects.equals(this.numbers, walletTransactionCounterparty.numbers);
  }

  @Override
  public int hashCode() {
    return Objects.hash(name, numbers);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class WalletTransactionCounterparty {\n");
    sb.append("    name: ").append(toIndentedString(name)).append("\n");
    sb.append("    numbers: ").append(toIndentedString(numbers)).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }

}


text:
package git

import (
	"fmt"
	"io"
	"os"
)

type MergeStrategy string

func commitishName(c Commitish) string {
	if b, ok := c.(Branch); ok {
		return b.BranchName()
	}
	return ""
}

const (
	MergeRecursive = MergeStrategy("recursive")
	MergeOctopus   = MergeStrategy("octopus")
)

var AlreadyUpToDate = fmt.Errorf("Already up-to-date.")

// Merge options represent the options that may be passed on
// the command line to "git merge"
type MergeOptions struct {
	// Not implemented
	NoCommit bool

	// Not implemented
	NoEdit bool

	NoFastForward   bool
	FastForwardOnly bool

	// Not implemented
	Log int
	// Not implemented
	Stat bool

	// Not implemented
	Squash bool

	// Not implemented
	Strategy MergeStrategy

	// Not implemented
	VerifySignatures bool

	// Not implemented
	Quiet bool
	// Not implemented
	Verbose bool

	// Not implemented
	NoProgress bool

	// Not implemented
	Message string
}

// Aborts an in progress merge as "git merge --abort"
// (Not implemented)
func MergeAbort(c *Client, opt MergeOptions) error {
	return fmt.Errorf("MergeAbort not yet implemented")
}

// Implements the "git merge" porcelain command to merge other commits
// into HEAD and create a new commit.
func Merge(c *Client, opts MergeOptions, others []Commitish) error {
	if len(others) < 1 {
		return fmt.Errorf("Can't merge nothing.")
	}

	head, err := c.GetHeadCommit()
	if err != nil {
		return err
	}

	// Check if all commits are already in head
	needsMerge := false
	for _, commit := range others {
		cid, err := commit.CommitID(c)
		if err != nil {
			return err
		}
		if !cid.IsAncestor(c, head) {
			needsMerge = true
			break
		}
	}
	if !needsMerge {
		return AlreadyUpToDate

	}

	// RevParse returns ParsedRevisions, which are Commitish, but slices
	// can't be passed in terms of interfaces without converting them
	// first.
	commitsWithHead := []Commitish{head}
	commitsWithHead = append(commitsWithHead, others...)

	// Find the mergebase. Use --octopus if there's more than 2 commits.
	base, err := MergeBase(c, MergeBaseOptions{Octopus: len(commitsWithHead) > 2}, commitsWithHead)
	if err != nil {
		return err
	}

	// Check if it's a fast-forward commit. If the merge base is HEAD,
	// it's a fast-forward
	if base == head && !opts.NoFastForward {
		dst := others[0]

		// Resolve to a CommitID to implement Treeish for ReadTree
		dstc, err := dst.CommitID(c)
		if err != nil {
			return err
		}
		_, err = ReadTreeFastForward(
			c,
			ReadTreeOptions{Merge: true, Update: true},
			head,
			dstc,
		)
		if err != nil {
			return err
		}
		var refmsg string
		if b, ok := others[0].(Branch); ok && b.BranchName() != "" {
			refmsg = fmt.Sprintf("merge %s into %s: Fast-forward (dgit)", b.BranchName(), c.GetHeadBranch().BranchName())
		} else {
			refmsg = fmt.Sprintf("merge into %s: Fast-forward (dgit)", c.GetHeadBranch().BranchName())
		}

		return UpdateRef(c, UpdateRefOptions{OldValue: head, CreateReflog: true}, "HEAD", dstc, refmsg)
	}

	if opts.FastForwardOnly {
		return fmt.Errorf("Not a fast-forward commit.")
	}

	if len(others) != 1 {
		return fmt.Errorf("Can only merge one branch at a time (for now.)")
	}

	// Perform a three-way merge with mergebase, head, and tree.
	tree, err := others[0].CommitID(c)
	if err != nil {
		return err
	}

	idx, err := ReadTreeThreeWay(c,
		ReadTreeOptions{
			Merge:  true,
			Update: true,
		},
		base,
		head,
		tree,
	)
	if err != nil {
		return err
	}

	// run MergeFile on any unmerged entries.
	unmerged := idx.GetUnmerged()
	if len(unmerged) != 0 {
		// Flag conflicts in the tree if necessary.
		conflictLabel := commitishName(others[0])
		if conflictLabel == "" {
			conflictLabel = tree.String()
		}
		var errStr string
		for path, file := range unmerged {
			fp, err := path.FilePath(c)
			if err != nil {
				return err
			}

			fmt.Fprintf(os.Stderr, "Auto-merging %v\n", fp)

			// Check out the stages to temporary files for MergeFile
			stage1tmp, _ := checkoutTemp(c, file.Stage1, CheckoutIndexOptions{})
			defer os.Remove(stage1tmp)
			stage2tmp, _ := checkoutTemp(c, file.Stage2, CheckoutIndexOptions{})
			defer os.Remove(stage2tmp)
			stage3tmp, _ := checkoutTemp(c, file.Stage3, CheckoutIndexOptions{})
			defer os.Remove(stage3tmp)

			// run git merge-file with the appropriate parameters.
			r, err := MergeFile(c,
				MergeFileOptions{
					Current: MergeFileFile{
						Filename: File(stage2tmp),
						Label:    "HEAD",
					},
					Base: MergeFileFile{
						Filename: File(stage1tmp),
						Label:    "merged common ancestors",
					},
					Other: MergeFileFile{
						Filename: File(stage3tmp),
						Label:    conflictLabel,
					},
				},
			)
			if err != nil {
				errStr += "CONFLICT (content): Merge conflict in " + fp.String() + "\n"
			}

			// Write the output with conflict markers into the file.
			f2, err := os.Create(fp.String())
			if err != nil {
				return err
			}

			io.Copy(f2, r)
			f2.Close()
		}

		// Only error out if there was at least 1 conflict, otherwise it was
		// a success.
		if errStr != "" {
			return fmt.Errorf("%vAutomatic merge failed; fix conflicts and then commit the result.", errStr)
		}
	}

	// TODO: Finally, create the new commit.
	return nil
}


text:
package com.anshulvyas.csc780.grocerymanagr;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import com.anshulvyas.csc780.grocerymanagr.Adapters.TimelineAdapter;
import com.anshulvyas.csc780.grocerymanagr.Model.DBManager;

import java.util.ArrayList;
import java.util.List;

/**
 * Hosts the listView of all the items that user has kept the track of
 * - with appropriate flags, i.e., stocked, expired or consumed.
 */
public class TimelineFragment extends Fragment {

    private List<Product> timelineList, filterTimelineList;
    private DBManager dbManager;
    private ListView timelineListView;

    /**
     * Called to do initial creation of a fragment. (overridden)
     * @param savedInstanceState
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        dbManager = new DBManager(getActivity());
    }

    /**
     * Called to have the fragment instantiate its user interface view.
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return view
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_timeline, container, false);

        filterTimelineList = new ArrayList<>();

        timelineList = dbManager.getAllProducts();
        if (timelineList.size() > 0) {
            Log.i("~!@#TIMELINEFRAGMENT", timelineList.get(0).toString());

            /**
             * Checking for the items that are in the shopping list items and not in the product items.
             */
            for (int i = 0; i < timelineList.size(); i++) {
                if (!timelineList.get(i).isShoppingCheck()) {
                    filterTimelineList.add(timelineList.get(i));
                }
            }

            timelineListView = (ListView) view.findViewById(R.id.listView_timeline_product);
            final TimelineAdapter timelineAdapter = new TimelineAdapter(getActivity().getBaseContext(), R.layout.list_view_timeline,
                    filterTimelineList);
            timelineListView.setAdapter(timelineAdapter);
            timelineListView.setDivider(this.getResources().getDrawable(R.drawable.transparent));

            timelineAdapter.setNotifyOnChange(true);
            timelineAdapter.notifyDataSetChanged();

        } else {
            Log.i("~!@#TIMELINEFRAGMENT", "list view not displayed");
        }
        return view;

    }
}


text:
package file

//go:generate go run gen.go
//go:generate gofmt -s -w .

import (
	"io/ioutil"
	"os"
	"path/filepath"

	"cuelang.org/go/cue"
	"cuelang.org/go/internal/task"
)

func init() {
	task.Register("tool/file.Read", newReadCmd)
	task.Register("tool/file.Append", newAppendCmd)
	task.Register("tool/file.Create", newCreateCmd)
	task.Register("tool/file.Glob", newGlobCmd)
}

func newReadCmd(v cue.Value) (task.Runner, error)   { return &cmdRead{}, nil }
func newAppendCmd(v cue.Value) (task.Runner, error) { return &cmdAppend{}, nil }
func newCreateCmd(v cue.Value) (task.Runner, error) { return &cmdCreate{}, nil }
func newGlobCmd(v cue.Value) (task.Runner, error)   { return &cmdGlob{}, nil }

type cmdRead struct{}
type cmdAppend struct{}
type cmdCreate struct{}
type cmdGlob struct{}

func (c *cmdRead) Run(ctx *task.Context) (res interface{}, err error) {
	filename := ctx.String("filename")
	if ctx.Err != nil {
		return nil, ctx.Err
	}

	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	update := map[string]interface{}{"contents": b}

	switch v := ctx.Lookup("contents"); v.IncompleteKind() {
	case cue.BytesKind:
		// already set above
	case cue.StringKind:
		update["contents"] = string(b)
	}
	return update, nil
}

func (c *cmdAppend) Run(ctx *task.Context) (res interface{}, err error) {
	var (
		filename = filepath.FromSlash(ctx.String("filename"))
		mode     = ctx.Int64("permissions")
		b        = ctx.Bytes("contents")
	)
	if ctx.Err != nil {
		return nil, ctx.Err
	}

	f, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.FileMode(mode))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	if _, err := f.Write(b); err != nil {
		return nil, err
	}
	return nil, nil
}

func (c *cmdCreate) Run(ctx *task.Context) (res interface{}, err error) {
	var (
		filename = filepath.FromSlash(ctx.String("filename"))
		mode     = ctx.Int64("permissions")
		b        = ctx.Bytes("contents")
	)
	if ctx.Err != nil {
		return nil, ctx.Err
	}

	return nil, ioutil.WriteFile(filename, b, os.FileMode(mode))
}

func (c *cmdGlob) Run(ctx *task.Context) (res interface{}, err error) {
	glob := ctx.String("glob")
	if ctx.Err != nil {
		return nil, ctx.Err
	}
	m, err := filepath.Glob(glob)
	for i, s := range m {
		m[i] = filepath.ToSlash(s)
	}
	files := map[string]interface{}{"files": m}
	return files, err
}


text:
package bsh;

import java.util.Stack;
import java.io.Serializable;
import java.util.EmptyStackException;

/**
    A stack of NameSpaces representing the call path.
    Each method invocation, for example, pushes a new NameSpace onto the stack.
    The top of the stack is always the current namespace of evaluation.

    This is used to support the this.caller magic reference and to print
    script "stack traces" when evaluation errors occur.

    Note: How can this be thread safe, you might ask?  Wouldn't a thread
    executing various beanshell methods be mutating the callstack?  Don't we
    need one CallStack per Thread in the interpreter?  The answer is that we do.
    Any java.lang.Thread enters our script via an external (hard) Java
    reference via a This type interface, e.g.  the Runnable interface
    implemented by This or an arbitrary interface implemented by XThis.
    In that case the This invokeMethod() method (called by any interface that
    it exposes) creates a new CallStack for each external call.

*/
public final class CallStack implements Serializable {
    /** default serial version id */
    private static final long serialVersionUID = 1L;
    private final Stack<NameSpace> stack = new Stack<>();

    public CallStack() { }

    public CallStack( NameSpace namespace ) {
        push( namespace );
    }

    public void clear() {
        stack.clear();
    }

    public void push( NameSpace ns ) {
        stack.push( ns );
    }

    public NameSpace top() {
        return stack.peek();
    }

    /**
        zero based.
    */
    public NameSpace get(int depth) {
        int size = stack.size();
        if ( depth >= size )
            return NameSpace.JAVACODE;
        return stack.toArray(new NameSpace[size])[size-1-depth];
    }

    /**
        This is kind of crazy, but used by the setNameSpace command.
        zero based.
    */
    public synchronized void set(int depth, NameSpace ns) {
        stack.set( stack.size()-1-depth, ns );
    }

    public NameSpace pop() {
        try {
            return stack.pop();
        } catch(EmptyStackException e) {
            throw new InterpreterError("pop on empty CallStack");
        }
    }

    /**
        Swap in the value as the new top of the stack and return the old
        value.
    */
    public NameSpace swap( NameSpace newTop ) {
        NameSpace oldTop = stack.pop();
        stack.push(newTop);
        return oldTop;
    }

    public int depth() {
        return stack.size();
    }
/*
    public NameSpace [] toArray() {
        NameSpace [] nsa = new NameSpace [ depth() ];
        stack.copyInto( nsa );
        return nsa;
    }
*/
    public synchronized String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("CallStack:\n");
        for( int i=stack.size()-1; i>=0; i-- )
            sb.append("\t"+stack.get(i)+"\n");

        return sb.toString();
    }

    /**
        Occasionally we need to freeze the callstack for error reporting
        purposes, etc.
    */
    public CallStack copy() {
        CallStack cs = new CallStack();
        cs.stack.addAll(this.stack);
        return cs;
    }
}


text:
using System;

namespace Mono.Addins
{
	/// <summary>
	/// An IProgressStatus class which writes output to the console.
	/// </summary>
#if NETFRAMEWORK
	public class ConsoleProgressStatus: MarshalByRefObject, IProgressStatus
#else
	public class ConsoleProgressStatus : IProgressStatus
#endif
	{
		bool canceled;
		int logLevel;

		/// <summary>
		/// Initializes a new instance
		/// </summary>
		/// <param name="verboseLog">
		/// Set to true to enabled verbose log
		/// </param>
		public ConsoleProgressStatus (bool verboseLog)
		{
			if (verboseLog)
				logLevel = 2;
			else
				logLevel = 1;
		}

		/// <summary>
		/// Initializes a new instance
		/// </summary>
		/// <param name="logLevel">
		/// Verbosity level. 0: not verbose, 1: normal, >1 extra verbose
		/// </param>
		public ConsoleProgressStatus (int logLevel)
		{
			this.logLevel = logLevel;
		}

		/// <summary>
		/// Sets the description of the current operation.
		/// </summary>
		/// <param name="msg">
		/// A message
		/// </param>
		/// <remarks>
		/// This method is called by the add-in engine to show a description of the operation being monitorized.
		/// </remarks>
		public void SetMessage (string msg)
		{
		}

		/// <summary>
		/// Sets the progress of the operation.
		/// </summary>
		/// <param name="progress">
		/// A number between 0 and 1. 0 means no progress, 1 means operation completed.
		/// </param>
		/// <remarks>
		/// This method is called by the add-in engine to show the progress of the operation being monitorized.
		/// </remarks>
		public void SetProgress (double progress)
		{
		}

		/// <summary>
		/// Writes text to the log.
		/// </summary>
		/// <param name="msg">
		/// Message to write
		/// </param>
		public void Log (string msg)
		{
			Console.WriteLine (msg);
		}

		/// <summary>
		/// Reports a warning.
		/// </summary>
		/// <param name="message">
		/// Warning message
		/// </param>
		/// <remarks>
		/// This method is called by the add-in engine to report a warning in the operation being monitorized.
		/// </remarks>
		public void ReportWarning (string message)
		{
			if (logLevel > 0)
				Console.WriteLine ("WARNING: " + message);
		}

		/// <summary>
		/// Reports an error.
		/// </summary>
		/// <param name="message">
		/// Error message
		/// </param>
		/// <param name="exception">
		/// Exception that caused the error. It can be null.
		/// </param>
		/// <remarks>
		/// This method is called by the add-in engine to report an error occurred while executing the operation being monitorized.
		/// </remarks>
		public void ReportError (string message, Exception exception)
		{
			if (logLevel == 0)
				return;
			Console.Write ("ERROR: ");
			if (logLevel > 1) {
				if (message != null)
					Console.WriteLine (message);
				if (exception != null)
					Console.WriteLine (exception);
			} else {
				if (message != null && exception != null)
					Console.WriteLine (message + " (" + exception.Message + ")");
				else {
					if (message != null)
						Console.WriteLine (message);
					if (exception != null)
						Console.WriteLine (exception.Message);
				}
			}
		}

		/// <summary>
		/// Returns True when the user requested to cancel this operation
		/// </summary>
		public bool IsCanceled {
			get { return canceled; }
		}

		/// <summary>
		/// Log level requested by the user: 0: no log, 1: normal log, >1 verbose log
		/// </summary>
		public int LogLevel {
			get { return logLevel; }
		}

		/// <summary>
		/// Cancels the operation being montorized.
		/// </summary>
		public void Cancel ()
		{
			canceled = true;
		}
	}
}


text:
namespace courgette {

class AssemblyProgram;
class InstructionReceptor;

class DisassemblerElf32X86 : public DisassemblerElf32 {
 public:
  // Returns true if a valid executable is detected using only quick checks.
  static bool QuickDetect(const uint8_t* start, size_t length) {
    return DisassemblerElf32::QuickDetect(start, length, EM_386);
  }

  class TypedRVAX86 : public TypedRVA {
   public:
    explicit TypedRVAX86(RVA rva) : TypedRVA(rva) { }
    ~TypedRVAX86() override { }

    // TypedRVA interfaces.
    CheckBool ComputeRelativeTarget(const uint8_t* op_pointer) override;
    CheckBool EmitInstruction(Label* label,
                              InstructionReceptor* receptor) override;
    uint16_t op_size() const override;
  };

  DisassemblerElf32X86(const uint8_t* start, size_t length);

  ~DisassemblerElf32X86() override { }

  // DisassemblerElf32 interfaces.
  ExecutableType kind() const override { return EXE_ELF_32_X86; }
  e_machine_values ElfEM() const override { return EM_386; }

 protected:
  // DisassemblerElf32 interfaces.
  CheckBool RelToRVA(Elf32_Rel rel,
                     RVA* result) const override WARN_UNUSED_RESULT;
  CheckBool ParseRelocationSection(const Elf32_Shdr* section_header,
                                   InstructionReceptor* receptor) const override
      WARN_UNUSED_RESULT;
  CheckBool ParseRel32RelocsFromSection(const Elf32_Shdr* section)
      override WARN_UNUSED_RESULT;

#if COURGETTE_HISTOGRAM_TARGETS
  std::map<RVA, int> rel32_target_rvas_;
#endif

 private:
  DISALLOW_COPY_AND_ASSIGN(DisassemblerElf32X86);
};

}  // namespace courgette

#endif  // COURGETTE_DISASSEMBLER_ELF_32_X86_H_