<commit_before>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.plugin.mailsender;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.localization.LocaleUtils;
import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.velocity.VelocityManager;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Api;
import com.xpn.xwiki.api.Attachment;
import com.xpn.xwiki.api.Document;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.web.ExternalServletURLFactory;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiURLFactory;

/**
 * Plugin that brings powerful mailing capabilities.
 * 
 * @see MailSender
 * @version $Id$
 */
public class MailSenderPlugin extends XWikiDefaultPlugin
{
    /** Logging helper object. */
    private static final Logger LOGGER = LoggerFactory.getLogger(MailSenderPlugin.class);

    /**
     * Since Java uses full Unicode Strings and email clients manage it we force email encoding to UTF-8. XWiki encoding
     * must be used when working with storage or the container since they can be configured to use another encoding,
     * this constraint does not apply here.
     */
    private static final String EMAIL_ENCODING = "UTF-8";

    /**
     * Error code signaling that the mail template requested for
     * {@link #sendMailFromTemplate(String, String, String, String, String, String, VelocityContext, XWikiContext)} was
     * not found.
     */
    public static int ERROR_TEMPLATE_EMAIL_OBJECT_NOT_FOUND = -2;

    /** Generic error code for plugin failures. */
    public static int ERROR = -1;

    /** The name of the Object Type holding mail templates. */
    public static final String EMAIL_XWIKI_CLASS_NAME = "XWiki.Mail";

    /** The name of the plugin, used for accessing it from scripting environments. */
    public static final String ID = "mailsender";

    protected static final String URL_SEPARATOR = "/";

    /** A pattern for determining if a line represents a SMTP header, conforming to RFC 2822. */
    private static final Pattern SMTP_HEADER = Pattern.compile("^([\\x21-\\x7E&&[^\\x3A]]++):(.*+)$");

    /** The name of the header that specifies the subject of the mail. */
    private static final String SUBJECT = "Subject";

    /** The name of the header that specifies the sender of the mail. */
    private static final String FROM = "From";

    /**
     * Default plugin constructor.
     * 
     * @see XWikiDefaultPlugin#XWikiDefaultPlugin(String,String,com.xpn.xwiki.XWikiContext)
     */
    public MailSenderPlugin(String name, String className, XWikiContext context)
    {
        super(name, className, context);
    }

