<?php
/**
* This file sends an email to the user!
* It's used to handle the contact form send message action. Even visitors are able to send emails.
*
* It's the form action for {@link _msgform.disp.php}.
*
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link https://github.com/b2evolution/b2evolution}.
*
* @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
*
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
* Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
*
* @package htsrv
*
* @author Jeff Bearer - {@link http://www.jeffbearer.com/} + blueyed, fplanque
*
* @todo dh> we should use the current_User's ID, if he's logged in here. It seems that only the message form gets pre-filled with hidden fields currently.
*/
/**
* Includes
*/
require_once dirname(__FILE__).'/../conf/_config.php';
require_once $inc_path.'_main.inc.php';
// Stop a request from the blocked IP addresses or Domains
antispam_block_request();
global $Session, $Settings, $admin_url, $baseurl, $dummy_fields;
header( 'Content-Type: text/html; charset='.$io_charset );
// Check that this action request is not a CSRF hacked request:
$Session->assert_received_crumb( 'newmessage' );
if( $Settings->get('system_lock') )
{ // System is locked for maintenance, users cannot send a message
$Messages->add( T_('You cannot send a message at this time because the system is under maintenance. Please try again in a few moments.'), 'error' );
header_redirect(); // Will save $Messages into Session
}
// TODO: Flood protection (Use Hit class to prevent mass mailings to members..)
// Get rediredt_to param
$redirect_to = param( 'redirect_to', 'url', '' );
// Getting GET or POST parameters:
param( 'blog', 'integer', '' );
param( 'recipient_id', 'integer', '' );
param( 'post_id', 'integer', '' );
param( 'comment_id', 'integer', '' );
// Activate the blog locale because all params were introduced with that locale
activate_blog_locale( $blog );
// Note: we use funky field names in order to defeat the most basic guestbook spam bots:
$sender_name = param( $dummy_fields['name'], 'string', '' );
$sender_address = utf8_strtolower( param( $dummy_fields['email'], 'string', '' ) );
$subject = param( $dummy_fields['subject'], 'string', '' );
$subject_other = param( $dummy_fields['subject'].'_other', 'string', '' );
$message = param( $dummy_fields['content'], 'html', '' ); // We accept html but we will NEVER display it
$contact_method = param( 'contact_method', 'string', '' );
$user_fields = param( 'user_fields', 'array', array() );
// save the message original content
$original_content = $message;
// Prevent register_globals injection!
$recipient_address = '';
$recipient_name = '';
$recipient_User = NULL;
$Comment = NULL;
// Getting current collection:
$BlogCache = & get_BlogCache();
if( ! empty( $comment_id ) || ! empty( $post_id ) )
{
$Collection = $Blog = & $BlogCache->get_by_ID( $blog ); // Required
}
else
{
$Collection = $Blog = & $BlogCache->get_by_ID( $blog, true, false ); // Optional
}
// Core param validation
if( $Blog->get_setting( 'msgform_display_subject' ) &&
$Blog->get_setting( 'msgform_require_subject' ) &&
empty( $subject ) &&
empty( $subject_other ) )
{ // If subject is required:
$Messages->add_to_group( T_('Please fill in the subject of your message.'), 'error', T_('Validation errors:') );
}
if( $Blog->get_setting( 'msgform_display_message' ) )
{ // If message field is displayed:
if( $Blog->get_setting( 'msgform_require_message' ) && empty( $message ) )
{ // If message is required:
$Messages->add_to_group( T_('Please do not send empty messages.'), 'error', T_('Validation errors:') );
}
elseif( $Settings->get( 'antispam_block_contact_form' ) && ( $block = antispam_check( $message ) ) )
{ // a blacklisted keyword has been found in the message:
// Log incident in system log
syslog_insert( sprintf( 'Antispam: Supplied message is invalid / appears to be spam. Message contains blacklisted word "%s".', $block ), 'error' );
$Messages->add_to_group( T_('The supplied message is invalid / appears to be spam.'), 'error', T_('Validation errors:') );
}
}
if( ! empty( $recipient_id ) )
{ // Get the recipient User by requested ID:
$UserCache = & get_UserCache();
$recipient_User = & $UserCache->get_by_ID( $recipient_id );
}
elseif( ! empty( $comment_id ) )
{ // Get the recipient data to send a message to comment's author:
$CommentCache = & get_CommentCache();
if( ! ( $Comment = & $CommentCache->get_by_ID( $comment_id, false, false ) ) )
{ // The requested comment must exists in DB:
debug_die( 'Invalid request for message sending because comment #'.$comment_id.' doesn\'t exists in DB!' );
}
// Get recipient User if it is a registered user:
$recipient_User = & $Comment->get_author_User();
if( empty( $recipient_User ) )
{ // If comment's author is anonymous user:
if( empty( $Comment->allow_msgform ) )
{ // If anonymous user didn't allow to send email messages:
debug_die( 'Author of the comment #'.$comment_id.' does not want to get contacted through the message form!' );
}
// Get the recipient data of the comment's author:
$recipient_name = $Comment->get_author_name();
$recipient_address = $Comment->get_author_email();
}
}
$update_user_fields = false;
if( is_logged_in() )
{ // Set name and email of the current logged in user:
$sender_name = '';
$sender_address = $current_User->get( 'email' );
$edited_user_perms = array( 'edited-user', 'edited-user-required' );
switch( $Blog->get_setting( 'msgform_user_name' ) )
{
case 'fullname':
$firstname_editing = $Settings->get( 'firstname_editing' );
if( in_array( $firstname_editing, $edited_user_perms ) )
{ // Get first name:
$user_firstname = param( 'user_firstname', 'string', '' );
if( $firstname_editing == 'edited-user-required' && empty( $user_firstname ) )
{ // First name is required:
param_error( 'user_firstname', T_('Please enter your first name.'), NULL, T_('Validation errors:') );
}
$sender_name .= $user_firstname;
if( ! empty( $user_firstname ) && $user_firstname != $current_User->get( 'firstname' ) )
{ // Set new first name if it has been entered as new:
$current_User->set( 'firstname', $user_firstname );
$update_user_fields = true;
}
}
$lastname_editing = $Settings->get( 'lastname_editing' );
if( in_array( $lastname_editing, $edited_user_perms ) )
{ // Get last name:
$user_lastname = param( 'user_lastname', 'string', '' );
if( $lastname_editing == 'edited-user-required' && empty( $user_lastname ) )
{ // Lsst name is required:
param_error( 'user_lastname', T_('Please enter your last name.'), NULL, T_('Validation errors:') );
}
$sender_name .= ' '.$user_lastname;
if( ! empty( $user_lastname ) && $user_lastname != $current_User->get( 'lastname' ) )
{ // Set new last name if it has been entered as new:
$current_User->set( 'lastname', $user_lastname );
$update_user_fields = true;
}
}
$sender_name = utf8_trim( $sender_name );
break;
case 'nickname':
$nickname_editing = $Settings->get( 'nickname_editing' );
if( in_array( $nickname_editing, $edited_user_perms ) )
{ // Get nickname:
$user_nickname = param( 'user_nickname', 'string', '' );
if( $nickname_editing == 'edited-user-required' && empty( $user_nickname ) )
{ // Nickname is required:
param_error( 'user_nickname', T_('Please enter your nickname.'), NULL, T_('Validation errors:') );
}
$sender_name .= $user_nickname;
if( ! empty( $user_nickname ) && $user_nickname != $current_User->get( 'nickname' ) )
{ // Set new nickname if it has been entered as new:
$current_User->set( 'nickname', $user_nickname );
$update_user_fields = true;
}
}
break;
}
if( empty( $sender_name ) )
{ // If sender name has not been detected from first/last/nickname fields then use preferred name of current User:
$sender_name = $current_User->get_username();
}
}
else
{ // Ask name and email only for anonymous users:
if( $Blog->get_setting( 'msgform_require_name' ) && empty( $sender_name ) )
{ // If name is required:
$Messages->add_to_group( T_('Please fill in your name.'), 'error', T_('Validation errors:') );
}
if( empty( $sender_address ) )
{
$Messages->add_to_group( T_('Please fill in your email.'), 'error', T_('Validation errors:') );
}
elseif( ! is_email( $sender_address ) || ( $block = antispam_check( $sender_address ) ) ) // TODO: dh> using antispam_check() here might not allow valid users to contact the admin in case of problems due to the antispam list itself.. :/
{
// Log incident in system log
syslog_insert( sprintf( 'Antispam: Supplied email address "%s" contains blacklisted word "%s".', $sender_address, $block ), 'error' );
$Messages->add_to_group( T_('Supplied email address is invalid.'), 'error', T_('Validation errors:') );
}
}
if( empty( $recipient_User ) && empty( $recipient_address ) )
{ // should be prevented by UI
debug_die( 'No recipient specified!' );
}
// Additional fields:
$send_additional_fields = array();
if( is_array( $user_fields ) && ! empty( $user_fields ) )
{
$UserFieldCache = & get_UserFieldCache();
$coll_additional_fields = $Blog->get_msgform_additional_fields();
foreach( $user_fields as $user_field_ID => $user_field_value )
{
if( ! isset( $coll_additional_fields[ $user_field_ID ] ) )
{ // Skip wrong field which is not selected for current collection as additional field:
continue;
}
if( ! ( $UserField = & $UserFieldCache->get_by_ID( $user_field_ID, false, false ) ) )
{ // Skip wrong field:
continue;
}
if( ! is_array( $user_field_value ) )
{
$user_field_value = array( $user_field_value );
}
$text_value = array();
foreach( $user_field_value as $text_val )
{
$text_val = utf8_trim( $text_val );
if( ! empty( $text_val ) )
{
$text_value[] = $text_val;
}
}
$text_value = implode( ', ', $text_value );
if( empty( $text_value ) )
{ // Skip empty values:
continue;
}
if( is_logged_in() )
{ // Update user fields of the logged in User:
$userfields = $current_User->userfields_by_ID( $UserField->ID );
foreach( $user_field_value as $u => $uf_value )
{
if( empty( $uf_value ) )
{ // Skip empty entered values from contact form:
continue;
}
// Format and check the entered value:
$field_type = $UserField->get( 'type' );
if( $field_type == 'number' )
{ // Change number type of integer because we have this type name preparing in function param_format():
$field_type = 'integer';
}
elseif( $field_type != 'text' && $field_type != 'url' )
{ // Use all other params as string, Only text and url have a preparing in function param_format():
$field_type = 'string';
}
$uf_value = param_format( $uf_value, $field_type );
if( $field_type == 'url' && ( $error_detail = validate_url( $uf_value, 'commenting' ) ) )
{ // Skip it if the entered URL is wrong:
$Messages->add_to_group( /* TRANS: %s contains error details */ sprintf( T_('Supplied URL is invalid. (%s)'), $error_detail ), 'error', T_('Validation errors:') );
continue;
}
if( $userfields === false )
{ // Add new field value:
$current_User->userfield_add( $UserField->ID, $uf_value );
$update_user_fields = true;
}
else
{ // Update existing field value:
$add_multifield_value = false;
foreach( $userfields as $m => $userfield_data )
{
if( ! empty( $userfield_data->list ) )
{ // Update a list field:
$s = 0;
foreach( $userfield_data->list as $saved_uf_ID => $saved_uf_value )
{
if( $s == $u && $uf_value != $saved_uf_value )
{ // Only if it was changed:
$current_User->userfield_update( $saved_uf_ID, $user_field_value[ $s ] );
$update_user_fields = true;
}
$s++;
}
// If count of entered values is more than count of saved values in DB:
$add_multifield_value = ( count( $user_field_value ) > count( $userfield_data->list ) );
}
elseif( $m == $u && $uf_value != $userfield_data->uf_varchar )
{ // Update a single field only if it was changed:
$current_User->userfield_update( $userfield_data->uf_ID, $uf_value );
$update_user_fields = true;
}
if( $add_multifield_value && $u > $m && $u < 2 )
{ // It means second value of multiple field should be added:
$current_User->userfield_add( $UserField->ID, $uf_value );
$update_user_fields = true;
}
}
}
}
}
// Prepare user field for correct html displaying:
$userfield = (object)array(
'ufdf_type' => $UserField->get( 'type' ),
'uf_varchar' => $text_value,
);
userfield_prepare( $userfield );
if( is_pro() )
{ // Format user field value by PRO function:
load_funcs( '_core/_pro_features.funcs.php' );
$html_value = pro_get_user_field_value( $userfield );
$text_value = strip_tags( $html_value );
}
else
{ // Display normal value:
$html_value = $userfield->uf_varchar;
}
$send_additional_fields[] = array(
'title' => $UserField->get( 'name' ),
'text_value' => $text_value,
'html_value' => $html_value,
);
}
}
if( $update_user_fields )
{ // If at least one field of current user must be updated:
$current_User->dbupdate();
}
if( intval( $contact_method ) > 0 )
{ // If preferred contact method is selected as user field:
$UserFieldCache = & get_UserFieldCache();
$msgform_additional_fields = $Blog->get_msgform_additional_fields();
if( isset( $msgform_additional_fields[ $contact_method ] ) &&
$UserField = & $UserFieldCache->get_by_ID( $contact_method, false, false ) )
{
$contact_method_field_is_filled = false;
if( isset( $user_fields[ $contact_method ] ) )
{ // Check the entered field for preferred contact method:
$entered_user_field = $user_fields[ $contact_method ];
$entered_user_field = trim( is_array( $entered_user_field ) ? implode( '', $entered_user_field ) : $entered_user_field );
if( ! empty( $entered_user_field ) )
{ // Allow to use the selected field for preferred contact method because it has been entered:
$contact_method_field_is_filled = true;
}
}
if( ! $contact_method_field_is_filled )
{ // If the selected contact method field is not filled:
$Messages->add_to_group( sprintf( T_('Please fill the field "%s" because you have selected this as preferred contact method.'), $UserField->get_name() ),'error', T_('Validation errors:') );
}
}
else
{ // If the selected contact method is not used as additional field or it doesn't exist in DB:
$Messages->add_to_group( /* NO TRANS because should never happen */ 'You have selected an unavailable preferred contact method.', 'error', T_('Validation errors:') );
}
}
// opt-out links:
if( $recipient_User )
{ // Member:
// Change the locale so the email is in the recipients language
locale_temp_switch( $recipient_User->locale );
}
else
{ // Visitor:
// We don't know the recipient's language - Change the locale so the email is in the blog's language:
locale_temp_switch( $Blog->locale );
}
// Trigger event: a Plugin could add a $category="error" message here..
$Plugins->trigger_event( 'MessageFormSent', array(
'recipient_ID' => $recipient_id,
'item_ID' => $post_id,
'comment_ID' => $comment_id,
'subject' => & $subject,
'message' => & $message,
'Blog' => & $Blog,
'sender_name' => & $sender_name,
'sender_email' => & $sender_address,
) );
// Validate first enabled captcha plugin:
$Plugins->trigger_event_first_return( 'ValidateCaptcha', array( 'form_type' => 'message' ) );
$success_message = ( !$Messages->has_errors() );
if( $success_message )
{ // No errors, try to send the message:
$send_subject = ( empty( $subject_other ) ? $subject : $subject_other );
$send_contact_method = $contact_method;
if( ! empty( $send_contact_method ) )
{ // If a preferred contact method is selected of the form:
if( $send_contact_method === 'pm' && is_logged_in() &&
$current_User->get_msgform_possibility( $recipient_User, 'PM' ) )
{ // PM option only if it is allowed between current and recipient users:
$send_contact_method = T_('Private Message on this Site');
}
elseif( $send_contact_method === 'email' )
{ // Email option:
$send_contact_method = T_('Email');
if( is_logged_in() )
{ // Display an email of current user:
$send_contact_method .= ' ('.$current_User->get( 'email' ).')';
}
}
elseif( intval( $send_contact_method ) > 0 )
{ // User field option:
$UserFieldCache = & get_UserFieldCache();
if( $UserField = & $UserFieldCache->get_by_ID( $send_contact_method, false, false ) )
{ // Get real name of the selected user field:
$send_contact_method = $UserField->get( 'name' );
if( is_logged_in() )
{ // Display a value of the selected contact method of current user:
$user_field_values = $current_User->userfield_values_by_code( $UserField->get( 'code' ) );
if( ! empty( $user_field_values ) )
{ // Only if it is entered by user:
$send_contact_method .= ' ('.implode( ', ', $user_field_values ).')';
}
}
}
else
{ // Wrong user field:
$send_contact_method = '';
}
}
}
$send_method_type = 'email';
// Check if sender and recipient can use private message instead of email:
if( $recipient_User && // recipient is a registered user
$recipient_User->get_msgform_possibility() == 'PM' && // recipient allows to send PM
! check_create_thread_limit() ) // sender can create a thread today
{
$send_method_type = 'PM';
}
if( $send_method_type == 'PM' )
{ // Send private message:
load_class( 'messaging/model/_thread.class.php', 'Thread' );
load_class( 'messaging/model/_message.class.php', 'Message' );
$send_message = array();
if( ! empty( $send_additional_fields ) )
{ // Append all filled additonal fields:
$send_message[0] = array();
foreach( $send_additional_fields as $send_additional_field )
{
$send_message[0][] = $send_additional_field['title'].': '.$send_additional_field['text_value'];
}
$send_message[0] = implode( "\n\n", $send_message[0] );
}
if( ! empty( $send_contact_method ) )
{ // Append a preferred contact method to the message text:
$send_message[1] = T_('Reply method').': '.$send_contact_method;
}
if( ! empty( $message ) )
{ // Append message text:
$send_message[2] = $message;
}
$send_message = implode( "\n\n---\n\n", $send_message );
$edited_Thread = new Thread();
$edited_Message = new Message();
$edited_Thread->set( 'title', $send_subject );
$edited_Thread->set( 'recipients', $current_User->ID.','.$recipient_User->ID );
$edited_Thread->recipients_list = array( $recipient_User->ID );
$edited_Message->Thread = & $edited_Thread;
$edited_Message->set( 'text', $send_message );
if( $edited_Message->dbinsert_discussion() )
{ // Successful creating of new thread:
$success_message = true;
// update author user last new thread setting
update_todays_thread_settings( 1 );
}
else
{ // Failed
$success_message = false;
}
}
if( $send_method_type == 'email' ||
( $send_method_type == 'PM' && ! $success_message ) )
{ // Send email message:
$send_method_type = 'email';
$email_template_params = array(
'sender_name' => $sender_name,
'sender_address' => $sender_address,
'Blog' => $Blog,
'message' => $message,
'contact_method' => $send_contact_method,
'additional_fields' => $send_additional_fields,
'comment_ID' => $comment_id,
'post_id' => $post_id,
'recipient_User' => $recipient_User,
'Comment' => $Comment,
);
$email_headers = array();
if( ! is_logged_in() )
{ // Allow to reply only to anonymous user:
$email_headers['Reply-To'] = $sender_address;
}
if( empty( $recipient_User ) )
{ // Send email to visitor/anonymous:
// Get a message text from template file
$email_template_params['anonymous_recipient_name'] = $recipient_name;
$message = mail_template( 'contact_message_new', 'text', $email_template_params );
$success_message = send_mail( $recipient_address, $recipient_name, $send_subject, $message, NULL, NULL, $email_headers );
}
else
{ // Send mail to registered user:
$success_message = send_mail_to_User( $recipient_User->ID, $send_subject, 'contact_message_new', $email_template_params, false, $email_headers );
}
}
// restore the locale to the blog visitor language, before we would display an error message
locale_restore_previous();
if( $success_message )
{ // Email has been sent successfully
if( ! is_logged_in() )
{ // We should save a counter (only for anonymous users)
antispam_increase_counter( 'contact_email' );
}
}
else
{ // Could not send email
if( $demo_mode )
{
$Messages->add( 'Sorry, could not send email. Sending email in demo mode is disabled.', 'error' );
}
else
{
$Messages->add( T_('Sorry, could not send email.')
.'<br />'.get_send_mail_error(), 'error' );
}
}
}
else
{ // Restore the locale to the blog visitor language even in case of errors
locale_restore_previous();
}
// Plugins should cleanup their temporary data here:
$Plugins->trigger_event( 'MessageFormSentCleanup', array(
'success_message' => $success_message,
) );
if( empty( $redirect_to ) && empty( $Blog ) )
{
$redirect_to = $baseurl;
}
if( $success_message )
{
if( $send_method_type == 'PM' )
{ // If PM has been sent:
$Messages->add( T_('Your private message has been sent.'), 'success' );
}
else
{ // If EMAIL has been sent:
$Messages->add( sprintf( T_('You have successfully sent an email to %s.'),
( empty( $recipient_User ) ? $recipient_name : $recipient_User->get_username() ) ), 'success' );
}
if( isset( $recipient_User, $Blog ) &&
$Blog->get_owner_User() &&
$recipient_User->ID == $Blog->get_owner_User()->ID )
{ // Message was sent to collection owner:
$ItemCache = & get_ItemCache();
if( $redirect_Item = & $ItemCache->get_by_urltitle( $Blog->get_setting( 'msgform_redirect_slug' ), false, false ) )
{ // Use item permanent URL from collection setting:
$redirect_to = $redirect_Item->get_permanent_url( '', '', '&' );
}
else
{ // Use collection home page URL:
$redirect_to = $Blog->gen_blogurl();
}
}
elseif( empty( $redirect_to ) )
{
$redirect_to = $Blog->gen_blogurl();
if( !empty( $recipient_User ) )
{
$redirect_to = url_add_param( $redirect_to, 'disp=msgform&recipient_id='.$recipient_User->ID );
}
}
header_redirect( $redirect_to );
// exited here
}
// unsuccessful message send, save message params into the Session to not lose the content
$unsaved_message_params = array();
$unsaved_message_params[ 'sender_name' ] = $sender_name;
$unsaved_message_params[ 'sender_address' ] = $sender_address;
$unsaved_message_params[ 'subject' ] = $subject;
$unsaved_message_params[ 'subject_other' ] = $subject_other;
$unsaved_message_params[ 'message' ] = $original_content;
$unsaved_message_params[ 'contact_method' ] = $contact_method;
$unsaved_message_params[ 'user_fields' ] = $user_fields;
save_message_params_to_session( $unsaved_message_params );
if( param_errors_detected() || empty( $redirect_to ) )
{
$redirect_to = url_add_param( $Blog->gen_blogurl(), 'disp=msgform&recipient_id='.$recipient_id, '&' );
}
header_redirect( $redirect_to );
//exited here
?>