    @Override
    public void init(XWikiContext context)
    {
        try {
            initMailClass(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void virtualInit(XWikiContext context)
    {
        try {
            initMailClass(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getName()
    {
        return ID;
    }

    @Override
    public Api getPluginApi(XWikiPluginInterface plugin, XWikiContext context)
    {
        return new MailSenderPluginApi((MailSenderPlugin) plugin, context);
    }

    /**
     * Split comma separated list of emails
     * 
     * @param email comma separated list of emails
     * @return An array containing the emails
     */
    public static String[] parseAddresses(String email)
    {
        if (email == null) {
            return null;
        }
        email = email.trim();
        String[] emails = email.split(",");
        for (int i = 0; i < emails.length; i++) {
            emails[i] = emails[i].trim();
        }
        return emails;
    }

    /**
     * Filters a list of emails : removes illegal addresses
     * 
     * @param email List of emails
     * @return An Array containing the correct adresses
     */
    private static InternetAddress[] toInternetAddresses(String email) throws AddressException
    {
        String[] mails = parseAddresses(email);
        if (mails == null) {
            return null;
        }

        InternetAddress[] address = new InternetAddress[mails.length];
        for (int i = 0; i < mails.length; i++) {
            address[i] = new InternetAddress(mails[i]);
        }
        return address;
    }

    /**
     * Creates the Mail XWiki Class
     * 
     * @param context Context of the request
     * @return the Mail XWiki Class
     */
    protected BaseClass initMailClass(XWikiContext context) throws XWikiException
    {
        XWikiDocument doc;
        XWiki xwiki = context.getWiki();
        boolean needsUpdate = false;

        try {
            doc = xwiki.getDocument(EMAIL_XWIKI_CLASS_NAME, context);
        } catch (Exception e) {
            doc = new XWikiDocument();
            String[] spaceAndName = EMAIL_XWIKI_CLASS_NAME.split(".");
            doc.setSpace(spaceAndName[0]);
            doc.setName(spaceAndName[1]);
            needsUpdate = true;
        }

        BaseClass bclass = doc.getXClass();
        bclass.setName(EMAIL_XWIKI_CLASS_NAME);
        needsUpdate |= bclass.addTextField("subject", "Subject", 40);
        needsUpdate |= bclass.addTextField("language", "Language", 5);
        needsUpdate |= bclass.addTextAreaField("text", "Text", 80, 15);
        needsUpdate |= bclass.addTextAreaField("html", "HTML", 80, 15);<commit_msg>XWIKI-13661: XWiki.Mail xclass textarea properties must be of type puretext * Also need to fix the old mailsender plugin as otherwise it overwrites the other initializer's changes...<commit_after>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.plugin.mailsender;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.localization.LocaleUtils;
import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.velocity.VelocityManager;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Api;
import com.xpn.xwiki.api.Attachment;
import com.xpn.xwiki.api.Document;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.objects.classes.TextAreaClass;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.web.ExternalServletURLFactory;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiURLFactory;

/**
 * Plugin that brings powerful mailing capabilities.
 * 
 * @see MailSender
 * @version $Id$
 */
public class MailSenderPlugin extends XWikiDefaultPlugin
{
    /** Logging helper object. */
    private static final Logger LOGGER = LoggerFactory.getLogger(MailSenderPlugin.class);

    /**
     * Since Java uses full Unicode Strings and email clients manage it we force email encoding to UTF-8. XWiki encoding
     * must be used when working with storage or the container since they can be configured to use another encoding,
     * this constraint does not apply here.
     */
    private static final String EMAIL_ENCODING = "UTF-8";

    /**
     * Error code signaling that the mail template requested for
     * {@link #sendMailFromTemplate(String, String, String, String, String, String, VelocityContext, XWikiContext)} was
     * not found.
     */
    public static int ERROR_TEMPLATE_EMAIL_OBJECT_NOT_FOUND = -2;

    /** Generic error code for plugin failures. */
    public static int ERROR = -1;

    /** The name of the Object Type holding mail templates. */
    public static final String EMAIL_XWIKI_CLASS_NAME = "XWiki.Mail";

    /** The name of the plugin, used for accessing it from scripting environments. */
    public static final String ID = "mailsender";

    protected static final String URL_SEPARATOR = "/";

    /** A pattern for determining if a line represents a SMTP header, conforming to RFC 2822. */
    private static final Pattern SMTP_HEADER = Pattern.compile("^([\\x21-\\x7E&&[^\\x3A]]++):(.*+)$");

    /** The name of the header that specifies the subject of the mail. */
    private static final String SUBJECT = "Subject";

    /** The name of the header that specifies the sender of the mail. */
    private static final String FROM = "From";

    /**
     * Default plugin constructor.
     * 
     * @see XWikiDefaultPlugin#XWikiDefaultPlugin(String,String,com.xpn.xwiki.XWikiContext)
     */
    public MailSenderPlugin(String name, String className, XWikiContext context)
    {
        super(name, className, context);
    }

    @Override
    public void init(XWikiContext context)
    {
        try {
            initMailClass(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void virtualInit(XWikiContext context)
    {
        try {
            initMailClass(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getName()
    {
        return ID;
    }

    @Override
    public Api getPluginApi(XWikiPluginInterface plugin, XWikiContext context)
    {
        return new MailSenderPluginApi((MailSenderPlugin) plugin, context);
    }

    /**
     * Split comma separated list of emails
     * 
     * @param email comma separated list of emails
     * @return An array containing the emails
     */
    public static String[] parseAddresses(String email)
    {
        if (email == null) {
            return null;
        }
        email = email.trim();
        String[] emails = email.split(",");
        for (int i = 0; i < emails.length; i++) {
            emails[i] = emails[i].trim();
        }
        return emails;
    }

    /**
     * Filters a list of emails : removes illegal addresses
     * 
     * @param email List of emails
     * @return An Array containing the correct adresses
     */
    private static InternetAddress[] toInternetAddresses(String email) throws AddressException
    {
        String[] mails = parseAddresses(email);
        if (mails == null) {
            return null;
        }

        InternetAddress[] address = new InternetAddress[mails.length];
        for (int i = 0; i < mails.length; i++) {
            address[i] = new InternetAddress(mails[i]);
        }
        return address;
    }

    /**
     * Creates the Mail XWiki Class
     * 
     * @param context Context of the request
     * @return the Mail XWiki Class
     */
    protected BaseClass initMailClass(XWikiContext context) throws XWikiException
    {
        XWikiDocument doc;
        XWiki xwiki = context.getWiki();
        boolean needsUpdate = false;

        try {
            doc = xwiki.getDocument(EMAIL_XWIKI_CLASS_NAME, context);
        } catch (Exception e) {
            doc = new XWikiDocument();
            String[] spaceAndName = EMAIL_XWIKI_CLASS_NAME.split(".");
            doc.setSpace(spaceAndName[0]);
            doc.setName(spaceAndName[1]);
            needsUpdate = true;
        }

        BaseClass bclass = doc.getXClass();
        bclass.setName(EMAIL_XWIKI_CLASS_NAME);
        needsUpdate |= bclass.addTextField("subject", "Subject", 40);
        needsUpdate |= bclass.addTextField("language", "Language", 5);
        needsUpdate |= bclass.addTextAreaField("text", "Text", 80, 15, TextAreaClass.EditorType.PURE_TEXT);
        needsUpdate |= bclass.addTextAreaField("html", "HTML", 80, 15, TextAreaClass.EditorType.PURE_TEXT);
{'fraction_non_alphanumeric': 0.09641269642521755, 'fraction_numerical': 0.005697113879671947, 'mean_word_length': 3.132988357050453, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6653661', 'n_tokens_mistral': 4678, 'n_tokens_neox': 4523, 'n_words': 1380}