Attached Files |
form_submissions_core.patch [^] (190,983 bytes) 2010-04-21 11:07
[Show Content]
Index: admin_templates/forms/form_edit_emails.tpl
===================================================================
--- admin_templates/forms/form_edit_emails.tpl (revision 0)
+++ admin_templates/forms/form_edit_emails.tpl (revision 0)
@@ -0,0 +1,105 @@
+<inp2:adm_SetPopupSize width="800" height="500"/>
+<inp2:m_include t="incs/header" />
+
+<inp2:m_RenderElement name="combined_header" section="in-portal:forms" prefix="form" title_preset="form_edit_emails" tab_preset="Default"/>
+
+<!-- ToolBar -->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+<tbody>
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+ a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
+ submit_event('form','<inp2:form_SaveEvent/>');
+ }
+ ) );
+ a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
+ submit_event('form','OnCancelEdit');
+ }
+ ) );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+ a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
+ go_to_id('form', '<inp2:form_PrevId/>');
+ }
+ ) );
+ a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
+ go_to_id('form', '<inp2:form_NextId/>');
+ }
+ ) );
+
+ //a_toolbar.AddButton( new ToolBarSeparator('sep2') );
+
+ a_toolbar.Render();
+
+ <inp2:m_if check="form_IsSingle" >
+ a_toolbar.HideButton('prev');
+ a_toolbar.HideButton('next');
+ a_toolbar.HideButton('sep1');
+ //a_toolbar.HideButton('sep2');
+ <inp2:m_else/>
+ <inp2:m_if check="form_IsLast" >
+ a_toolbar.DisableButton('next');
+ </inp2:m_if>
+ <inp2:m_if check="form_IsFirst" >
+ a_toolbar.DisableButton('prev');
+ </inp2:m_if>
+ </inp2:m_if>
+ </script>
+ </td>
+ </tr>
+</tbody>
+</table>
+
+<inp2:form_SaveWarning name="grid_save_warning"/>
+<inp2:form_ErrorWarning name="form_error_warning"/>
+
+<div id="scroll_container">
+ <table class="edit-form">
+ <inp2:m_RenderElement name="subsection" title="la_title_General"/>
+ <inp2:m_RenderElement name="inp_edit_checkbox" prefix="form" field="EnableEmailCommunication" title="la_fld_Enable" onclick="reflectFromFields();"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyFromName" title="la_fld_ReplyFromName"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyCc" title="la_fld_ReplyCc"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyBcc" title="la_fld_ReplyBcc"/>
+ <inp2:m_RenderElement name="inp_edit_textarea" prefix="form" field="ReplyMessageSignature" title="la_fld_ReplyMessageSignature"/>
+
+ <inp2:m_RenderElement name="subsection" title="la_title_ReplySettings"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyFromEmail" title="la_fld_ReplyFromEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyServer" title="la_fld_Server" hint_label="la_hint_PopServer"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyPort" title="la_fld_Port" hint_label="la_hint_PopPort"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyUsername" title="la_fld_Username"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyPassword" title="la_fld_Password"/>
+
+ <inp2:m_RenderElement name="subsection" title="la_title_BounceSettings"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BounceEmail" title="la_fld_BounceEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BounceServer" title="la_fld_Server" hint_label="la_hint_PopServer"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BouncePort" title="la_fld_Port" hint_label="la_hint_PopPort"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BounceUsername" title="la_fld_Username"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BouncePassword" title="la_fld_Password"/>
+
+ <inp2:m_RenderElement name="inp_edit_filler"/>
+ </table>
+</div>
+
+<script type="text/javascript">
+ var $field_mask = '<inp2:form_InputName field="#FIELD_NAME#" js_escape="1"/>';
+
+ function reflectFromFields() {
+ var $enabled = get_control($field_mask, 'EnableEmailCommunication', undefined, '_cb').checked;
+ var $fields = [
+ 'ReplyFromEmail', 'ReplyServer', 'ReplyPort', 'ReplyUsername', 'ReplyPassword',
+ 'BounceEmail', 'BounceServer', 'BouncePort', 'BounceUsername', 'BouncePassword',
+ 'ReplyFromName', 'ReplyCc', 'ReplyBcc', 'ReplyMessageSignature'
+ ];
+
+ for (var $i = 0; $i < $fields.length; $i++) {
+ get_control($field_mask, $fields[$i]).disabled = !$enabled;
+ }
+ }
+
+ reflectFromFields();
+</script>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: admin_templates/forms/form_field_edit.tpl
===================================================================
--- admin_templates/forms/form_field_edit.tpl (revision 13377)
+++ admin_templates/forms/form_field_edit.tpl (working copy)
@@ -1,3 +1,5 @@
+<inp2:adm_SetPopupSize width="780" height="570"/>
+
<inp2:m_include t="incs/header" />
<inp2:m_RenderElement name="combined_header" section="in-portal:forms" prefix="form" title_preset="form_field_edit"/>
@@ -37,7 +39,7 @@
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="FieldName" title="!la_prompt_FieldName!" size="40"/>
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="FieldLabel" title="!la_prompt_FieldLabel!" size="40"/>
- <inp2:m_RenderElement name="subsection" prefix="" fields="Prompt,ElementType,Validation,ValueList,DefaultValue,Priority,Required,DisplayInGrid" title="!la_tab_AdminUI!"/>
+ <inp2:m_RenderElement name="subsection" prefix="formflds" fields="Prompt,ElementType,Validation,ValueList,DefaultValue,Priority,Required,DisplayInGrid,Visibility,EmailCommunicationRole" title="!la_tab_AdminUI!"/>
<!--<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="Heading" title="!la_prompt_heading!" size="40"/>-->
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="Prompt" title="!la_prompt_FieldPrompt!" size="40"/>
<inp2:m_RenderElement name="inp_edit_options" prefix="formflds" field="ElementType" title="!la_prompt_InputType!"/>
@@ -47,7 +49,12 @@
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="Priority" title="!la_field_Priority!" size="10"/>
<inp2:m_RenderElement name="inp_edit_checkbox" prefix="formflds" field="Required" title="!la_fld_Required!"/>
<inp2:m_RenderElement name="inp_edit_checkbox" prefix="formflds" field="DisplayInGrid" title="!la_fld_DisplayInGrid!"/>
+ <inp2:m_RenderElement name="inp_edit_radio" prefix="formflds" field="Visibility" title="la_fld_Visibility"/>
+ <inp2:m_if check="form_Field" name="EnableEmailCommunication" db="db">
+ <inp2:m_RenderElement name="inp_edit_options" prefix="formflds" field="EmailCommunicationRole" title="la_fld_EmailCommunicationRole" has_empty="1"/>
+ </inp2:m_if>
+
<inp2:m_if check="m_IsDebugMode">
<inp2:m_RenderElement name="inp_edit_checkbox" prefix="formflds" field="IsSystem" title="!la_fld_IsSystem!"/>
</inp2:m_if>
Index: admin_templates/forms/forms_edit.tpl
===================================================================
--- admin_templates/forms/forms_edit.tpl (revision 13377)
+++ admin_templates/forms/forms_edit.tpl (working copy)
@@ -60,9 +60,29 @@
<table class="edit-form">
<inp2:m_RenderElement name="inp_id_label" prefix="form" field="FormId" title="!la_fld_Id!"/>
<inp2:m_RenderElement name="inp_edit_box" prefix="form" field="Title" title="!la_fld_Title!" size="100"/>
+ <inp2:m_RenderElement name="inp_edit_checkbox" prefix="form" field="RequireLogin" title="la_fld_RequireLogin" onclick="reflectSecurutyImage();"/>
+ <inp2:m_RenderElement name="inp_edit_checkbox" prefix="form" field="UseSecurityImage" title="la_fld_UseSecurityImage"/>
<inp2:m_RenderElement name="inp_edit_textarea" prefix="form" field="Description" title="!la_fld_Description!" cols="60" rows="5"/>
<inp2:m_RenderElement name="inp_edit_filler"/>
</table>
</div>
+<script type="text/javascript">
+ var $field_mask = '<inp2:form_InputName field="#FIELD_NAME#" js_escape="1"/>';
+
+ function reflectSecurutyImage() {
+ var $use_security_image = get_control($field_mask, 'UseSecurityImage', undefined, '_cb');
+
+ if (get_control($field_mask, 'RequireLogin', undefined, '_cb').checked) {
+ $use_security_image.checked = false;
+ $use_security_image.disabled = true;
+ }
+ else {
+ $use_security_image.disabled = false;
+ }
+ }
+
+ reflectSecurutyImage();
+</script>
+
<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: admin_templates/img/itemicons/icon16_bounce.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\itemicons\icon16_bounce.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/itemicons/icon16_new_email.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\itemicons\icon16_new_email.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/itemicons/icon16_not_replied.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\itemicons\icon16_not_replied.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/itemicons/icon16_replied.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\itemicons\icon16_replied.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/toolbar/tool_reply.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\toolbar\tool_reply.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/toolbar/tool_reply_f2.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\toolbar\tool_reply_f2.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/toolbar/tool_reply_f3.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\toolbar\tool_reply_f3.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/toolbar/tool_resend.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\toolbar\tool_resend.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/toolbar/tool_resend_f2.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\toolbar\tool_resend_f2.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/img/toolbar/tool_resend_f3.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: admin_templates\img\toolbar\tool_resend_f3.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: admin_templates/submissions/submission_edit_logs.tpl
===================================================================
--- admin_templates/submissions/submission_edit_logs.tpl (revision 0)
+++ admin_templates/submissions/submission_edit_logs.tpl (revision 0)
@@ -0,0 +1,143 @@
+<inp2:adm_SetPopupSize width="800" height="640"/>
+
+<inp2:m_include t="incs/header"/>
+<inp2:m_Get var="form_id" result_to_var="form_id"/>
+
+<inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="submission_edit_logs" tab_preset="Default" />
+
+<!-- ToolBar --->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+ <tr>
+ <td>
+ <table width="100%" cellpadding="0" cellspacing="0">
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'cancel',
+ '<inp2:m_phrase label="la_ToolTip_Close" escape="1"/>',
+ function() {
+ submit_event('formsubs', 'OnGoBack');
+ }
+ )
+ );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'prev',
+ '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>',
+ function() {
+ go_to_id('formsubs', '<inp2:formsubs_PrevId/>');
+ }
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'next',
+ '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>',
+ function() {
+ go_to_id('formsubs', '<inp2:formsubs_NextId/>');
+ }
+ )
+ );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep2') );
+
+ function edit()
+ {
+ std_edit_temp_item('submission-log', 'submissions/submission_log_edit');
+ }
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'edit',
+ '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>',
+ edit
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'reply',
+ '<inp2:m_phrase label="la_ToolTip_Reply" escape="1"/>',
+ function() {
+ Application.SetVar('client_mode', 0);
+ std_new_item('submission-log', 'submissions/submission_log_edit');
+ }
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'delete',
+ '<inp2:m_phrase label="la_ToolTip_Delete" escape="1"/>',
+ function() {
+ std_delete_items('submission-log')
+ }
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'resend',
+ '<inp2:m_phrase label="la_ToolTip_Resend" escape="1"/>',
+ function() {
+ submit_event('submission-log', 'OnResendReply');
+ }
+ )
+ );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep3') );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'view',
+ '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>',
+ function(id) {
+ show_viewmenu(a_toolbar, 'view');
+ }
+ )
+ );
+
+ a_toolbar.Render();
+
+ <inp2:m_if check="formsubs_IsSingle">
+ a_toolbar.HideButton('prev');
+ a_toolbar.HideButton('next');
+ a_toolbar.HideButton('sep1');
+ <inp2:m_else/>
+ <inp2:m_if check="formsubs_IsLast">
+ a_toolbar.DisableButton('next');
+ </inp2:m_if>
+ <inp2:m_if check="formsubs_IsFirst">
+ a_toolbar.DisableButton('prev');
+ </inp2:m_if>
+ </inp2:m_if>
+ </script>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+
+<inp2:m_DefineElement name="grid_subject_td" format="" nl2br="" first_chars="" td_style="" currency="">
+ <inp2:m_if check="IsNewUserReply">
+ <strong><inp2:Field field="$field" first_chars="$first_chars" currency="$currency" nl2br="$nl2br" grid="$grid" format="$format"/></strong>
+ <inp2:m_else/>
+ <inp2:Field field="$field" first_chars="$first_chars" currency="$currency" nl2br="$nl2br" grid="$grid" format="$format"/>
+ </inp2:m_if>
+</inp2:m_DefineElement>
+
+<inp2:m_RenderElement name="grid" PrefixSpecial="submission-log" IdField="SubmissionLogId" grid="Default"/>
+<script type="text/javascript">
+Grids['submission-log'].SetDependantToolbarButtons( new Array('edit','delete', 'resend') );
+</script>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: admin_templates/submissions/submission_log_edit.tpl
===================================================================
--- admin_templates/submissions/submission_log_edit.tpl (revision 0)
+++ admin_templates/submissions/submission_log_edit.tpl (revision 0)
@@ -0,0 +1,145 @@
+<inp2:adm_SetPopupSize width="820" height="570"/>
+
+<inp2:m_include t="incs/header"/>
+
+<inp2:m_Get var="form_id" result_to_var="form_id"/>
+<inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="submission_log_edit"/>
+
+<!-- ToolBar --->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+
+ <inp2:m_if check="submission-log_IsNewItem">
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'select',
+ '<inp2:m_phrase label="la_ToolTip_Send" escape="1"/>',
+ function() {
+ submit_event('submission-log', '<inp2:submission-log_SaveEvent/>');
+ }
+ )
+ );
+ </inp2:m_if>
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'cancel',
+ '<inp2:m_phrase label="la_ToolTip_Close" escape="1"/>',
+ function() {
+ cancel_edit('submission-log', 'OnGoBack', '<inp2:submission-log_SaveEvent/>', '<inp2:m_Phrase label="la_FormCancelConfirmation" escape="1"/>');
+ }
+ )
+ );
+
+ <inp2:m_if check="submission-log_IsUserReply" inverse="inverse">
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'resend',
+ '<inp2:m_phrase label="la_ToolTip_Resend" escape="1"/>',
+ function() {
+ submit_event('submission-log', 'OnResendReply');
+ }
+ )
+ );
+ </inp2:m_if>
+
+ <inp2:m_if check="submission-log_IsNewItem">
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'reset_to_user',
+ '<inp2:m_phrase label="la_ToolTip_SaveAsDraft" escape="1"/>',
+ function() {
+ submit_event('submission-log', 'OnSaveDraft');
+ }
+ )
+ );
+ </inp2:m_if>
+
+ a_toolbar.Render();
+ </script>
+
+ <script type="text/javascript" src="js/swfobject.js"></script>
+ <script type="text/javascript" src="js/uploader.js"></script>
+ </td>
+ </tr>
+</table>
+
+<inp2:m_DefineElement name="file_element">
+ <a href="<inp2:Field field='$field' format='full_url'/>" target="_blank"><inp2:Field field="$field"/></a><br/>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="inp_edit_upload_label" is_last="">
+ <tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
+ <inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
+ <td class="control-cell">
+ <inp2:$prefix_IterateFiles render_as="file_element" field="$field"/>
+ </td>
+ <inp2:m_RenderElement name="inp_edit_error" pass_params="1"/>
+ </tr>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="inp_edit_draft" is_last="">
+ <tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
+ <inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="la_DraftAvailableFrom" is_last="$is_last"/>
+ <td class="control-cell">
+ <inp2:draft.related_Field name="CreatedOn"/>
+ [<a href="#" onclick="submit_event('<inp2:m_Param name='prefix'/>', 'OnUseDraft'); return false;"><inp2:m_Phrase name="la_btn_UseDraft"/></a>]
+ [<a href="#" onclick="submit_event('<inp2:m_Param name='prefix'/>', 'OnDeleteDraft'); return false;"><inp2:m_Phrase name="la_btn_DeleteDraft"/></a>]
+ </td>
+ <inp2:m_RenderElement name="inp_edit_error" pass_params="1"/>
+ </tr>
+</inp2:m_DefineElement>
+
+<input type="hidden" name="client_mode" value="<inp2:m_Get name='client_mode'/>"/>
+
+<inp2:submission-log_SaveWarning name="grid_save_warning"/>
+<inp2:submission-log_ErrorWarning name="form_error_warning"/>
+
+<div id="scroll_container">
+ <table class="edit-form">
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="FormSubmissionId"/>
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="DraftId"/>
+ <inp2:m_RenderElement name="inp_id_label" prefix="submission-log" field="SubmissionLogId" title="la_fld_Id"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="FromEmail" title="la_fld_FromEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="ToEmail" size="60" title="la_fld_ToEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="Cc" size="60" title="la_fld_Cc"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="Bcc" size="60" title="la_fld_Bcc"/>
+
+ <inp2:m_if check="submission-log_IsNewItem">
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="Subject" size="80" title="la_fld_Subject"/>
+
+ <inp2:m_if check="submission-log_HasDraft">
+ <inp2:m_RenderElement name="inp_edit_draft" prefix="submission-log" field="DraftId"/>
+ </inp2:m_if>
+
+ <inp2:m_RenderElement name="inp_edit_textarea" prefix="submission-log" field="Message" rows="30" cols="100" title="la_fld_Message"/>
+ <inp2:m_RenderElement name="inp_edit_swf_upload" prefix="submission-log" field="Attachment" title="la_fld_Attachment"/>
+ <inp2:m_else/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="Subject" title="la_fld_Subject"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="Message" title="la_fld_Message" nl2br="1"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="ReplyStatus" title="la_fld_ReplyStatus"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="RepliedOn" title="la_fld_RepliedOn"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="SentStatus" title="la_fld_SentStatus"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="SentOn" title="la_fld_SentOn"/>
+ <inp2:m_RenderElement name="inp_edit_upload_label" prefix="submission-log" field="Attachment" title="la_fld_Attachment"/>
+
+ <inp2:m_if check="submission-log_Field" name="BounceInfo">
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="BounceInfo" title="la_fld_BounceInfo" nl2br="1"/>
+ </inp2:m_if>
+
+ <inp2:m_if check="submission-log_Field" name="BounceDate" db="db">
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="BounceDate" title="la_fld_BounceDate"/>
+ </inp2:m_if>
+ </inp2:m_if>
+
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="FromEmail"/>
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="ReplyTo"/>
+
+ <inp2:m_RenderElement name="inp_edit_filler" />
+ </table>
+</div>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: admin_templates/submissions/submission_view.tpl
===================================================================
--- admin_templates/submissions/submission_view.tpl (revision 13377)
+++ admin_templates/submissions/submission_view.tpl (working copy)
@@ -1,8 +1,14 @@
+<inp2:adm_SetPopupSize width="800" height="640"/>
+
<inp2:m_include t="incs/header"/>
-
<inp2:m_Get var="form_id" result_to_var="form_id"/>
-<inp2:m_RenderElement name="combined_header" section="in-portal:submissions:$form_id" prefix="formsubs" title_preset="formsubs_view"/>
+<inp2:m_if check="form_Field" name="EnableEmailCommunication" db="db">
+ <inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="formsubs_view" tab_preset="Default"/>
+<inp2:m_else/>
+ <inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="formsubs_view"/>
+</inp2:m_if>
+
<!-- ToolBar -->
<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
<tbody>
@@ -11,11 +17,16 @@
<script type="text/javascript">
a_toolbar = new ToolBar();
- a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
- submit_event('formsubs','OnCancelEdit');
+ a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
+ submit_event('formsubs', '<inp2:formsubs_SaveEvent/>');
}
) );
+ a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Close" escape="1"/>', function() {
+ submit_event('formsubs', 'OnGoBack');
+ }
+ ) );
+
a_toolbar.AddButton( new ToolBarSeparator('sep1') );
a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
@@ -52,7 +63,7 @@
<inp2:m_DefineElement name="form_field_text">
<inp2:m_if check="FieldEquals" field="Validation" value="1">
- <a href="mailto:<inp2:SubmissionTag tag="Field"/>"><inp2:SubmissionTag tag="Field"/></a>
+ <a href="mailto:<inp2:SubmissionTag tag='Field'/>"><inp2:SubmissionTag tag="Field"/></a>
<inp2:m_else/>
<inp2:SubmissionTag tag="Field"/>
</inp2:m_if>
@@ -62,42 +73,40 @@
<inp2:SubmissionTag tag="Field"/>
</inp2:m_DefineElement>
-<inp2:m_DefineElement name="form_field_option">
- <option value="<inp2:m_param name="key"/>"<inp2:m_param name="selected"/>><inp2:m_param name="option"/></option>
-</inp2:m_DefineElement>
-
<inp2:m_DefineElement name="form_field_select">
<inp2:SubmissionTag tag="Field"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_checkbox">
- <input type="hidden" id="<inp2:CustomInputName/>" name="<inp2:CustomInputName/>" value="<inp2:SubmissionTag tag="Field" field="$field" db="db"/>">
- <input disabled="disabled" tabindex="<inp2:m_get param="tab_index"/>" type="checkbox" id="_cb_<inp2:m_param name="field"/>" name="_cb_<inp2:m_param name="field"/>" <inp2:SubmissionTag tag="Field" checked="checked" db="db"/> class="<inp2:m_param name="field_class"/>" onclick="document.getElementById('<inp2:CustomInputName/>').value = this.checked ? 1:0">
+ <inp2:SubmissionTag tag="Field"/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_textarea">
<inp2:SubmissionTag tag="Field" nl2br="1" no_special="1"/>
</inp2:m_DefineElement>
-<inp2:m_DefineElement name="form_radio_item">
- <input disabled="disabled" type="radio" <inp2:m_param name="checked"/> name="<inp2:m_param name="field_name"/>" id="<inp2:m_param name="field_name"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>"><label for="<inp2:m_param name="field_name"/>_<inp2:m_param name="key"/>"><inp2:m_param name="option"/></label>
+<inp2:m_DefineElement name="form_field_radio" pass_tabindex="">
+ <inp2:SubmissionTag tag="Field"/>
</inp2:m_DefineElement>
-<inp2:m_DefineElement name="form_field_radio">
- <inp2:SubmissionTag tag="PredefinedOptions" field="$field" tabindex="$pass_tabindex" block="form_radio_item" selected="checked"/>
-</inp2:m_DefineElement>
-
-
<inp2:formsubs_SaveWarning name="grid_save_warning"/>
<inp2:formsubs_ErrorWarning name="form_error_warning"/>
<div id="scroll_container">
<table class="edit-form">
- <inp2:m_RenderElement name="subsection" prefix="formsubs" fields="FormSubmissionId,SubmissionTime" title="!la_section_General!"/>
- <inp2:m_RenderElement name="inp_id_label" prefix="formsubs" field="FormSubmissionId" title="!la_fld_Id!"/>
- <inp2:m_RenderElement name="inp_edit_date_time" prefix="formsubs" field="SubmissionTime" title="!la_fld_SubmissionTime!" />
- <inp2:m_RenderElement name="subsection" title="!la_section_Data!"/>
+ <inp2:m_RenderElement name="subsection" prefix="formsubs" fields="FormSubmissionId,SubmissionTime,IPAddress,ReferrerURL,LogStatus,LastUpdatedOn" title="la_section_General"/>
+ <inp2:m_RenderElement name="inp_id_label" prefix="formsubs" field="FormSubmissionId" title="la_fld_Id"/>
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="SubmissionTime" title="la_fld_SubmissionTime" />
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="IPAddress" title="la_fld_IPAddress" />
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="ReferrerURL" title="la_fld_ReferrerURL" />
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="LogStatus" title="la_fld_Status" />
+ <inp2:m_if check="formsubs_Field" name="LastUpdatedOn" db="db">
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="LastUpdatedOn" title="la_fld_LastUpdatedOn" />
+ </inp2:m_if>
+
+ <inp2:m_RenderElement name="subsection" title="la_section_Data"/>
+
<inp2:m_DefineElement name="form_field">
<tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
<inp2:m_inc param="tab_index" by="1"/>
Index: admin_templates/submissions/submissions_list.tpl
===================================================================
--- admin_templates/submissions/submissions_list.tpl (revision 13377)
+++ admin_templates/submissions/submissions_list.tpl (working copy)
@@ -12,7 +12,8 @@
//do not rename - this function is used in default grid for double click!
function edit()
{
- std_edit_item('formsubs', 'submissions/submission_view');
+ // don't use temp tables, since we can receive user replies while reviewing form submission
+ std_edit_temp_item('formsubs', 'submissions/submission_view');
}
var a_toolbar = new ToolBar();
Index: install/english.lang
===================================================================
--- install/english.lang (revision 13377)
+++ install/english.lang (working copy)
@@ -20,6 +20,7 @@
<PHRASE Label="la_btn_Change" Module="Core" Type="1">Q2hhbmdl</PHRASE>
<PHRASE Label="la_btn_ContentMode" Module="Core" Type="1">Q29udGVudCBNb2Rl</PHRASE>
<PHRASE Label="la_btn_Delete" Module="Core" Type="1">RGVsZXRl</PHRASE>
+ <PHRASE Label="la_btn_DeleteDraft" Module="Core" Type="1">RGVsZXRl</PHRASE>
<PHRASE Label="la_btn_DesignMode" Module="Core" Type="1">RGVzaWduIE1vZGU=</PHRASE>
<PHRASE Label="la_btn_Down" Module="Core" Type="1">RG93bg==</PHRASE>
<PHRASE Label="la_btn_Edit" Module="Core" Type="1">RWRpdA==</PHRASE>
@@ -33,6 +34,7 @@
<PHRASE Label="la_btn_SectionProperties" Module="Core" Type="1">U2VjdGlvbiBQcm9wZXJ0aWVz</PHRASE>
<PHRASE Label="la_btn_SectionTemplate" Module="Core" Type="1">U2VjdGlvbiBUZW1wbGF0ZQ==</PHRASE>
<PHRASE Label="la_btn_Up" Module="Core" Type="1">VXA=</PHRASE>
+ <PHRASE Label="la_btn_UseDraft" Module="Core" Type="1">VXNl</PHRASE>
<PHRASE Label="la_Cancel" Module="Core" Type="1">Q2FuY2Vs</PHRASE>
<PHRASE Label="la_category" Module="Core" Type="1">U2VjdGlvbg==</PHRASE>
<PHRASE Label="la_category_daysnew_prompt" Module="Core" Type="1">TnVtYmVyIG9mIGRheXMgZm9yIGEgY2F0LiB0byBiZSBORVc=</PHRASE>
@@ -61,10 +63,12 @@
<PHRASE Label="la_col_Duration" Module="Core" Type="1">RHVyYXRpb24=</PHRASE>
<PHRASE Label="la_col_Effective" Module="Core" Type="1">RWZmZWN0aXZl</PHRASE>
<PHRASE Label="la_col_Email" Module="Core" Type="1">RW1haWw=</PHRASE>
+ <PHRASE Label="la_col_EmailCommunicationRole" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24gUm9sZQ==</PHRASE>
<PHRASE Label="la_col_EmailsQueued" Module="Core" Type="1">UXVldWU=</PHRASE>
<PHRASE Label="la_col_EmailsSent" Module="Core" Type="1">U2VudA==</PHRASE>
<PHRASE Label="la_col_EmailsTotal" Module="Core" Type="1">VG90YWw=</PHRASE>
<PHRASE Label="la_col_Enabled" Module="Core" Type="1">RW5hYmxlZA==</PHRASE>
+ <PHRASE Label="la_col_EnableEmailCommunication" Module="Core" Type="1">RW5hYmxlIEUtbWFpbCBDb21tdW5pY2F0aW9u</PHRASE>
<PHRASE Label="la_col_EndDate" Module="Core" Type="1">RW5kIERhdGU=</PHRASE>
<PHRASE Label="la_col_Error" Module="Core" Type="1">Jm5ic3A7</PHRASE>
<PHRASE Label="la_col_Event" Module="Core" Type="1">RXZlbnQ=</PHRASE>
@@ -75,6 +79,7 @@
<PHRASE Label="la_col_FileName" Module="Core" Type="1">RmlsZW5hbWU=</PHRASE>
<PHRASE Label="la_col_FilePath" Module="Core" Type="1">UGF0aA==</PHRASE>
<PHRASE Label="la_col_FirstName" Module="Core" Type="1">Rmlyc3QgTmFtZQ==</PHRASE>
+ <PHRASE Label="la_col_FromEmail" Module="Core" Type="1">RnJvbSBFLW1haWw=</PHRASE>
<PHRASE Label="la_col_FromToUser" Module="Core" Type="1">RnJvbSAvIFRvIFVzZXI=</PHRASE>
<PHRASE Label="la_col_FrontEndOnly" Module="Core" Type="1">RnJvbnQtRW5kIE9ubHk=</PHRASE>
<PHRASE Label="la_col_FrontRegistration" Module="Core" Type="1">QWxsb3cgUmVnaXN0cmF0aW9u</PHRASE>
@@ -106,6 +111,7 @@
<PHRASE Label="la_col_LastRunOn" Module="Core" Type="1">TGFzdCBSdW4gT24=</PHRASE>
<PHRASE Label="la_col_LastRunStatus" Module="Core" Type="1">TGFzdCBSdW4gU3RhdHVz</PHRASE>
<PHRASE Label="la_col_LastSendRetry" Module="Core" Type="1">TGFzdCBBdHRlbXB0</PHRASE>
+ <PHRASE Label="la_col_LastUpdatedOn" Module="Core" Type="1">TGFzdCBVcGRhdGVkIE9u</PHRASE>
<PHRASE Label="la_col_LinkUrl" Module="Core" Type="1">TGluayBVUkw=</PHRASE>
<PHRASE Label="la_col_LocalName" Module="Core" Type="1">TmFtZQ==</PHRASE>
<PHRASE Label="la_col_Location" Module="Core" Type="1">TG9jYXRpb24=</PHRASE>
@@ -114,6 +120,7 @@
<PHRASE Label="la_col_MasterId" Module="Core" Type="1">TWFzdGVyIElE</PHRASE>
<PHRASE Label="la_col_MasterPrefix" Module="Core" Type="1">TWFzdGVyIFByZWZpeA==</PHRASE>
<PHRASE Label="la_col_MembershipExpires" Module="Core" Type="1">TWVtYmVyc2hpcCBFeHBpcmVz</PHRASE>
+ <PHRASE Label="la_col_Message" Module="Core" Type="1">TWVzc2FnZQ==</PHRASE>
<PHRASE Label="la_col_MessageHeaders" Module="Core" Type="1">TWVzc2FnZSBIZWFkZXJz</PHRASE>
<PHRASE Label="la_col_MessageHtml" Module="Core" Type="1">SFRNTA==</PHRASE>
<PHRASE Label="la_col_MessageText" Module="Core" Type="1">UGxhaW4gVGV4dA==</PHRASE>
@@ -145,7 +152,11 @@
<PHRASE Label="la_col_Rating" Module="Core" Type="1">UmF0aW5n</PHRASE>
<PHRASE Label="la_col_RecipientType" Module="Core" Type="1">UmVjaXBpZW50IFR5cGU=</PHRASE>
<PHRASE Label="la_col_Referer" Module="Core" Type="1">UmVmZXJlcg==</PHRASE>
+ <PHRASE Label="la_col_ReferrerURL" Module="Core" Type="1">UmVmZXJyZXIgVVJM</PHRASE>
<PHRASE Label="la_col_RelationshipType" Module="Core" Type="1">UmVsYXRpb24gVHlwZQ==</PHRASE>
+ <PHRASE Label="la_col_RepliedOn" Module="Core" Type="1">UmVwbGllZCBPbg==</PHRASE>
+ <PHRASE Label="la_col_ReplyStatus" Module="Core" Type="1">UmVwbGllZA==</PHRASE>
+ <PHRASE Label="la_col_RequireLogin" Module="Core" Type="1">UmVxdWlyZSBMb2dpbg==</PHRASE>
<PHRASE Label="la_col_ResetToDefaultSorting" Module="Core" Type="1">UmVzZXQgdG8gZGVmYXVsdA==</PHRASE>
<PHRASE Label="la_col_ReviewCount" Module="Core" Type="1">Q29tbWVudHM=</PHRASE>
<PHRASE Label="la_col_ReviewedBy" Module="Core" Type="1">Q3JlYXRlZCBieQ==</PHRASE>
@@ -156,6 +167,8 @@
<PHRASE Label="la_col_SearchTerm" Module="Core" Type="1">U2VhcmNoIFRlcm0=</PHRASE>
<PHRASE Label="la_col_SelectorName" Module="Core" Type="1">U2VsZWN0b3I=</PHRASE>
<PHRASE Label="la_col_SendRetries" Module="Core" Type="1">QXR0ZW1wdHMg</PHRASE>
+ <PHRASE Label="la_col_SentOn" Module="Core" Type="1">U2VudCBPbg==</PHRASE>
+ <PHRASE Label="la_col_SentStatus" Module="Core" Type="1">U2VudA==</PHRASE>
<PHRASE Label="la_col_SessionEnd" Module="Core" Type="1">U2Vzc2lvbiBFbmQ=</PHRASE>
<PHRASE Label="la_col_SessionLogId" Module="Core" Type="1">U2Vzc2lvbiBMb2cgSUQ=</PHRASE>
<PHRASE Label="la_col_SessionStart" Module="Core" Type="1">U2Vzc2lvbiBTdGFydA==</PHRASE>
@@ -173,13 +186,16 @@
<PHRASE Label="la_col_ThesaurusTerm" Module="Core" Type="1">VGhlc2F1cnVzIFRlcm0=</PHRASE>
<PHRASE Label="la_col_ThesaurusType" Module="Core" Type="1">VGhlc2F1cnVzIFR5cGU=</PHRASE>
<PHRASE Label="la_col_Title" Module="Core" Type="1">VGl0bGU=</PHRASE>
+ <PHRASE Label="la_col_ToEmail" Module="Core" Type="1">VG8gRS1tYWls</PHRASE>
<PHRASE Label="la_col_Translation" Module="Core" Type="1">VmFsdWU=</PHRASE>
<PHRASE Label="la_col_Type" Module="Core" Type="1">VHlwZQ==</PHRASE>
<PHRASE Label="la_col_UserCount" Module="Core" Type="1">VXNlcnM=</PHRASE>
<PHRASE Label="la_col_UserFirstLastName" Module="Core" Type="1">TGFzdG5hbWUgRmlyc3RuYW1l</PHRASE>
<PHRASE Label="la_col_Username" Module="Core" Type="1">VXNlcm5hbWU=</PHRASE>
+ <PHRASE Label="la_col_UseSecurityImage" Module="Core" Type="1">VXNlIFNlY3VyaXR5IEltYWdl</PHRASE>
<PHRASE Label="la_col_Value" Module="Core" Type="1">RmllbGQgVmFsdWU=</PHRASE>
<PHRASE Label="la_col_Version" Module="Core" Type="1">VmVyc2lvbg==</PHRASE>
+ <PHRASE Label="la_col_Visibility" Module="Core" Type="1">VmlzaWJpbGl0eQ==</PHRASE>
<PHRASE Label="la_col_Visible" Module="Core" Type="1">VmlzaWJsZQ==</PHRASE>
<PHRASE Label="la_col_VisitDate" Module="Core" Type="1">VmlzaXQgRGF0ZQ==</PHRASE>
<PHRASE Label="la_common_ascending" Module="Core" Type="1">QXNjZW5kaW5n</PHRASE>
@@ -504,6 +520,7 @@
<PHRASE Label="la_DownloadCSV" Module="Core" Type="1">RG93bmxvYWQgQ1NW</PHRASE>
<PHRASE Label="la_DownloadExportFile" Module="Core" Type="1">RG93bmxvYWQgRXhwb3J0IEZpbGU=</PHRASE>
<PHRASE Label="la_DownloadLanguageExport" Module="Core" Type="1">RG93bmxvYWQgTGFuZ3VhZ2UgRXhwb3J0</PHRASE>
+ <PHRASE Label="la_DraftAvailableFrom" Module="Core" Type="1">RHJhZnQgQXZhaWxhYmxl</PHRASE>
<PHRASE Label="la_EditingContent" Module="Core" Type="1">Q29udGVudCBFZGl0b3I=</PHRASE>
<PHRASE Label="la_EditingInProgress" Module="Core" Type="1">WW91IGhhdmUgbm90IHNhdmVkIGNoYW5nZXMgdG8gdGhlIGl0ZW0geW91IGFyZSBlZGl0aW5nITxiciAvPkNsaWNrIE9LIHRvIGxvb3NlIGNoYW5nZXMgYW5kIGdvIHRvIHRoZSBzZWxlY3RlZCBzZWN0aW9uPGJyIC8+b3IgQ2FuY2VsIHRvIHN0YXkgaW4gdGhlIGN1cnJlbnQgc2VjdGlvbi4=</PHRASE>
<PHRASE Label="la_editor_default_style" Module="Core" Type="1">RGVmYXVsdCB0ZXh0</PHRASE>
@@ -512,11 +529,13 @@
<PHRASE Label="la_empty_file" Module="Core" Type="1">RmlsZSBpcyBlbXB0eQ==</PHRASE>
<PHRASE Label="la_Enabled" Module="Core" Type="1">RW5hYmxlZA==</PHRASE>
<PHRASE Label="la_error_cant_save_file" Module="Core" Type="1">Q2FuJ3Qgc2F2ZSBhIGZpbGU=</PHRASE>
+ <PHRASE Label="la_error_ConnectionFailed" Module="Core" Type="1">Q29ubmVjdGlvbiBGYWlsZWQ=</PHRASE>
<PHRASE Label="la_error_copy_subcategory" Module="Core" Type="1">RXJyb3IgY29weWluZyBzdWJzZWN0aW9ucw==</PHRASE>
<PHRASE Label="la_error_CustomExists" Module="Core" Type="1">Q3VzdG9tIGZpZWxkIHdpdGggaWRlbnRpY2FsIG5hbWUgYWxyZWFkeSBleGlzdHM=</PHRASE>
<PHRASE Label="la_error_FileTooLarge" Module="Core" Type="1">RmlsZSBpcyB0b28gbGFyZ2U=</PHRASE>
<PHRASE Label="la_error_InvalidFileFormat" Module="Core" Type="1">SW52YWxpZCBGaWxlIEZvcm1hdA==</PHRASE>
<PHRASE Label="la_error_invalidoption" Module="Core" Type="1">aW52YWxpZCBvcHRpb24=</PHRASE>
+ <PHRASE Label="la_error_LoginFailed" Module="Core" Type="1">TG9naW4gRmFpbGVk</PHRASE>
<PHRASE Label="la_error_move_subcategory" Module="Core" Type="1">RXJyb3IgbW92aW5nIHN1YnNlY3Rpb24=</PHRASE>
<PHRASE Label="la_error_NoInheritancePossible" Module="Core" Type="1">Q2FuJ3QgaW5oZXJpdCB0ZW1wbGF0ZSBmcm9tIHRvcCBjYXRlZ29yeQ==</PHRASE>
<PHRASE Label="la_error_PasswordMatch" Module="Core" Type="1">UGFzc3dvcmRzIGRvIG5vdCBtYXRjaCE=</PHRASE>
@@ -570,17 +589,22 @@
<PHRASE Label="la_fld_BackgroundImage" Module="Core" Type="1">QmFja2dyb3VuZCBJbWFnZQ==</PHRASE>
<PHRASE Label="la_fld_BackgroundPosition" Module="Core" Type="1">QmFja2dyb3VuZCBQb3NpdGlvbg==</PHRASE>
<PHRASE Label="la_fld_BackgroundRepeat" Module="Core" Type="1">QmFja2dyb3VuZCBSZXBlYXQ=</PHRASE>
+ <PHRASE Label="la_fld_Bcc" Module="Core" Type="1">QmNj</PHRASE>
<PHRASE Label="la_fld_BlockPosition" Module="Core" Type="1">RWxlbWVudCBQb3NpdGlvbg==</PHRASE>
<PHRASE Label="la_fld_BorderBottom" Module="Core" Type="1">Qm9yZGVyIEJvdHRvbQ==</PHRASE>
<PHRASE Label="la_fld_BorderLeft" Module="Core" Type="1">Qm9yZGVyIExlZnQ=</PHRASE>
<PHRASE Label="la_fld_BorderRight" Module="Core" Type="1">Qm9yZGVyIFJpZ2h0</PHRASE>
<PHRASE Label="la_fld_Borders" Module="Core" Type="1">Qm9yZGVycw==</PHRASE>
<PHRASE Label="la_fld_BorderTop" Module="Core" Type="1">Qm9yZGVyIFRvcA==</PHRASE>
+ <PHRASE Label="la_fld_BounceDate" Module="Core" Type="1">Qm91bmNlIERhdGU=</PHRASE>
+ <PHRASE Label="la_fld_BounceEmail" Module="Core" Type="1">Qm91bmNlIEVtYWls</PHRASE>
+ <PHRASE Label="la_fld_BounceInfo" Module="Core" Type="1">Qm91bmNlIEluZm8=</PHRASE>
<PHRASE Label="la_fld_Category" Module="Core" Type="1">U2VjdGlvbg==</PHRASE>
<PHRASE Label="la_fld_CategoryFormat" Module="Core" Type="1">U2VjdGlvbiBGb3JtYXQ=</PHRASE>
<PHRASE Label="la_fld_CategoryId" Module="Core" Type="1">U2VjdGlvbiBJRA==</PHRASE>
<PHRASE Label="la_fld_CategorySeparator" Module="Core" Type="1">U2VjdGlvbiBzZXBhcmF0b3I=</PHRASE>
<PHRASE Label="la_fld_CategoryTemplate" Module="Core" Type="1">U2VjdGlvbiBUZW1wbGF0ZQ==</PHRASE>
+ <PHRASE Label="la_fld_Cc" Module="Core" Type="1">Q2M=</PHRASE>
<PHRASE Label="la_fld_Changes" Module="Core" Type="1">Q2hhbmdlcw==</PHRASE>
<PHRASE Label="la_fld_Charset" Module="Core" Type="1">Q2hhcnNldA==</PHRASE>
<PHRASE Label="la_fld_CheckDuplicatesMethod" Module="Core" Type="1">Q2hlY2sgRHVwbGljYXRlcyBieQ==</PHRASE>
@@ -607,9 +631,11 @@
<PHRASE Label="la_fld_EditorsPick" Module="Core" Type="1">RWRpdG9ycyBQaWNr</PHRASE>
<PHRASE Label="la_fld_ElapsedTime" Module="Core" Type="1">RWxhcHNlZCBUaW1l</PHRASE>
<PHRASE Label="la_fld_Email" Module="Core" Type="1">RS1tYWls</PHRASE>
+ <PHRASE Label="la_fld_EmailCommunicationRole" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24gUm9sZQ==</PHRASE>
<PHRASE Label="la_fld_EmailsQueued" Module="Core" Type="1">RW1haWxzIGluIFF1ZXVl</PHRASE>
<PHRASE Label="la_fld_EmailsSent" Module="Core" Type="1">RW1haWxzIFNlbnQ=</PHRASE>
<PHRASE Label="la_fld_EmailsTotal" Module="Core" Type="1">RW1haWxzIFRvdGFs</PHRASE>
+ <PHRASE Label="la_fld_Enable" Module="Core" Type="1">RW5hYmxl</PHRASE>
<PHRASE Label="la_fld_Enabled" Module="Core" Type="1">RW5hYmxlZA==</PHRASE>
<PHRASE Label="la_fld_ErrorTag" Module="Core" Type="1">RXJyb3IgVGFn</PHRASE>
<PHRASE Label="la_fld_EstimatedTime" Module="Core" Type="1">RXN0aW1hdGVkIFRpbWU=</PHRASE>
@@ -647,6 +673,7 @@
<PHRASE Label="la_fld_Form" Module="Core" Type="1">T25saW5lIEZvcm0=</PHRASE>
<PHRASE Label="la_fld_FormSubmittedTemplate" Module="Core" Type="1">T25saW5lIEZvcm0gU3VibWl0dGVkIFRlbXBsYXRl</PHRASE>
<PHRASE Label="la_fld_FriendlyURL" Module="Core" Type="1">U2hvcnQgVVJM</PHRASE>
+ <PHRASE Label="la_fld_FromEmail" Module="Core" Type="1">RnJvbSBFbWFpbA==</PHRASE>
<PHRASE Label="la_fld_FromToUser" Module="Core" Type="1">RnJvbSAvIFRvIFVzZXI=</PHRASE>
<PHRASE Label="la_fld_FrontEndOnly" Module="Core" Type="1">RnJvbnQtRW5kIE9ubHk=</PHRASE>
<PHRASE Label="la_fld_FrontRegistration" Module="Core" Type="1">QWxsb3cgUmVnaXN0cmF0aW9uIG9uIEZyb250LWVuZA==</PHRASE>
@@ -668,6 +695,7 @@
<PHRASE Label="la_fld_InputTimeFormat" Module="Core" Type="1">SW5wdXQgVGltZSBGb3JtYXQ=</PHRASE>
<PHRASE Label="la_fld_InstallModules" Module="Core" Type="1">SW5zdGFsbCBNb2R1bGVz</PHRASE>
<PHRASE Label="la_fld_InstallPhraseTypes" Module="Core" Type="1">SW5zdGFsbCBQaHJhc2UgVHlwZXM=</PHRASE>
+ <PHRASE Label="la_fld_IPAddress" Module="Core" Type="1">SVAgQWRkcmVzcw==</PHRASE>
<PHRASE Label="la_fld_IsBaseCategory" Module="Core" Type="1">VXNlIGN1cnJlbnQgc2VjdGlvbiBhcyByb290IGZvciB0aGUgZXhwb3J0</PHRASE>
<PHRASE Label="la_fld_IsPrimary" Module="Core" Type="1">UHJpbWFyeQ==</PHRASE>
<PHRASE Label="la_fld_IsRequired" Module="Core" Type="1">UmVxdWlyZWQ=</PHRASE>
@@ -682,6 +710,7 @@
<PHRASE Label="la_fld_LastName" Module="Core" Type="1">TGFzdCBOYW1l</PHRASE>
<PHRASE Label="la_fld_LastRunOn" Module="Core" Type="1">TGFzdCBSdW4gT24=</PHRASE>
<PHRASE Label="la_fld_LastRunStatus" Module="Core" Type="1">TGFzdCBSdW4gU3RhdHVz</PHRASE>
+ <PHRASE Label="la_fld_LastUpdatedOn" Module="Core" Type="1">TGFzdCBVcGRhdGVkIE9u</PHRASE>
<PHRASE Label="la_fld_Left" Module="Core" Type="1">TGVmdA==</PHRASE>
<PHRASE Label="la_fld_LineEndings" Module="Core" Type="1">TGluZSBlbmRpbmdz</PHRASE>
<PHRASE Label="la_fld_LineEndingsInside" Module="Core" Type="1">TGluZSBFbmRpbmdzIEluc2lkZSBGaWVsZHM=</PHRASE>
@@ -702,6 +731,7 @@
<PHRASE Label="la_fld_MaxCategories" Module="Core" Type="1">TWF4aW11bSBudW1iZXIgb2YgU2VjdGlvbnMgb24gSXRlbSBjYW4gYmUgYWRkZWQgdG8=</PHRASE>
<PHRASE Label="la_fld_MenuIcon" Module="Core" Type="1">Q3VzdG9tIE1lbnUgSWNvbiAoaWUuIGltZy9tZW51X3Byb2R1Y3RzLmdpZik=</PHRASE>
<PHRASE Label="la_fld_MenuStatus" Module="Core" Type="1">TWVudSBTdGF0dXM=</PHRASE>
+ <PHRASE Label="la_fld_Message" Module="Core" Type="1">TWVzc2FnZQ==</PHRASE>
<PHRASE Label="la_fld_MessageBody" Module="Core" Type="1">TWVzc2FnZSBCb2R5</PHRASE>
<PHRASE Label="la_fld_MessageText" Module="Core" Type="1">UGxhaW4gVGV4dCBWZXJzaW9u</PHRASE>
<PHRASE Label="la_fld_MessageType" Module="Core" Type="1">TWVzc2FnZSBUeXBl</PHRASE>
@@ -735,6 +765,7 @@
<PHRASE Label="la_fld_PhraseType" Module="Core" Type="1">UGhyYXNlIFR5cGU=</PHRASE>
<PHRASE Label="la_fld_Pop" Module="Core" Type="1">UG9w</PHRASE>
<PHRASE Label="la_fld_Popular" Module="Core" Type="1">UG9wdWxhcg==</PHRASE>
+ <PHRASE Label="la_fld_Port" Module="Core" Type="1">UG9ydA==</PHRASE>
<PHRASE Label="la_fld_Position" Module="Core" Type="1">UG9zaXRpb24=</PHRASE>
<PHRASE Label="la_fld_Prefix" Module="Core" Type="1">UHJlZml4</PHRASE>
<PHRASE Label="la_fld_Primary" Module="Core" Type="1">UHJpbWFyeQ==</PHRASE>
@@ -743,11 +774,19 @@
<PHRASE Label="la_fld_PrimaryTranslation" Module="Core" Type="1">UHJpbWFyeSBMYW5ndWFnZSBQaHJhc2U=</PHRASE>
<PHRASE Label="la_fld_Priority" Module="Core" Type="1">T3JkZXI=</PHRASE>
<PHRASE Label="la_fld_Rating" Module="Core" Type="1">UmF0aW5n</PHRASE>
+ <PHRASE Label="la_fld_ReferrerURL" Module="Core" Type="1">UmVmZXJyZXIgVVJM</PHRASE>
<PHRASE Label="la_fld_RelatedSearchKeyword" Module="Core" Type="1">S2V5d29yZA==</PHRASE>
<PHRASE Label="la_fld_RelationshipType" Module="Core" Type="1">VHlwZQ==</PHRASE>
<PHRASE Label="la_fld_RemoteUrl" Module="Core" Type="1">UmVtb3RlIFVSTA==</PHRASE>
<PHRASE Label="la_fld_ReplaceDuplicates" Module="Core" Type="1">UmVwbGFjZSBEdXBsaWNhdGVz</PHRASE>
<PHRASE Label="la_fld_ReplacementTags" Module="Core" Type="1">UmVwbGFjZW1lbnQgVGFncw==</PHRASE>
+ <PHRASE Label="la_fld_RepliedOn" Module="Core" Type="1">UmVwbGllZCBPbg==</PHRASE>
+ <PHRASE Label="la_fld_ReplyBcc" Module="Core" Type="1">UmVwbHkgQmNj</PHRASE>
+ <PHRASE Label="la_fld_ReplyCc" Module="Core" Type="1">UmVwbHkgQ2M=</PHRASE>
+ <PHRASE Label="la_fld_ReplyFromEmail" Module="Core" Type="1">UmVwbHkgRnJvbSBFLW1haWw=</PHRASE>
+ <PHRASE Label="la_fld_ReplyFromName" Module="Core" Type="1">UmVwbHkgRnJvbSBOYW1l</PHRASE>
+ <PHRASE Label="la_fld_ReplyMessageSignature" Module="Core" Type="1">UmVwbHkgTWVzc2FnZSBTaWduYXR1cmU=</PHRASE>
+ <PHRASE Label="la_fld_ReplyStatus" Module="Core" Type="1">UmVwbGllZA==</PHRASE>
<PHRASE Label="la_fld_Required" Module="Core" Type="1">UmVxdWlyZWQ=</PHRASE>
<PHRASE Label="la_fld_ReviewText" Module="Core" Type="1">Q29tbWVudA==</PHRASE>
<PHRASE Label="la_fld_RuleType" Module="Core" Type="1">UnVsZSBUeXBl</PHRASE>
@@ -760,6 +799,9 @@
<PHRASE Label="la_fld_SelectorData" Module="Core" Type="1">U3R5bGU=</PHRASE>
<PHRASE Label="la_fld_SelectorId" Module="Core" Type="1">U2VsZWN0b3IgSUQ=</PHRASE>
<PHRASE Label="la_fld_SelectorName" Module="Core" Type="1">U2VsZWN0b3IgTmFtZQ==</PHRASE>
+ <PHRASE Label="la_fld_SentOn" Module="Core" Type="1">U2VudCBPbg==</PHRASE>
+ <PHRASE Label="la_fld_SentStatus" Module="Core" Type="1">U2VudA==</PHRASE>
+ <PHRASE Label="la_fld_Server" Module="Core" Type="1">U2VydmVy</PHRASE>
<PHRASE Label="la_fld_SessionLogId" Module="Core" Type="1">U2Vzc2lvbiBMb2cgSUQ=</PHRASE>
<PHRASE Label="la_fld_SimpleSearch" Module="Core" Type="1">U2ltcGxlIFNlYXJjaA==</PHRASE>
<PHRASE Label="la_fld_SkinName" Module="Core" Type="1">TmFtZQ==</PHRASE>
@@ -786,6 +828,7 @@
<PHRASE Label="la_fld_TimeFormat" Module="Core" Type="1">VGltZSBGb3JtYXQ=</PHRASE>
<PHRASE Label="la_fld_Title" Module="Core" Type="1">VGl0bGU=</PHRASE>
<PHRASE Label="la_fld_To" Module="Core" Type="1">VG8=</PHRASE>
+ <PHRASE Label="la_fld_ToEmail" Module="Core" Type="1">VG8gRS1tYWls</PHRASE>
<PHRASE Label="la_fld_Top" Module="Core" Type="1">VG9w</PHRASE>
<PHRASE Label="la_fld_TrackingCode" Module="Core" Type="1">VHJhY2tpbmcgQ29kZQ==</PHRASE>
<PHRASE Label="la_fld_Translation" Module="Core" Type="1">UGhyYXNl</PHRASE>
@@ -798,6 +841,7 @@
<PHRASE Label="la_fld_UserDocsUrl" Module="Core" Type="1">VXNlciBEb2N1bWVudGF0aW9uIFVSTA==</PHRASE>
<PHRASE Label="la_fld_UserGroups" Module="Core" Type="1">VXNlciBHcm91cHM=</PHRASE>
<PHRASE Label="la_fld_Username" Module="Core" Type="1">VXNlcm5hbWU=</PHRASE>
+ <PHRASE Label="la_fld_UseSecurityImage" Module="Core" Type="1">VXNlIFNlY3VyaXR5IEltYWdl</PHRASE>
<PHRASE Label="la_fld_VerifyPassword" Module="Core" Type="1">UmUtZW50ZXIgUGFzc3dvcmQ=</PHRASE>
<PHRASE Label="la_fld_Version" Module="Core" Type="1">VmVyc2lvbg==</PHRASE>
<PHRASE Label="la_fld_Visibility" Module="Core" Type="1">VmlzaWJpbGl0eQ==</PHRASE>
@@ -815,6 +859,8 @@
<PHRASE Label="la_hint_AllFiles" Module="Core" Type="1">QWxsIEZpbGVz</PHRASE>
<PHRASE Label="la_hint_CSVFiles" Module="Core" Type="1">Q1NWIEZpbGVz</PHRASE>
<PHRASE Label="la_hint_ImageFiles" Module="Core" Type="1">SW1hZ2UgRmlsZXM=</PHRASE>
+ <PHRASE Label="la_hint_PopPort" Module="Core" Type="1">UE9QMyBTZXJ2ZXIgUG9ydC4gRm9yIGV4LiAiMTEwIiBmb3IgcmVndWxhciBjb25uZWN0aW9uLCAiOTk1IiBmb3Igc2VjdXJlIGNvbm5lY3Rpb24u</PHRASE>
+ <PHRASE Label="la_hint_PopServer" Module="Core" Type="1">UE9QMyBTZXJ2ZXIgQWRkcmVzcy4gRm9yIGV4LiB1c2UgInNzbDovL3BvcC5nbWFpbC5jb20iIGZvciBHbWFpbCwgInBvcC5tYWlsLnlhaG9vLmNvbSIgZm9yIFlhaG9vLg==</PHRASE>
<PHRASE Label="la_Hot" Module="Core" Type="1">SG90</PHRASE>
<PHRASE Label="la_Html" Module="Core" Type="1">SFRNTA==</PHRASE>
<PHRASE Label="la_IDField" Module="Core" Type="1">SUQgRmllbGQ=</PHRASE>
@@ -880,6 +926,7 @@
<PHRASE Label="la_opt_After" Module="Core" Type="1">QWZ0ZXI=</PHRASE>
<PHRASE Label="la_opt_Allow" Module="Core" Type="1">QWxsb3c=</PHRASE>
<PHRASE Label="la_opt_Before" Module="Core" Type="1">QmVmb3Jl</PHRASE>
+ <PHRASE Label="la_opt_Bounce" Module="Core" Type="1">Qm91bmNlZA==</PHRASE>
<PHRASE Label="la_opt_Cancelled" Module="Core" Type="1">Q2FuY2VsZWQ=</PHRASE>
<PHRASE Label="la_opt_City" Module="Core" Type="1">Q2l0eQ==</PHRASE>
<PHRASE Label="la_opt_Colon" Module="Core" Type="1">Q29sb24=</PHRASE>
@@ -891,11 +938,15 @@
<PHRASE Label="la_opt_Description" Module="Core" Type="1">RGVzY3JpcHRpb24=</PHRASE>
<PHRASE Label="la_opt_Disabled" Module="Core" Type="1">RGlzYWJsZWQ=</PHRASE>
<PHRASE Label="la_opt_EditorsPick" Module="Core" Type="1">RWRpdG9yJ3MgUGljaw==</PHRASE>
- <PHRASE Label="la_opt_Email" Module="Core" Type="1">RW1haWw=</PHRASE>
+ <PHRASE Label="la_opt_Email" Module="Core" Type="1">RS1tYWls</PHRASE>
+ <PHRASE Label="la_opt_EmailBody" Module="Core" Type="1">RS1tYWlsIEJvZHk=</PHRASE>
+ <PHRASE Label="la_opt_EmailSubject" Module="Core" Type="1">RS1tYWlsIFN1YmplY3Q=</PHRASE>
+ <PHRASE Label="la_opt_Everyone" Module="Core" Type="1">RXZlcnlvbmU=</PHRASE>
<PHRASE Label="la_opt_Exact" Module="Core" Type="1">RXhhY3Q=</PHRASE>
<PHRASE Label="la_opt_Expired" Module="Core" Type="1">RXhwaXJlZA==</PHRASE>
<PHRASE Label="la_opt_Failed" Module="Core" Type="1">RmFpbGVk</PHRASE>
<PHRASE Label="la_opt_FirstName" Module="Core" Type="1">Rmlyc3QgTmFtZQ==</PHRASE>
+ <PHRASE Label="la_opt_GuestsOnly" Module="Core" Type="1">R3Vlc3RzIE9ubHk=</PHRASE>
<PHRASE Label="la_opt_hour" Module="Core" Type="1">aG91cihzKQ==</PHRASE>
<PHRASE Label="la_opt_InheritFromParent" Module="Core" Type="1">SW5oZXJpdCBmcm9tIFBhcmVudA==</PHRASE>
<PHRASE Label="la_opt_IP_Address" Module="Core" Type="1">SVAgQWRkcmVzcw==</PHRASE>
@@ -904,12 +955,17 @@
<PHRASE Label="la_opt_min" Module="Core" Type="1">bWludXRlKHMp</PHRASE>
<PHRASE Label="la_opt_ModalWindow" Module="Core" Type="1">TW9kYWwgV2luZG93</PHRASE>
<PHRASE Label="la_opt_month" Module="Core" Type="1">bW9udGgocyk=</PHRASE>
+ <PHRASE Label="la_opt_NewEmail" Module="Core" Type="1">TmV3IEUtbWFpbA==</PHRASE>
<PHRASE Label="la_opt_NotProcessed" Module="Core" Type="1">Tm90IFByb2Nlc3NlZA==</PHRASE>
+ <PHRASE Label="la_opt_NotReplied" Module="Core" Type="1">Tm90IFJlcGxpZWQ=</PHRASE>
<PHRASE Label="la_opt_PartiallyProcessed" Module="Core" Type="1">UGFydGlhbGx5IFByb2Nlc3NlZA==</PHRASE>
<PHRASE Label="la_opt_Phone" Module="Core" Type="1">UGhvbmU=</PHRASE>
<PHRASE Label="la_opt_PopupWindow" Module="Core" Type="1">UG9wdXAgV2luZG93</PHRASE>
<PHRASE Label="la_opt_Processed" Module="Core" Type="1">UHJvY2Vzc2Vk</PHRASE>
<PHRASE Label="la_opt_Rating" Module="Core" Type="1">UmF0aW5n</PHRASE>
+ <PHRASE Label="la_opt_RecipientEmail" Module="Core" Type="1">UmVjaXBpZW50IEUtbWFpbA==</PHRASE>
+ <PHRASE Label="la_opt_RecipientName" Module="Core" Type="1">UmVjaXBpZW50IE5hbWU=</PHRASE>
+ <PHRASE Label="la_opt_Replied" Module="Core" Type="1">UmVwbGllZA==</PHRASE>
<PHRASE Label="la_opt_Running" Module="Core" Type="1">UnVubmluZw==</PHRASE>
<PHRASE Label="la_opt_SameWindow" Module="Core" Type="1">U2FtZSBXaW5kb3c=</PHRASE>
<PHRASE Label="la_opt_sec" Module="Core" Type="1">c2Vjb25kKHMp</PHRASE>
@@ -1231,6 +1287,7 @@
<PHRASE Label="la_tab_ConfigSettings" Module="Core" Type="1">R2VuZXJhbA==</PHRASE>
<PHRASE Label="la_tab_Custom" Module="Core" Type="1">Q3VzdG9t</PHRASE>
<PHRASE Label="la_tab_E-mails" Module="Core" Type="1">RS1tYWlsIFRlbXBsYXRlcw==</PHRASE>
+ <PHRASE Label="la_tab_EmailCommunication" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24=</PHRASE>
<PHRASE Label="la_tab_EmailEvents" Module="Core" Type="1">RW1haWwgRXZlbnRz</PHRASE>
<PHRASE Label="la_tab_EmailLog" Module="Core" Type="1">RS1tYWlsIExvZw==</PHRASE>
<PHRASE Label="la_tab_EmailQueue" Module="Core" Type="1">RW1haWwgUXVldWU=</PHRASE>
@@ -1245,6 +1302,7 @@
<PHRASE Label="la_tab_ImportData" Module="Core" Type="1">SW1wb3J0IERhdGE=</PHRASE>
<PHRASE Label="la_tab_Items" Module="Core" Type="1">SXRlbXM=</PHRASE>
<PHRASE Label="la_tab_Labels" Module="Core" Type="1">TGFiZWxz</PHRASE>
+ <PHRASE Label="la_tab_Messages" Module="Core" Type="1">TWVzc2FnZXM=</PHRASE>
<PHRASE Label="la_tab_PackageContent" Module="Core" Type="1">UGFja2FnZSBDb250ZW50</PHRASE>
<PHRASE Label="la_tab_Permissions" Module="Core" Type="1">UGVybWlzc2lvbnM=</PHRASE>
<PHRASE Label="la_tab_Properties" Module="Core" Type="1">UHJvcGVydGllcw==</PHRASE>
@@ -1374,6 +1432,7 @@
<PHRASE Label="la_title_Agents" Module="Core" Type="1">QWdlbnRz</PHRASE>
<PHRASE Label="la_title_BaseStyles" Module="Core" Type="1">QmFzZSBTdHlsZXM=</PHRASE>
<PHRASE Label="la_title_BlockStyles" Module="Core" Type="1">QmxvY2sgU3R5bGVz</PHRASE>
+ <PHRASE Label="la_title_BounceSettings" Module="Core" Type="1">Qm91bmNlIFBPUDMgU2VydmVyIFNldHRpbmdz</PHRASE>
<PHRASE Label="la_title_Categories" Module="Core" Type="1">U2VjdGlvbnM=</PHRASE>
<PHRASE Label="la_title_category_select" Module="Core" Type="1">U2VsZWN0IHNlY3Rpb24=</PHRASE>
<PHRASE Label="la_title_ColumnPicker" Module="Core" Type="1">Q29sdW1uIFBpY2tlcg==</PHRASE>
@@ -1413,6 +1472,7 @@
<PHRASE Label="la_title_Editing_Stylesheet" Module="Core" Type="1">RWRpdGluZyBTdHlsZXNoZWV0</PHRASE>
<PHRASE Label="la_title_Editing_Theme" Module="Core" Type="1">RWRpdGluZyBUaGVtZQ==</PHRASE>
<PHRASE Label="la_title_Editing_User" Module="Core" Type="1">RWRpdGluZyBVc2Vy</PHRASE>
+ <PHRASE Label="la_title_EmailCommunication" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24=</PHRASE>
<PHRASE Label="la_title_EmailEvents" Module="Core" Type="1">RS1tYWlsIEV2ZW50cw==</PHRASE>
<PHRASE Label="la_title_EmailMessages" Module="Core" Type="1">RS1tYWlscw==</PHRASE>
<PHRASE Label="la_title_EmailSettings" Module="Core" Type="1">RS1tYWlsIFNldHRpbmdz</PHRASE>
@@ -1434,9 +1494,11 @@
<PHRASE Label="la_title_LanguagesManagement" Module="Core" Type="1">TGFuZ3VhZ2VzIE1hbmFnZW1lbnQ=</PHRASE>
<PHRASE Label="la_title_Loading" Module="Core" Type="1">TG9hZGluZyAuLi4=</PHRASE>
<PHRASE Label="la_title_MailingLists" Module="Core" Type="1">TWFpbGluZ3M=</PHRASE>
+ <PHRASE Label="la_title_Messages" Module="Core" Type="1">TWVzc2FnZXM=</PHRASE>
<PHRASE Label="la_title_Module_Status" Module="Core" Type="1">TW9kdWxlcw==</PHRASE>
<PHRASE Label="la_title_NewAgent" Module="Core" Type="1">TmV3IEFnZW50</PHRASE>
<PHRASE Label="la_title_NewFile" Module="Core" Type="1">TmV3IEZpbGU=</PHRASE>
+ <PHRASE Label="la_title_NewReply" Module="Core" Type="1">TmV3IFJlcGx5</PHRASE>
<PHRASE Label="la_title_NewTheme" Module="Core" Type="1">TmV3IFRoZW1l</PHRASE>
<PHRASE Label="la_title_NewThemeFile" Module="Core" Type="1">TmV3IFRoZW1lIFRlbXBsYXRl</PHRASE>
<PHRASE Label="la_title_New_BaseStyle" Module="Core" Type="1">TmV3IEJhc2UgU3R5bGU=</PHRASE>
@@ -1454,6 +1516,7 @@
<PHRASE Label="la_title_Properties" Module="Core" Type="1">UHJvcGVydGllcw==</PHRASE>
<PHRASE Label="la_title_RelatedSearches" Module="Core" Type="1">UmVsYXRlZCBTZWFyY2hlcw==</PHRASE>
<PHRASE Label="la_title_Relations" Module="Core" Type="1">UmVsYXRpb25z</PHRASE>
+ <PHRASE Label="la_title_ReplySettings" Module="Core" Type="1">UmVwbHkgUE9QMyBTZXJ2ZXIgU2V0dGluZ3M=</PHRASE>
<PHRASE Label="la_title_Reviews" Module="Core" Type="1">Q29tbWVudHM=</PHRASE>
<PHRASE Label="la_title_SelectGroup" Module="Core" Type="1">U2VsZWN0IEdyb3VwKHMp</PHRASE>
<PHRASE Label="la_title_SelectUser" Module="Core" Type="1">U2VsZWN0IFVzZXI=</PHRASE>
@@ -1471,6 +1534,7 @@
<PHRASE Label="la_title_Users" Module="Core" Type="1">VXNlcnM=</PHRASE>
<PHRASE Label="la_title_ViewingFormSubmission" Module="Core" Type="1">Vmlld2luZyBmb3JtIHN1Ym1pc3Npb24=</PHRASE>
<PHRASE Label="la_title_ViewingMailingList" Module="Core" Type="1">Vmlld2luZyBNYWlsaW5nIExpc3Q=</PHRASE>
+ <PHRASE Label="la_title_ViewingReply" Module="Core" Type="1">Vmlld2luZyBSZXBseQ==</PHRASE>
<PHRASE Label="la_title_Visits" Module="Core" Type="1">VmlzaXRz</PHRASE>
<PHRASE Label="la_title_Website" Module="Core" Type="1">V2Vic2l0ZQ==</PHRASE>
<PHRASE Label="la_ToolTipShort_Edit_Current_Category" Module="Core" Type="1">Q3Vyci4gU2VjdGlvbg==</PHRASE>
@@ -1537,12 +1601,15 @@
<PHRASE Label="la_ToolTip_RebuildCategoryCache" Module="Core" Type="1">UmVidWlsZCBTZWN0aW9uIENhY2hl</PHRASE>
<PHRASE Label="la_ToolTip_RecalculatePriorities" Module="Core" Type="1">UmVjYWxjdWxhdGUgUHJpb3JpdGllcw==</PHRASE>
<PHRASE Label="la_ToolTip_Refresh" Module="Core" Type="1">UmVmcmVzaA==</PHRASE>
+ <PHRASE Label="la_ToolTip_Reply" Module="Core" Type="1">UmVwbHk=</PHRASE>
<PHRASE Label="la_ToolTip_RescanThemes" Module="Core" Type="1">UmVzY2FuIFRoZW1lcw==</PHRASE>
+ <PHRASE Label="la_ToolTip_Resend" Module="Core" Type="1">UmVzZW5k</PHRASE>
<PHRASE Label="la_ToolTip_Reset" Module="Core" Type="1">UmVzZXQ=</PHRASE>
<PHRASE Label="la_ToolTip_ResetSettings" Module="Core" Type="1">UmVzZXQgUGVyc2lzdGVudCBTZXR0aW5ncw==</PHRASE>
<PHRASE Label="la_ToolTip_ResetToBase" Module="Core" Type="1">UmVzZXQgVG8gQmFzZQ==</PHRASE>
<PHRASE Label="la_ToolTip_RunSQL" Module="Core" Type="1">UnVuIFNRTA==</PHRASE>
<PHRASE Label="la_ToolTip_save" Module="Core" Type="1">U2F2ZQ==</PHRASE>
+ <PHRASE Label="la_ToolTip_SaveAsDraft" Module="Core" Type="1">U2F2ZSBhcyBEcmFmdA==</PHRASE>
<PHRASE Label="la_ToolTip_Search" Module="Core" Type="1">U2VhcmNo</PHRASE>
<PHRASE Label="la_ToolTip_SearchReset" Module="Core" Type="1">UmVzZXQ=</PHRASE>
<PHRASE Label="la_ToolTip_SelectUser" Module="Core" Type="1">U2VsZWN0IFVzZXI=</PHRASE>
@@ -1662,6 +1729,9 @@
<EVENT MessageType="html" Event="CATEGORY.APPROVE" Type="0">U3ViamVjdDogQSBjYXRlZ29yeSBoYXMgYmVlbiBhcHByb3ZlZAoKWW91ciBzdWdnZXN0ZWQgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYXBwcm92ZWQu</EVENT>
<EVENT MessageType="html" Event="CATEGORY.DENY" Type="0">U3ViamVjdDogWW91ciBDYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBEZW5pZWQKCllvdXIgY2F0ZWdvcnkgc3VnZ2VzdGlvbiAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBkZW5pZWQu</EVENT>
<EVENT MessageType="html" Event="COMMON.FOOTER" Type="1">U3ViamVjdDogQ29tbW9uIEZvb3RlciBUZW1wbGF0ZQoKPGJyLz48YnIvPg0KDQpTaW5jZXJlbHksPGJyLz48YnIvPg0KDQpXZWJzaXRlIGFkbWluaXN0cmF0aW9uLg==</EVENT>
+ <EVENT MessageType="html" Event="FORM.SUBMISSION.REPLY.FROM.USER" Type="1">U3ViamVjdDogTmV3IEVtYWlsIFJFUExZIFJlY2VpdmVkIGluICJGZWVkYmFjayBNYW5hZ2VyIiAoPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRmllbGQgbmFtZT0iRm9ybVN1Ym1pc3Npb25JZCIvPikKCk5ldyBFbWFpbCBSRVBMWSBSZWNlaXZlZCBpbiAmcXVvdDtGZWVkYmFjayBNYW5hZ2VyJnF1b3Q7LjxiciAvPg0KPGJyIC8+DQpPcmlnaW5hbCBGZWVkYmFja0lkOiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9GaWVsZCBuYW1lPSJGb3JtU3VibWlzc2lvbklkIi8+IDxiciAvPg0KT3JpZ2luYWwgU3ViamVjdDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRm9ybUZpZWxkIHJvbGU9InN1YmplY3QiLz4gPGJyIC8+DQo8YnIgLz4NClBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIGluIG9yZGVyIHRvIHJldmlldyBhbmQgcmVwbHkgdG8gdGhlIHVzZXIu</EVENT>
+ <EVENT MessageType="html" Event="FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED" Type="1">U3ViamVjdDogTmV3IEVtYWlsIC0gRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAiRmVlZGJhY2sgTWFuYWdlciIgKDxpbnAyOmZvcm1zdWJzLi1pdGVtX0ZpZWxkIG5hbWU9IkZvcm1TdWJtaXNzaW9uSWQiLz4pCgpOZXcgRW1haWwgRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAmcXVvdDtGZWVkYmFjayBNYW5hZ2VyJnF1b3Q7LjxiciAvPg0KPGJyIC8+DQpPcmlnaW5hbCBGZWVkYmFja0lkOiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9GaWVsZCBuYW1lPSJGb3JtU3VibWlzc2lvbklkIi8+IDxiciAvPg0KT3JpZ2luYWwgU3ViamVjdDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRm9ybUZpZWxkIHJvbGU9InN1YmplY3QiLz4gPGJyIC8+DQo8YnIgLz4NClBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIGluIG9yZGVyIHRvIHJldmlldyBhbmQgcmVwbHkgdG8gdGhlIHVzZXIu</EVENT>
+ <EVENT MessageType="html" Event="FORM.SUBMISSION.REPLY.TO.USER" Type="1">U3ViamVjdDogPGlucDI6bV9QYXJhbSBuYW1lPSJzdWJqZWN0Ii8+ICN2ZXJpZnk8aW5wMjpzdWJtaXNzaW9uLWxvZ19GaWVsZCBuYW1lPSJWZXJpZnlDb2RlIi8+Cgo8aW5wMjptX1BhcmFtIG5hbWU9Im1lc3NhZ2UiLz4=</EVENT>
<EVENT MessageType="html" Event="FORM.SUBMITTED" Type="0">U3ViamVjdDogVGhhbmsgWW91IGZvciBDb250YWN0aW5nIFVzIQoKPHA+VGhhbmsgeW91IGZvciBjb250YWN0aW5nIHVzLiBXZSdsbCBiZSBpbiB0b3VjaCB3aXRoIHlvdSBzaG9ydGx5ITwvcD4=</EVENT>
<EVENT MessageType="html" Event="FORM.SUBMITTED" Type="1">U3ViamVjdDogTmV3IGZvcm0gc3VibWlzc2lvbgoKPHA+Rm9ybSBoYXMgYmVlbiBzdWJtaXR0ZWQuIFBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIHRvIHJldmlldyB0aGUgc3VibWlzc2lvbiE8L3A+</EVENT>
<EVENT MessageType="html" Event="USER.ADD" Type="0">U3ViamVjdDogSW4tcG9ydGFsIHJlZ2lzdHJhdGlvbgoKRGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIgLz4gPGlucDI6dV9GaWVsZCBuYW1lPSJMYXN0TmFtZSIgLz4sDQoNClRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9CYXNlVXJsLz4uIFlvdXIgcmVnaXN0cmF0aW9uIGlzIG5vdyBhY3RpdmUu</EVENT>
Index: install/install_data.sql
===================================================================
--- install/install_data.sql (revision 13377)
+++ install/install_data.sql (working copy)
@@ -160,6 +160,9 @@
INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'COMMON.FOOTER', NULL, 1, 0, NULL, 'Core', 'Common Footer Template', 1);
INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, NULL, 'Core:Category', 'This e-mail is sent to a user after filling in the Contact Us form', 1);
INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, NULL, 'Core:Category', 'This e-mail is sent to a user after filling in the Contact Us form', 0);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.TO.USER', NULL, 1, 0, NULL, 'Core:Category', 'Admin Reply to User Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER', NULL, 1, 0, NULL, 'Core:Category', 'User Replied to It\'s Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED', NULL, 1, 0, NULL, 'Core:Category', 'Form Submission Admin Reply Delivery Failure', 1);
INSERT INTO IdGenerator VALUES ('100');
Index: install/install_schema.sql
===================================================================
--- install/install_schema.sql (revision 13377)
+++ install/install_schema.sql (working copy)
@@ -1064,28 +1064,101 @@
DisplayInGrid tinyint(1) NOT NULL DEFAULT '1',
DefaultValue text,
Validation tinyint(4) NOT NULL DEFAULT '0',
+ Visibility tinyint(4) NOT NULL DEFAULT '1',
+ EmailCommunicationRole tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (FormFieldId),
KEY `Type` (`Type`),
KEY FormId (FormId),
KEY Priority (Priority),
KEY IsSystem (IsSystem),
- KEY DisplayInGrid (DisplayInGrid)
+ KEY DisplayInGrid (DisplayInGrid),
+ KEY Visibility (Visibility),
+ KEY EmailCommunicationRole (EmailCommunicationRole)
);
CREATE TABLE FormSubmissions (
FormSubmissionId int(11) NOT NULL AUTO_INCREMENT,
FormId int(11) NOT NULL DEFAULT '0',
SubmissionTime int(11) DEFAULT NULL,
+ IPAddress varchar(15) NOT NULL DEFAULT '',
+ ReferrerURL varchar(255) NOT NULL DEFAULT '',
+ LogStatus tinyint(3) unsigned NOT NULL DEFAULT '2',
+ LastUpdatedOn int(10) unsigned DEFAULT NULL,
PRIMARY KEY (FormSubmissionId),
KEY FormId (FormId),
- KEY SubmissionTime (SubmissionTime)
+ KEY SubmissionTime (SubmissionTime),
+ KEY LogStatus (LogStatus),
+ KEY LastUpdatedOn (LastUpdatedOn)
);
+CREATE TABLE SubmissionLog (
+ SubmissionLogId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL,
+ FromEmail varchar(255) NOT NULL DEFAULT '',
+ ToEmail varchar(255) NOT NULL DEFAULT '',
+ Cc text,
+ Bcc text,
+ `Subject` varchar(255) NOT NULL DEFAULT '',
+ Message text,
+ Attachment text,
+ ReplyStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentOn int(10) unsigned DEFAULT NULL,
+ RepliedOn int(10) unsigned DEFAULT NULL,
+ VerifyCode varchar(32) NOT NULL DEFAULT '',
+ DraftId int(10) unsigned NOT NULL DEFAULT '0',
+ MessageId varchar(255) NOT NULL DEFAULT '',
+ BounceInfo text,
+ BounceDate int(11) DEFAULT NULL,
+ PRIMARY KEY (SubmissionLogId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY ReplyStatus (ReplyStatus),
+ KEY SentStatus (SentStatus),
+ KEY SentOn (SentOn),
+ KEY RepliedOn (RepliedOn),
+ KEY VerifyCode (VerifyCode),
+ KEY DraftId (DraftId),
+ KEY BounceDate (BounceDate),
+ KEY MessageId (MessageId)
+);
+
+CREATE TABLE Drafts (
+ DraftId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL DEFAULT '0',
+ CreatedOn int(10) unsigned DEFAULT NULL,
+ CreatedById int(11) NOT NULL,
+ Message text,
+ PRIMARY KEY (DraftId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY CreatedOn (CreatedOn),
+ KEY CreatedById (CreatedById)
+);
+
CREATE TABLE Forms (
- FormId int(11) NOT NULL auto_increment,
- Title VARCHAR(255) NOT NULL DEFAULT '',
+ FormId int(11) NOT NULL AUTO_INCREMENT,
+ Title varchar(255) NOT NULL DEFAULT '',
Description text,
- PRIMARY KEY (FormId)
+ RequireLogin tinyint(4) NOT NULL DEFAULT '0',
+ UseSecurityImage tinyint(4) NOT NULL DEFAULT '0',
+ EnableEmailCommunication tinyint(4) NOT NULL DEFAULT '0',
+ ReplyFromName varchar(255) NOT NULL DEFAULT '',
+ ReplyFromEmail varchar(255) NOT NULL DEFAULT '',
+ ReplyCc varchar(255) NOT NULL DEFAULT '',
+ ReplyBcc varchar(255) NOT NULL DEFAULT '',
+ ReplyMessageSignature text NOT NULL,
+ ReplyServer varchar(255) NOT NULL DEFAULT '',
+ ReplyPort int(11) NOT NULL DEFAULT '110',
+ ReplyUsername varchar(255) NOT NULL DEFAULT '',
+ ReplyPassword varchar(255) NOT NULL DEFAULT '',
+ BounceEmail varchar(255) NOT NULL DEFAULT '',
+ BounceServer varchar(255) NOT NULL DEFAULT '',
+ BouncePort int(11) NOT NULL DEFAULT '110',
+ BounceUsername varchar(255) NOT NULL DEFAULT '',
+ BouncePassword varchar(255) NOT NULL DEFAULT '',
+ PRIMARY KEY (FormId),
+ KEY UseSecurityImage (UseSecurityImage),
+ KEY RequireLogin (RequireLogin),
+ KEY EnableEmailCommunication (EnableEmailCommunication)
);
CREATE TABLE Semaphores (
Index: install/remove_schema.sql
===================================================================
--- install/remove_schema.sql (revision 13377)
+++ install/remove_schema.sql (working copy)
@@ -65,6 +65,8 @@
DROP TABLE PageContent;
DROP TABLE FormFields;
DROP TABLE FormSubmissions;
+DROP TABLE SubmissionLog;
+DROP TABLE Drafts;
DROP TABLE Forms;
DROP TABLE Semaphores;
DROP TABLE CachedUrls;
Index: install/upgrades.sql
===================================================================
--- install/upgrades.sql (revision 13377)
+++ install/upgrades.sql (working copy)
@@ -1710,4 +1710,87 @@
cv.GroupDisplayOrder = (SELECT ca7.GroupDisplayOrder FROM <%TABLE_PREFIX%>ConfigurationAdmin ca7 WHERE ca7.VariableName = cv.VariableName),
cv.`Install` = (SELECT ca8.`Install` FROM <%TABLE_PREFIX%>ConfigurationAdmin ca8 WHERE ca8.VariableName = cv.VariableName);
-DROP TABLE ConfigurationAdmin;
\ No newline at end of file
+DROP TABLE ConfigurationAdmin;
+
+ALTER TABLE Forms
+ ADD RequireLogin TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (RequireLogin),
+ ADD UseSecurityImage TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (UseSecurityImage),
+ ADD EnableEmailCommunication TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (EnableEmailCommunication),
+ ADD ReplyFromName VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyFromEmail VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyCc VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyBcc VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyMessageSignature TEXT NOT NULL,
+ ADD ReplyServer VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyPort INT(10) NOT NULL DEFAULT '110',
+ ADD ReplyUsername VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyPassword VARCHAR(255) NOT NULL DEFAULT ''
+ ADD BounceEmail VARCHAR(255) NOT NULL DEFAULT '',
+ ADD BounceServer VARCHAR(255) NOT NULL DEFAULT '',
+ ADD BouncePort INT(10) NOT NULL DEFAULT '110',
+ ADD BounceUsername VARCHAR(255) NOT NULL DEFAULT '',
+ ADD BouncePassword VARCHAR(255) NOT NULL DEFAULT '';
+
+ALTER TABLE FormFields
+ ADD Visibility TINYINT NOT NULL DEFAULT '1',
+ ADD INDEX (Visibility),
+ ADD EmailCommunicationRole TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (EmailCommunicationRole);
+
+ALTER TABLE FormSubmissions
+ ADD IPAddress VARCHAR(15) NOT NULL DEFAULT '' AFTER SubmissionTime,
+ ADD ReferrerURL VARCHAR(255) NOT NULL DEFAULT '' AFTER IPAddress,
+ ADD LogStatus TINYINT UNSIGNED NOT NULL DEFAULT '2' AFTER ReferrerURL,
+ ADD LastUpdatedOn INT UNSIGNED NULL AFTER LogStatus,
+ ADD INDEX (LogStatus),
+ ADD INDEX (LastUpdatedOn);
+
+CREATE TABLE SubmissionLog (
+ SubmissionLogId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL,
+ FromEmail varchar(255) NOT NULL DEFAULT '',
+ ToEmail varchar(255) NOT NULL DEFAULT '',
+ Cc text,
+ Bcc text,
+ `Subject` varchar(255) NOT NULL DEFAULT '',
+ Message text,
+ Attachment text,
+ ReplyStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentOn int(10) unsigned DEFAULT NULL,
+ RepliedOn int(10) unsigned DEFAULT NULL,
+ VerifyCode varchar(32) NOT NULL DEFAULT '',
+ DraftId int(10) unsigned NOT NULL DEFAULT '0',
+ MessageId varchar(255) NOT NULL DEFAULT '',
+ BounceInfo text,
+ BounceDate int(11) DEFAULT NULL,
+ PRIMARY KEY (SubmissionLogId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY ReplyStatus (ReplyStatus),
+ KEY SentStatus (SentStatus),
+ KEY SentOn (SentOn),
+ KEY RepliedOn (RepliedOn),
+ KEY VerifyCode (VerifyCode),
+ KEY DraftId (DraftId),
+ KEY BounceDate (BounceDate),
+ KEY MessageId (MessageId)
+);
+
+CREATE TABLE Drafts (
+ DraftId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL DEFAULT '0',
+ CreatedOn int(10) unsigned DEFAULT NULL,
+ CreatedById int(11) NOT NULL,
+ Message text,
+ PRIMARY KEY (DraftId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY CreatedOn (CreatedOn),
+ KEY CreatedById (CreatedById)
+);
+
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.TO.USER', NULL, 1, 0, NULL, 'Core:Category', 'Admin Reply to User Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER', NULL, 1, 0, NULL, 'Core:Category', 'User Replied to It\'s Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED', NULL, 1, 0, NULL, 'Core:Category', 'Form Submission Admin Reply Delivery Failure', 1);
\ No newline at end of file
Index: kernel/constants.php
===================================================================
--- kernel/constants.php (revision 13377)
+++ kernel/constants.php (working copy)
@@ -129,3 +129,28 @@
define('SESSION_LOG_ACTIVE', 0);
define('SESSION_LOG_LOGGED_OUT', 1);
define('SESSION_LOG_EXPIRED', 2);
+
+ // form field visibility
+ define('FORM_FIELD_EVERYONE', 1);
+ define('FORM_FIELD_UNREGISTERED', 2);
+
+ // form field e-mail communication roles
+ define('EMAIL_COMMUNICATION_ROLE_NAME', 1);
+ define('EMAIL_COMMUNICATION_ROLE_EMAIL', 2);
+ define('EMAIL_COMMUNICATION_ROLE_SUBJECT', 3);
+ define('EMAIL_COMMUNICATION_ROLE_BODY', 4);
+
+ // form submission statuses
+ define('SUBMISSION_REPLIED', 1); // submission was replied by admin
+ define('SUBMISSION_NOT_REPLIED', 2); // submission has no client replies (no messages at all)
+ define('SUBMISSION_NEW_EMAIL', 3); // submission have new reply/email from client
+ define('SUBMISSION_BOUNCE', 4); // submission have bounce from client
+
+ // submission log statuses
+ define('SUBMISSION_LOG_SENT', 1);
+ define('SUBMISSION_LOG_BOUNCE', 2);
+ define('SUBMISSION_LOG_REPLIED', 1);
+
+ define('SUBMISSION_LOG_ATTACHMENT_PATH', WRITEBALE_BASE . '/user_files/submission_log/');
+
+ define('TIMENOW', adodb_mktime()); // for faster message processing
\ No newline at end of file
Index: units/drafts/draft_eh.php
===================================================================
--- units/drafts/draft_eh.php (revision 0)
+++ units/drafts/draft_eh.php (revision 0)
@@ -0,0 +1,43 @@
+<?php
+
+ class DraftEventHandler extends kDBEventHandler
+ {
+
+ /**
+ * Sets user, who created draft
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $user_id = $this->Application->RecallVar('user_id');
+
+ $object->SetDBField('CreatedById', $user_id);
+ }
+
+ /**
+ * Allows to load draft, that best matches given form submission
+ *
+ * @param kEvent $event
+ * @return int
+ */
+ function getPassedID(&$event)
+ {
+ if ($event->Special == 'related') {
+ $form_submission =& $this->Application->recallObject('formsubs');
+ /* @var $form_submission kDBItem */
+
+ return Array (
+ 'FormSubmissionId' => $form_submission->GetID(),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+ }
+
+ return parent::getPassedID($event);
+ }
+ }
\ No newline at end of file
Index: units/drafts/drafts_config.php
===================================================================
--- units/drafts/drafts_config.php (revision 0)
+++ units/drafts/drafts_config.php (revision 0)
@@ -0,0 +1,48 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => 'draft',
+ 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
+ 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
+ 'EventHandlerClass' => Array ('class' => 'DraftEventHandler', 'file' => 'draft_eh.php', 'build_event' => 'OnBuild'),
+ 'TagProcessorClass' => Array ('class' => 'kDBTagProcessor', 'file' => '', 'build_event' => 'OnBuild'),
+
+ 'AutoLoad' => true,
+
+ 'QueryString' => Array (
+ 1 => 'id',
+ 2 => 'Page',
+ 3 => 'event',
+ 4 => 'mode',
+ ),
+
+ 'IDField' => 'DraftId',
+
+ 'ParentPrefix' => 'formsubs',
+ 'ForeignKey' => 'FormSubmissionId',
+ 'ParentTableKey' => 'FormSubmissionId',
+ 'AutoDelete' => true,
+ 'AutoClone' => true,
+
+ 'TableName' => TABLE_PREFIX . 'Drafts',
+
+ 'TitleField' => 'DraftId',
+
+ 'ListSQLs' => Array (
+ '' => ' SELECT %1$s.* %2$s FROM %1$s',
+ ),
+
+ 'ListSortings' => Array (
+ '' => Array (
+ 'Sorting' => Array ('DraftId' => 'desc'),
+ )
+ ),
+
+ 'Fields' => Array (
+ 'DraftId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'FormSubmissionId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'CreatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
+ 'CreatedById' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'Message' => Array ('type' => 'string', 'default' => NULL),
+ ),
+ );
\ No newline at end of file
Index: units/form_fields/form_field_eh.php
===================================================================
--- units/form_fields/form_field_eh.php (revision 0)
+++ units/form_fields/form_field_eh.php (revision 0)
@@ -0,0 +1,35 @@
+<?php
+
+ class FormFieldEventHandler extends kDBEventHandler {
+
+ /**
+ * Returns form field visibility filter
+ *
+ * @return string
+ */
+ function getVisiblilityFilter()
+ {
+ if ($this->Application->LoggedIn() && !$this->Application->isAdminUser) {
+ return '%1$s.Visibility = ' . FORM_FIELD_EVERYONE;
+ }
+
+ return '';
+ }
+
+ /**
+ * Shows fields based on user logged-in status
+ *
+ * @param kEvent $event
+ */
+ function SetCustomQuery(&$event)
+ {
+ parent::SetCustomQuery($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBList */
+
+ $visibility_filter = $this->getVisiblilityFilter();
+
+ $object->addFilter('visibility_filter', $visibility_filter);
+ }
+ }
Index: units/form_fields/form_fields_config.php
===================================================================
--- units/form_fields/form_fields_config.php (revision 13377)
+++ units/form_fields/form_fields_config.php (working copy)
@@ -18,7 +18,7 @@
'Prefix' => 'formflds',
'ItemClass' => Array('class'=>'kDBItem','file'=>'','build_event'=>'OnItemBuild'),
'ListClass' => Array('class'=>'kDBList','file'=>'','build_event'=>'OnListBuild'),
- 'EventHandlerClass' => Array('class'=>'kDBEventHandler','file'=>'','build_event'=>'OnBuild'),
+ 'EventHandlerClass' => Array('class'=>'FormFieldEventHandler','file'=>'form_field_eh.php','build_event'=>'OnBuild'),
'TagProcessorClass' => Array('class'=>'FormFieldsTagProcessor','file'=>'form_fields_tp.php'),
'AutoLoad' => true,
'QueryString' => Array(
@@ -77,6 +77,16 @@
'DisplayInGrid' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array(0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1),
'DefaultValue' => Array('type' => 'string', 'default' => NULL),
'Validation' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array(0 => 'la_None', 1 => 'la_ValidationEmail'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0),
+ 'Visibility' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_Everyone', 2 => 'la_opt_GuestsOnly'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 1
+ ),
+ 'EmailCommunicationRole' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_RecipientName', 2 => 'la_opt_RecipientEmail', 3 => 'la_opt_EmailSubject', 4 => 'la_opt_EmailBody'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
),
'VirtualFields' => Array(
@@ -96,6 +106,8 @@
'ElementType' => Array('title' => 'la_prompt_ElementType', 'filter_block' => 'grid_options_filter'),
'Required' => Array('title' => 'la_prompt_Required', 'filter_block' => 'grid_options_filter'),
'DisplayInGrid' => Array('title' => 'la_prompt_DisplayInGrid', 'filter_block' => 'grid_options_filter', 'width' => 150 ),
+ 'Visibility' => Array('title' => 'la_col_Visibility', 'filter_block' => 'grid_options_filter', 'width' => 100),
+ 'EmailCommunicationRole' => Array('title' => 'la_col_EmailCommunicationRole', 'filter_block' => 'grid_options_filter', 'width' => 150),
),
),
),
Index: units/form_fields/form_fields_tp.php
===================================================================
--- units/form_fields/form_fields_tp.php (revision 13377)
+++ units/form_fields/form_fields_tp.php (working copy)
@@ -45,7 +45,17 @@
*/
function PrepareListElementParams(&$object, &$block_params)
{
- $object->SetDBField('DirectOptions', false);
+ if (!array_key_exists('SourcePrefix', $block_params)) {
+ // don't have source prefix in administrative console
+ $object->SetDBField('DirectOptions', false);
+ return ;
+ }
+
+ $submission =& $this->Application->recallObject( $block_params['SourcePrefix'] );
+ /* @var $submission kDBItem */
+
+ $options = $submission->GetFieldOptions('fld_' . $object->GetID());
+ $object->SetDBField('DirectOptions', array_key_exists('options', $options) ? $options['options'] : false);
}
}
\ No newline at end of file
Index: units/form_submissions/form_submission_tp.php
===================================================================
--- units/form_submissions/form_submission_tp.php (revision 13377)
+++ units/form_submissions/form_submission_tp.php (working copy)
@@ -19,4 +19,28 @@
return $this->Application->Phrase($phrase_name);
}
+
+ /**
+ * Allows to retrieve for submission field by it's name or role in email communications
+ *
+ * @param Array $params
+ * @return string
+ */
+ function FormField($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $formatted = !(array_key_exists('db', $params) && $params['db']);
+ $format = $formatted ? (array_key_exists('format', $params) ? $params['format'] : null) : null;
+
+ if (array_key_exists('role', $params)) {
+ return $form_submission_helper->getFieldByRole($object, $params['role'], $formatted, $format);
+ }
+
+ return $form_submission_helper->getFieldByName($params['name'], $formatted, $format);
+ }
}
Index: units/form_submissions/form_submissions_config.php
===================================================================
--- units/form_submissions/form_submissions_config.php (revision 13377)
+++ units/form_submissions/form_submissions_config.php (working copy)
@@ -32,39 +32,70 @@
Array(
'Mode' => hAFTER,
'Conditional' => false,
- 'HookToPrefix' => 'formsubs', //self
+ 'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnAfterConfigRead'),
'DoPrefix' => '',
'DoSpecial' => '',
'DoEvent' => 'OnBuildFormFields',
),
- ),
- 'TitlePresets' => Array(
- 'default' => Array( 'new_status_labels' => Array('form'=>'!la_title_Adding_Form!'),
- 'edit_status_labels' => Array('form'=>'!la_title_Editing_Form!'),
- 'new_titlefield' => Array('form'=>''),
+ // Captcha processing
+ Array (
+ 'Mode' => hAFTER,
+ 'Conditional' => false,
+ 'HookToPrefix' => '',
+ 'HookToSpecial' => '*',
+ 'HookToEvent' => Array('OnAfterConfigRead'),
+ 'DoPrefix' => 'captcha',
+ 'DoSpecial' => '*',
+ 'DoEvent' => 'OnPrepareCaptcha',
+ ),
),
+ 'TitlePresets' => Array(
+ 'default' => Array(
+ 'new_status_labels' => Array('form'=>'!la_title_Adding_Form!'),
+ 'edit_status_labels' => Array('form'=>'!la_title_Editing_Form!'),
+ ),
+
'formsubs_list' => Array (
- 'prefixes' => Array('form', 'formsubs_List'),
- 'format' => "!la_title_FormSubmissions! '#form_titlefield#'",
- 'toolbar_buttons' => Array ('edit', 'delete', 'dbl-click'),
- ),
+ 'prefixes' => Array('form', 'formsubs_List'),
+ 'format' => "!la_title_FormSubmissions! '#form_titlefield#'",
+ 'toolbar_buttons' => Array ('edit', 'delete', 'dbl-click'),
+ ),
'formsubs_view' => Array(
- 'prefixes' => Array('formsubs'),
- 'format' => "!la_title_ViewingFormSubmission!",
- 'toolbar_buttons' => Array ('cancel', 'prev', 'next'),
- ),
+ 'prefixes' => Array('formsubs'),
+ 'format' => "!la_title_ViewingFormSubmission!",
+ 'toolbar_buttons' => Array ('cancel', 'prev', 'next'),
+ ),
- ),
+ 'submission_edit_logs' => Array (
+ 'prefixes' => Array ('formsubs', 'submission-log_List'),
+ 'format' => "!la_title_ViewingFormSubmission! - !la_title_Messages! (#submission-log_recordcount#)"
+ ),
+ 'submission_log_edit' => Array (
+ 'new_status_labels' => Array ('submission-log' => '!la_title_NewReply!'),
+ 'edit_status_labels' => Array ('submission-log' => '!la_title_ViewingReply!'),
+
+ 'prefixes' => Array ('submission-log'), 'format' => "!la_title_ViewingFormSubmission! - #submission-log_status#"
+ ),
+ ),
+
+ 'EditTabPresets' => Array (
+ 'Default' => Array (
+ Array ('title' => 'la_tab_General', 't' => 'submissions/submission_view', 'priority' => 1),
+ Array ('title' => 'la_tab_Messages', 't' => 'submissions/submission_edit_logs', 'priority' => 2),
+ ),
+ ),
+
'PermSection' => Array('main' => 'in-portal:submissions'),
'IDField' => 'FormSubmissionId',
/*'TitleField' => 'Name',*/
+ 'StatusField' => Array ('LogStatus'),
'TableName' => TABLE_PREFIX.'FormSubmissions',
'ListSQLs' => Array(
''=>' SELECT %1$s.* %2$s FROM %1$s',
@@ -79,16 +110,28 @@
'AutoDelete' => true,
'AutoClone' => true,*/
+ 'SubItems' => Array ('submission-log', 'draft'),
+
'ListSortings' => Array(
'' => Array(
'Sorting' => Array('SubmissionTime' => 'desc'),
)
),
- 'Fields' => Array(
- 'FormSubmissionId' => Array('type' => 'int', 'not_null' => 1,'default' => 0),
- 'FormId' => Array('type' => 'int','not_null' => '1','default' => 0),
- 'SubmissionTime' => Array('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
+ 'Fields' => Array(
+ 'FormSubmissionId' => Array('type' => 'int', 'not_null' => 1,'default' => 0),
+ 'FormId' => Array('type' => 'int','not_null' => '1','default' => 0),
+ 'SubmissionTime' => Array('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
+ 'IPAddress' => Array ('type' => 'string', 'max_len' => 15, 'not_null' => 1, 'default' => ''),
+ 'ReferrerURL' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+
+ 'LogStatus' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_Replied', 2 => 'la_opt_NotReplied', 3 => 'la_opt_NewEmail', 4 => 'la_opt_Bounce'), 'use_phrases' => 1,
+ 'not_null' => 1, 'required' => 1, 'default' => 2
+ ),
+
+ 'LastUpdatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
),
'VirtualFields' => Array(
),
@@ -96,10 +139,14 @@
),
'Grids' => Array(
'Default' => Array(
- 'Icons' => Array('default' => 'icon16_item.png'),
+ 'Icons' => Array('default' => 'icon16_item.png', 1 => 'icon16_replied.gif', 2 => 'icon16_not_replied.gif', 3 => 'icon16_new_email.gif', 4 => 'icon16_bounce.gif'),
'Fields' => Array(
'FormSubmissionId' => Array( 'title'=>'la_col_Id', 'data_block' => 'grid_checkbox_td', 'sort_field' => 'FormFieldId', 'filter_block' => 'grid_range_filter', 'width' => 60 ),
'SubmissionTime' => Array( 'title'=>'la_prompt_SumbissionTime', 'filter_block' => 'grid_date_range_filter', 'width' => 145 ),
+ 'IPAddress' => Array ('title' => 'la_col_IPAddress', 'filter_block' => 'grid_like_filter', 'width' => 100 ),
+ 'ReferrerURL' => Array ('title' => 'la_col_ReferrerURL', 'filter_block' => 'grid_like_filter', 'first_chars' => 100, 'width' => 200 ),
+ 'LogStatus' => Array ('title' => 'la_col_Status', 'filter_block' => 'grid_options_filter', 'width' => 100 ),
+ 'LastUpdatedOn' => Array ('title' => 'la_col_LastUpdatedOn', 'filter_block' => 'grid_date_range_filter', 'width' => 145 ),
),
),
),
Index: units/form_submissions/form_submissions_eh.php
===================================================================
--- units/form_submissions/form_submissions_eh.php (revision 13377)
+++ units/form_submissions/form_submissions_eh.php (working copy)
@@ -24,15 +24,28 @@
return true;
}
}
+
+ $section = $event->getSection();
+ $form_id = $this->Application->GetVar('form_id');
+
+ $event->setEventParam('PermSection', $section . ':' . $form_id);
+
return parent::CheckPermission($event);
}
+ /**
+ * Always allow to view feedback form
+ *
+ */
function mapPermissions()
{
parent::mapPermissions();
+
$permissions = Array(
- 'OnEdit' => Array('self' => 'view', 'subitem' => 'view'),
+ 'OnItemBuild' => Array ('self' => true),
+ 'OnEdit' => Array ('self' => 'view', 'subitem' => 'view'),
);
+
$this->permMapping = array_merge($this->permMapping, $permissions);
}
@@ -66,6 +79,7 @@
$conf_grids = $this->Application->getUnitOption($event->Prefix, 'Grids');
$helper =& $this->Application->recallObject('InpCustomFieldsHelper');
+ /* @var $helper InpCustomFieldsHelper */
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'FormFields
@@ -73,36 +87,58 @@
ORDER BY Priority DESC';
$fields = $this->Conn->Query($sql, 'FormFieldId');
+ $use_options = Array ('radio', 'select', 'checkbox');
+ $check_visibility = $this->Application->LoggedIn() && !$this->Application->isAdminUser;
+
foreach ($fields as $field_id => $options) {
- $conf_fields['fld_'.$field_id] = Array('type'=>'string', 'default'=>$options['DefaultValue']);
- if ($options['Required']) {
- $conf_fields['fld_'.$field_id]['required'] = 1;
+ $field_visible = $check_visibility ? $options['Visibility'] == FORM_FIELD_EVERYONE : true;
+ $field_options = Array('type' => 'string', 'default' => $options['DefaultValue']);
+
+ if ($options['Required'] && $field_visible) {
+ $field_options['required'] = 1;
}
+
if ($options['Validation'] == 1) {
- $conf_fields['fld_'.$field_id]['formatter'] = 'kFormatter';
- $conf_fields['fld_'.$field_id]['regexp'] = '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i';
+ $field_options['formatter'] = 'kFormatter';
+ $field_options['regexp'] = '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i';
}
+
if ($options['DisplayInGrid']) {
$title = $options['Prompt'];
- if (substr($title, 0,1) == '+') {
- $this->Application->Phrases->AddCachedPhrase('form_col_title'.$field_id, substr($title,1));
- $title = 'form_col_title'.$field_id;
+
+ if (substr($title, 0, 1) == '+') {
+ $this->Application->Phrases->AddCachedPhrase('form_col_title' . $field_id, substr($title, 1));
+ $title = 'form_col_title' . $field_id;
}
- $conf_grids['Default']['Fields']['fld_'.$field_id] = Array('title'=>$title, 'no_special' => 1, 'nl2br' => 1, 'first_chars' => 200, 'filter_block' => $this->_getFilterBlock($options['ElementType']));
- if ($options['Validation'] == 1)
- {
- $conf_grids['Default']['Fields']['fld_'.$field_id]['data_block'] = 'grid_email_td';
+
+ $conf_grids['Default']['Fields']['fld_' . $field_id] = Array (
+ 'title' => $title, 'no_special' => 1, 'nl2br' => 1, 'first_chars' => 200,
+ 'filter_block' => $this->_getFilterBlock($options['ElementType'])
+ );
+
+ if ($options['Validation'] == 1) {
+ $conf_grids['Default']['Fields']['fld_' . $field_id]['data_block'] = 'grid_email_td';
}
}
- if ($options['ElementType'] == 'radio' || $options['ElementType'] == 'select') {
- $conf_fields['fld_'.$field_id]['options'] = $helper->GetValuesHash( $options['ValueList'] );
- $conf_fields['fld_'.$field_id]['formatter'] = 'kOptionsFormatter';
+
+ if ($options['ElementType'] == 'checkbox' && !$options['ValueList']) {
+ // fix case, when user haven't defined any options for checkbox
+ $options['ValueList'] = '1=la_Yes||0=la_No';
}
+
+ if (in_array($options['ElementType'], $use_options) && $options['ValueList']) {
+ // field type can have options and user have defined them too
+ $field_options['options'] = $helper->GetValuesHash( $options['ValueList'] );
+ $field_options['formatter'] = 'kOptionsFormatter';
+ }
+
if ($options['ElementType'] == 'password') {
- $conf_fields['fld_'.$field_id]['formatter'] = 'kPasswordFormatter';
- $conf_fields['fld_'.$field_id]['encryption_method'] = 'plain';
- $conf_fields['fld_'.$field_id]['verify_field'] = 'fld_'.$field_id.'_verify';
+ $field_options['formatter'] = 'kPasswordFormatter';
+ $field_options['encryption_method'] = 'plain';
+ $field_options['verify_field'] = 'fld_' . $field_id . '_verify';
}
+
+ $conf_fields['fld_' . $field_id] = $field_options;
}
$this->Application->setUnitOption($event->Prefix, 'Fields', $conf_fields);
@@ -116,14 +152,26 @@
$object->addFilter('form_filter','%1$s.FormId = '.$form_id);
}
+ /**
+ * Allows user to see it's last feedback form data
+ *
+ * @param kEvent $event
+ * @return int
+ */
function getPassedID(&$event)
{
- if (!$this->Application->isAdminUser) {
- // no way to see other user's form submission by giving it's ID directly in url
- return 0;
+ if ($event->Special == 'last') {
+ // allow user to see his last submitted form
+ return $this->Application->RecallVar('last_submission_id');
}
- return parent::getPassedID($event);
+ if ($this->Application->isAdminUser) {
+ // don't check ids in admin
+ return parent::getPassedID($event);
+ }
+
+ // no way to see other user's form submission by giving it's ID directly in url
+ return 0;
}
/**
@@ -139,6 +187,12 @@
return ;
}
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ // allows user to view only it's last submission
+ $this->Application->StoreVar('last_submission_id', $object->GetID());
+
$this->Application->EmailEventAdmin('FORM.SUBMITTED');
// $this->Application->EmailEventUser('FORM.SUBMITTED', null, 'to_email' => '');
@@ -153,4 +207,62 @@
$event->redirect = $alias_template ? $alias_template : $template;
}
+
+ /**
+ * Processes Captcha code
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $object->SetDBField('IPAddress', $_SERVER['REMOTE_ADDR']);
+ $object->SetDBField('ReferrerURL', $_SERVER['HTTP_REFERER']);
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($object);
+
+ // validate captcha code
+ if ($form->GetDBField('UseSecurityImage') && !$this->Application->LoggedIn()) {
+ $captcha_helper =& $this->Application->recallObject('CaptchaHelper');
+ /* @var $captcha_helper kCaptchaHelper */
+
+ $captcha_helper->validateCode($event, false);
+ }
+ }
+
+ /**
+ * Passes form_id, when using "Prev"/"Next" toolbar buttons
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGo(&$event)
+ {
+ parent::OnPreSaveAndGo($event);
+
+ if ($event->status == erSUCCESS) {
+ $event->SetRedirectParam('pass', 'm,form,formsubs');
+ }
+ }
+
+ /**
+ * Saves edited item in temp table and goes
+ * to passed tabs, by redirecting to it with OnPreSave event
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGoToTab(&$event)
+ {
+ parent::OnPreSaveAndGoToTab($event);
+
+ if ($event->status == erSUCCESS) {
+ $event->SetRedirectParam('pass', 'm,form,formsubs');
+ }
+ }
}
\ No newline at end of file
Index: units/forms/forms_config.php
===================================================================
--- units/forms/forms_config.php (revision 13377)
+++ units/forms/forms_config.php (working copy)
@@ -20,6 +20,7 @@
'ListClass' => Array('class'=>'kDBList','file'=>'','build_event'=>'OnListBuild'),
'EventHandlerClass' => Array('class'=>'FormsEventHandler','file'=>'forms_eh.php','build_event'=>'OnBuild'),
'TagProcessorClass' => Array('class'=>'FormsTagProcessor','file'=>'forms_tp.php','build_event'=>'OnBuild'),
+
'AutoLoad' => true,
'QueryString' => Array(
1 => 'id',
@@ -28,6 +29,12 @@
4 => 'event',
5 => 'mode',
),
+
+ 'RegularEvents' => Array (
+ 'check_submission_repies' => Array('EventName' => 'OnProcessReplies', 'RunInterval' => 3600, 'Type' => reAFTER),
+ 'check_bounced_submission_repies' => Array('EventName' => 'OnProcessBouncedReplies', 'RunInterval' => 18000, 'Type' => reAFTER),
+ ),
+
'Hooks' => Array(
Array(
'Mode' => hAFTER,
@@ -82,6 +89,12 @@
'toolbar_buttons' => Array('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'move_up', 'move_down', 'view', 'dbl-click'),
),
+ 'form_edit_emails' => Array (
+ 'prefixes' => Array('form'),
+ 'format' => "#form_status# '#form_titlefield#' - !la_title_EmailCommunication!",
+ 'toolbar_buttons' => Array('select', 'cancel', 'prev', 'next'),
+ ),
+
'form_field_edit' => Array (
'prefixes' => Array('form', 'formflds'),
'new_status_labels' => Array('formflds'=>"!la_title_Adding_FormField!"),
@@ -100,6 +113,7 @@
'Default' => Array (
'general' => Array ('title' => 'la_tab_General', 't' => 'forms/forms_edit', 'priority' => 1),
'fields' => Array ('title' => 'la_tab_Fields', 't' => 'forms/forms_edit_fields', 'priority' => 2),
+ 'emails' => Array ('title' => 'la_tab_EmailCommunication', 't' => 'forms/form_edit_emails', 'priority' => 3),
),
),
@@ -118,10 +132,65 @@
)
),
- 'Fields' => Array(
+ 'Fields' => Array(
'FormId' => Array('type' => 'int', 'not_null' => 1, 'default' => 0, 'filter_type' => 'equals'),
'Title' => Array('type' => 'string','not_null' => 1, 'default' => '','required' => 1),
'Description' => Array('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null),
+ 'RequireLogin' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
+ 'UseSecurityImage' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
+ 'EnableEmailCommunication' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
+ 'ReplyFromName' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyFromEmail' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyCc' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyBcc' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyMessageSignature' => Array ('type' => 'string', 'not_null' => 1, 'default' => NULL),
+ 'ReplyServer' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'connection_failed' => '!la_error_ConnectionFailed!',
+ 'message_listing_failed' => '!la_error_MessageListingFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'ReplyPort' => Array ('type' => 'int', 'not_null' => 1, 'default' => 110),
+ 'ReplyUsername' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'login_failed' => '!la_error_LoginFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'ReplyPassword' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'BounceEmail' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'BounceServer' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'connection_failed' => '!la_error_ConnectionFailed!',
+ 'message_listing_failed' => '!la_error_MessageListingFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'BouncePort' => Array ('type' => 'int', 'not_null' => 1, 'default' => 110),
+ 'BounceUsername' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'login_failed' => '!la_error_LoginFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'BouncePassword' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
),
'Grids' => Array(
'Default' => Array(
@@ -133,8 +202,11 @@
),
'Fields' => Array(
'FormId' => Array( 'title'=>'la_col_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
- 'Title' => Array( 'title' => 'la_col_Title', 'filter_block' => 'grid_like_filter', 'width' => 250, ),
+ 'Title' => Array( 'title' => 'la_col_Title', 'filter_block' => 'grid_like_filter', 'width' => 220, ),
'Description' => Array( 'title' => 'la_col_Description', 'filter_block' => 'grid_like_filter', 'width' => 300, ),
+ 'RequireLogin' => Array ('title' => 'la_col_RequireLogin', 'filter_block' => 'grid_options_filter', 'width' => 80,),
+ 'UseSecurityImage' => Array ('title' => 'la_col_UseSecurityImage', 'filter_block' => 'grid_options_filter', 'width' => 110,),
+ 'EnableEmailCommunication' => Array ('title' => 'la_col_EnableEmailCommunication', 'filter_block' => 'grid_options_filter', 'width' => 120,),
),
),
),
Index: units/forms/forms_eh.php
===================================================================
--- units/forms/forms_eh.php (revision 13377)
+++ units/forms/forms_eh.php (working copy)
@@ -96,55 +96,43 @@
}
/**
- * Dynamically fills customdata config
- *
- * @param kEvent $event
- */
- function OnCreateFormFields(&$event)
- {
- $cur_fields = $this->Conn->Query('DESCRIBE '.TABLE_PREFIX.'FormSubmissions', 'Field');
- $cur_fields = array_keys($cur_fields);
+ * Dynamically fills customdata config
+ *
+ * @param kEvent $event
+ */
+ function OnCreateFormFields(&$event)
+ {
+ $cur_fields = $this->Conn->Query('DESCRIBE '.TABLE_PREFIX.'FormSubmissions', 'Field');
+ $cur_fields = array_keys($cur_fields);
- // keep all fields, that are not created on the fly (includes ones, that are added during customizations)
- foreach ($cur_fields as $field_index => $field_name) {
- if (!preg_match('/^fld_[\d]+/', $field_name)) {
- unset($cur_fields[$field_index]);
- }
+ // keep all fields, that are not created on the fly (includes ones, that are added during customizations)
+ foreach ($cur_fields as $field_index => $field_name) {
+ if (!preg_match('/^fld_[\d]+/', $field_name)) {
+ unset($cur_fields[$field_index]);
}
+ }
- $desired_fields = $this->Conn->GetCol('SELECT CONCAT(\'fld_\', FormFieldId) FROM '.TABLE_PREFIX.'FormFields ORDER BY FormFieldId');
+ $desired_fields = $this->Conn->GetCol('SELECT CONCAT(\'fld_\', FormFieldId) FROM '.TABLE_PREFIX.'FormFields ORDER BY FormFieldId');
- $sql = array();
+ $sql = array();
- $fields_to_add = array_diff($desired_fields, $cur_fields);
- foreach ($fields_to_add as $field) {
- $field_expression = $field.' Text NULL';
- $sql[] = 'ADD COLUMN '.$field_expression;
- }
+ $fields_to_add = array_diff($desired_fields, $cur_fields);
+ foreach ($fields_to_add as $field) {
+ $field_expression = $field.' Text NULL';
+ $sql[] = 'ADD COLUMN '.$field_expression;
+ }
- $fields_to_drop = array_diff($cur_fields, $desired_fields);
- foreach ($fields_to_drop as $field) {
- $sql[] = 'DROP COLUMN '.$field;
- }
+ $fields_to_drop = array_diff($cur_fields, $desired_fields);
+ foreach ($fields_to_drop as $field) {
+ $sql[] = 'DROP COLUMN '.$field;
+ }
- if ($sql) {
- $query = 'ALTER TABLE '.TABLE_PREFIX.'FormSubmissions '.implode(', ', $sql);
- $this->Conn->Query($query);
- }
+ if ($sql) {
+ $query = 'ALTER TABLE '.TABLE_PREFIX.'FormSubmissions '.implode(', ', $sql);
+ $this->Conn->Query($query);
}
-
- /*function GetPassedId($event)
- {
- return 0;
}
- function LoadItem(&$event)
- {
- $object =& $event->getObject();
- $object->SetField('Id',0);
- $object->SetId(0);
- }
-*/
/**
* Enter description here...
*
@@ -210,4 +198,314 @@
$event->status = erFAIL;
}
}
+
+ /**
+ * Don't use security image, when form requires login
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $this->_validatePopSettings($event);
+ $this->_disableSecurityImage($event);
+ $this->_setRequired($event);
+ }
+
+ /**
+ * Don't use security image, when form requires login
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+ parent::OnBeforeItemUpdate($event);
+
+ $this->_validatePopSettings($event);
+ $this->_disableSecurityImage($event);
+ $this->_setRequired($event);
+ }
+
+ /**
+ * Validates POP3 settings (performs test connect)
+ *
+ * @param kEvent $event
+ */
+ function _validatePopSettings(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $modes = Array ('Reply', 'Bounce');
+ $fields = Array ('Server', 'Port', 'Username', 'Password');
+ $changed_fields = array_keys( $object->GetChangedFields() );
+
+ foreach ($modes as $mode) {
+ $set = true;
+ $changed = false;
+
+ foreach ($fields as $field) {
+ $value = $object->GetDBField($mode . $field);
+
+ if (strlen( trim($value) ) == 0) {
+ $set = false;
+ break;
+ }
+
+ if (!$changed && in_array($mode . $field, $changed_fields)) {
+ $changed = true;
+ }
+ }
+
+ if ($set && $changed) {
+ // fields are set and at least on of them is changed
+ $connection_info = Array ();
+
+ foreach ($fields as $field) {
+ $connection_info[ strtolower($field) ] = $object->GetDBField($mode . $field);
+ }
+
+ $pop3_helper =& $this->Application->makeClass('POP3Helper', $connection_info, 10);
+ /* @var $pop3_helper POP3Helper */
+
+ switch ( $pop3_helper->initMailbox(true) ) {
+ case 'socket':
+ $object->SetError($mode . 'Server', 'connection_failed');
+ break;
+
+ case 'login':
+ $object->SetError($mode . 'Username', 'login_failed');
+ break;
+
+ case 'list':
+ $object->SetError($mode . 'Server', 'message_listing_failed');
+ break;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Makes email communication fields required, when form uses email communication
+ *
+ * @param kEvent $event
+ */
+ function _setRequired(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $required = $object->GetDBField('EnableEmailCommunication');
+ $fields = Array (
+ 'ReplyFromName', 'ReplyFromEmail', 'ReplyServer', 'ReplyPort', 'ReplyUsername', 'ReplyPassword',
+ );
+
+ if ($required && $object->GetDBField('BounceEmail')) {
+ $bounce_fields = Array ('BounceEmail', 'BounceServer', 'BouncePort', 'BounceUsername', 'BouncePassword');
+ $fields = array_merge($fields, $bounce_fields);
+ }
+
+ foreach ($fields as $field) {
+ $object->setRequired($field, $required);
+ }
+ }
+
+ /**
+ * Don't use security image, when form requires login
+ *
+ * @param kEvent $event
+ */
+ function _disableSecurityImage(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ if ($object->GetDBField('RequireLogin')) {
+ $object->SetDBField('UseSecurityImage', 0);
+ }
+ }
+
+ /**
+ * Queries pop3 server about new incoming mail
+ *
+ * @param kEvent $event
+ */
+ function OnProcessReplies(&$event)
+ {
+ $this->_processMailbox($event, false);
+ }
+
+ /**
+ * Queries pop3 server about new incoming mail
+ *
+ * @param kEvent $event
+ */
+ function OnProcessBouncedReplies(&$event)
+ {
+ $this->_processMailbox($event, true);
+ }
+
+ /**
+ * Queries pop3 server about new incoming mail
+ *
+ * @param kEvent $event
+ */
+ function _processMailbox(&$event, $bounce_mode = false)
+ {
+// die('wait here :)');
+
+ $event->status = erSTOP; // for debugging
+
+ $this->Application->SetVar('client_mode', 1);
+
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
+ $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
+
+ $sql = 'SELECT *
+ FROM ' . $table_name . '
+ WHERE EnableEmailCommunication = 1';
+ $forms = $this->Conn->Query($sql, $id_field);
+
+ $mailbox_helper =& $this->Application->recallObject('MailboxHelper');
+ /* @var $mailbox_helper MailboxHelper */
+
+ $field_prefix = $bounce_mode ? 'Bounce' : 'Reply';
+
+ foreach ($forms as $form_id => $form_info) {
+ $recipient_email = $bounce_mode ? $form_info['BounceEmail'] : $form_info['ReplyFromEmail'];
+
+ if (!$recipient_email) {
+ continue;
+ }
+
+ $mailbox_helper->process(
+ Array (
+ 'server' => $form_info[$field_prefix . 'Server'],
+ 'port' => $form_info[$field_prefix . 'Port'],
+ 'username' => $form_info[$field_prefix . 'Username'],
+ 'password' => $form_info[$field_prefix . 'Password']
+ ),
+ Array (&$this, 'isValidRecipient'),
+ Array (&$this, 'processEmail'),
+ Array (
+ 'recipient_email' => $recipient_email,
+ 'bounce_mode' => $bounce_mode,
+ )
+ );
+ }
+ }
+
+ function isValidRecipient($params)
+ {
+ $mailbox_helper =& $this->Application->recallObject('MailboxHelper');
+ /* @var $mailbox_helper MailboxHelper */
+
+ $recipients = $mailbox_helper->getRecipients();
+ $recipient_email = $params['recipient_email'];
+
+ $emails_found = preg_match_all('/((' . REGEX_EMAIL_USER . ')(@' . REGEX_EMAIL_DOMAIN . '))/i', $recipients, $all_emails);
+
+ if (is_array($all_emails)) {
+ for ($i = 0; $i < $emails_found; $i++) {
+ if ($all_emails[1][$i] == $recipient_email) {
+ // only read messages, that are addresses to submission reply email
+ return true;
+ }
+ }
+ }
+
+ // If this is a forwarded message - we drop all the other aliases and deliver only to the x-forward to address;
+ if (preg_match('/((' . REGEX_EMAIL_USER . ')(@' . REGEX_EMAIL_DOMAIN . '))/i', $mailbox_helper->headers['x-forward-to'], $get_to_email)) {
+ if ($get_to_email[1] == $recipient_email) {
+ // only read messages, that are addresses to submission reply email
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function processEmail($params, &$fields_hash)
+ {
+ if ($params['bounce_mode']) {
+ // mark original message as bounced
+
+ $mailbox_helper =& $this->Application->recallObject('MailboxHelper');
+ /* @var $mailbox_helper MailboxHelper */
+
+ if (!array_key_exists('attachments', $mailbox_helper->parsedMessage)) {
+ // for now only parse bounces based on attachments, skip other bounce types
+ return false;
+ }
+
+ for ($i = 0; $i < count($mailbox_helper->parsedMessage['attachments']); $i++) {
+ $attachment =& $mailbox_helper->parsedMessage['attachments'][$i];
+
+ switch ($attachment['headers']['content-type']) {
+ case 'message/delivery-status':
+ // save as BounceInfo
+ $mime_decode_helper =& $this->Application->recallObject('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ $charset = $mailbox_helper->parsedMessage[ $fields_hash['MessageType'] ][0]['charset'];
+ $fields_hash['Message'] = $mime_decode_helper->convertEncoding($charset, $attachment['data']);
+ break;
+
+ case 'message/rfc822':
+ // undelivered message
+ $fields_hash['Subject'] = $attachment['filename2'] ? $attachment['filename2'] : $attachment['filename'];
+ break;
+ }
+ }
+ }
+
+ if (!preg_match('/^(.*) #verify(.*)$/', $fields_hash['Subject'], $regs)) {
+ // incorrect subject, no verification code
+ return false;
+ }
+
+ $sql = 'SELECT ' . $this->Application->getUnitOption('submission-log', 'IDField') . '
+ FROM ' . $this->Application->getUnitOption('submission-log', 'TableName') . '
+ WHERE MessageId = ' . $this->Conn->qstr($fields_hash['MessageId']);
+ $found = $this->Conn->GetOne($sql);
+
+ if ($found) {
+ // don't process same message twice
+ return false;
+ }
+
+ $reply_to =& $this->Application->recallObject('submission-log.-reply-to', null, Array ('skip_autoload' => true));
+ /* @var $reply_to kDBItem */
+
+ $reply_to->Load($regs[2], 'VerifyCode');
+ if (!$reply_to->isLoaded()) {
+ // fake verification code OR feedback, containing submission log was deleted
+ return false;
+ }
+
+ if ($params['bounce_mode']) {
+ // mark original message as bounced
+ $reply_to->SetDBField('BounceInfo', $fields_hash['Message']);
+ $reply_to->SetDBField('BounceDate_date', TIMENOW);
+ $reply_to->SetDBField('BounceDate_time', TIMENOW);
+ $reply_to->SetDBField('SentStatus', SUBMISSION_LOG_BOUNCE);
+ $reply_to->Update();
+
+ return true;
+ }
+
+ $reply =& $this->Application->recallObject('submission-log.-reply', null, Array ('skip_autoload' => true));
+ /* @var $reply kDBItem */
+
+ $reply->SetDBFieldsFromHash($fields_hash);
+ $reply->SetDBField('ReplyTo', $reply_to->GetID());
+ $reply->SetDBField('FormSubmissionId', $reply_to->GetDBField('FormSubmissionId'));
+ $reply->SetDBField('ToEmail', $params['recipient_email']);
+ $reply->SetDBField('Subject', $regs[1]); // save subject without verification code
+ $reply->SetDBField('SentStatus', SUBMISSION_LOG_SENT);
+
+ return $reply->Create();
+ }
}
\ No newline at end of file
Index: units/helpers/form_submission_helper.php
===================================================================
--- units/helpers/form_submission_helper.php (revision 0)
+++ units/helpers/form_submission_helper.php (revision 0)
@@ -0,0 +1,105 @@
+<?php
+
+ class FormSubmissionHelper extends kHelper {
+
+ /**
+ * Role names for easy usage via FormField tag
+ *
+ * @var Array
+ */
+ var $roleNames = Array (
+ 'name' => EMAIL_COMMUNICATION_ROLE_NAME,
+ 'email' => EMAIL_COMMUNICATION_ROLE_EMAIL,
+ 'subject' => EMAIL_COMMUNICATION_ROLE_SUBJECT,
+ 'body' => EMAIL_COMMUNICATION_ROLE_BODY,
+ );
+
+ /**
+ * Returns submission field based on given role
+ *
+ * @param kDBItem $form_submission
+ * @param string $role
+ * @return string
+ */
+ function getFieldByRole(&$form_submission, $role, $formatted = false, $format = null)
+ {
+ static $cache = Array ();
+
+ $form_id = $form_submission->GetDBField('FormId');
+
+ if (!array_key_exists($form_id, $cache)) {
+ $id_field = $this->Application->getUnitOption('formflds', 'IDField');
+ $table_name = $this->Application->getUnitOption('formflds', 'TableName');
+
+ $sql = 'SELECT ' . $id_field . ', EmailCommunicationRole
+ FROM ' . $table_name . '
+ WHERE FormId = ' . $form_id . ' AND EmailCommunicationRole <> 0';
+ $cache[$form_id] = $this->Conn->GetCol($sql, 'EmailCommunicationRole');
+ }
+
+ // convert string representation of role to numeric
+ if (!is_numeric($role)) {
+ $role = strtolower($role);
+ $role = array_key_exists($role, $this->roleNames) ? $this->roleNames[$role] : false;
+ }
+
+ // get field by role
+ $field_id = array_key_exists($role, $cache[$form_id]) ? $cache[$form_id][$role] : false;
+
+ if ($field_id) {
+ return $formatted ? $form_submission->GetField('fld_' . $field_id, $format) : $form_submission->GetDBField('fld_' . $field_id);
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns submission field based on given name
+ *
+ * @param kDBItem $form_submission
+ * @param string $name
+ * @return string
+ */
+ function getFieldByName(&$form_submission, $name, $formatted = false, $format = null)
+ {
+ static $cache = Array ();
+
+ $form_id = $form_submission->GetDBField('FormId');
+
+ if (!array_key_exists($form_id, $cache)) {
+ $id_field = $this->Application->getUnitOption('formflds', 'IDField');
+ $table_name = $this->Application->getUnitOption('formflds', 'TableName');
+
+ $sql = 'SELECT ' . $id_field . ', FieldName
+ FROM ' . $table_name . '
+ WHERE FormId = ' . $form_id;
+ $cache[$form_id] = $this->Conn->GetCol($sql, 'FieldName');
+ }
+
+ if ($field_id) {
+ return $formatted ? $form_submission->GetField('fld_' . $field_id, $format) : $form_submission->GetDBField('fld_' . $field_id);
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns form object field based on form submission
+ *
+ * @param $form_submission kDBItem
+ * @return kDBItem
+ */
+ function &getForm(&$form_submission)
+ {
+ $form_id = $form_submission->GetDBField('FormId');
+
+ $form =& $this->Application->recallObject('form', null, Array ('skip_autoload' => true));
+ /* @var $form kDBItem */
+
+ if (!$form->isLoaded() || ($form->GetID() != $form_id)) {
+ $form->Load($form_id);
+ }
+
+ return $form;
+ }
+ }
\ No newline at end of file
Index: units/helpers/helpers_config.php
===================================================================
--- units/helpers/helpers_config.php (revision 13377)
+++ units/helpers/helpers_config.php (working copy)
@@ -49,15 +49,20 @@
Array ('pseudo' => 'JSONHelper', 'class' => 'JSONHelper', 'file' => 'json_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
Array ('pseudo' => 'LanguageImportHelper', 'class' => 'LanguageImportHelper', 'file' => 'language_import_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
Array ('pseudo' => 'SkinHelper', 'class' => 'SkinHelper', 'file' => 'skin_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'SiteConfigHelper', 'pseudo' => 'SiteConfigHelper', 'file' => 'site_config_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'MenuHelper', 'pseudo' => 'MenuHelper', 'file' => 'menu_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'SiteConfigHelper', 'class' => 'SiteConfigHelper', 'file' => 'site_config_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'MenuHelper', 'class' => 'MenuHelper', 'file' => 'menu_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'InpCustomFieldsHelper', 'pseudo' => 'InpCustomFieldsHelper', 'file' => 'custom_fields_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kCountryStatesHelper', 'pseudo' => 'CountryStatesHelper', 'file' => 'country_states_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kBracketsHelper', 'pseudo' => 'BracketsHelper', 'file' => 'brackets_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kXMLHelper', 'pseudo' => 'kXMLHelper', 'file' => 'xml_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kCatDBItemExportHelper', 'pseudo' => 'CatItemExportHelper', 'file' => 'cat_dbitem_export_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'EmailMessageHelper', 'pseudo' => 'EmailMessageHelper', 'file' => 'email_message_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'ListHelper', 'pseudo' => 'ListHelper', 'file' => 'list_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'InpCustomFieldsHelper', 'class' => 'InpCustomFieldsHelper', 'file' => 'custom_fields_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'CountryStatesHelper', 'class' => 'kCountryStatesHelper', 'file' => 'country_states_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'BracketsHelper', 'class' => 'kBracketsHelper', 'file' => 'brackets_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'kXMLHelper', 'class' => 'kXMLHelper', 'file' => 'xml_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'CatItemExportHelper', 'class' => 'kCatDBItemExportHelper', 'file' => 'cat_dbitem_export_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'EmailMessageHelper', 'class' => 'EmailMessageHelper', 'file' => 'email_message_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'ListHelper', 'class' => 'ListHelper', 'file' => 'list_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+
+ Array ('pseudo' => 'FormSubmissionHelper', 'class' => 'FormSubmissionHelper', 'file' => 'form_submission_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'MailboxHelper', 'class' => 'MailboxHelper', 'file' => 'mailbox_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'POP3Helper', 'class' => 'POP3Helper', 'file' => 'pop3_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'MimeDecodeHelper', 'class' => 'MimeDecodeHelper', 'file' => 'mime_decode_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
),
);
\ No newline at end of file
Index: units/helpers/mailbox_helper.php
===================================================================
--- units/helpers/mailbox_helper.php (revision 0)
+++ units/helpers/mailbox_helper.php (revision 0)
@@ -0,0 +1,477 @@
+<?php
+
+
+ class MailboxHelper extends kHelper {
+
+ var $headers = Array ();
+
+ var $parsedMessage = Array ();
+
+ /**
+ * Maximal megabytes of data to process
+ *
+ * @var int
+ */
+ var $maxMegabytes = 2;
+
+ /**
+ * Maximal message count to process
+ *
+ * @var int
+ */
+ var $maxMessages = 50;
+
+ /**
+ * Reads mailbox and gives messages to processing callback
+ *
+ * @param Array $connection_info
+ * @param Array $verify_callback
+ * @param Array $process_callback
+ * @param Array $callback_params
+ * @param bool $include_attachment_contents
+ * @return string
+ */
+ function process($connection_info, $verify_callback, $process_callback, $callback_params = Array (), $include_attachment_contents = true)
+ {
+ $pop3_helper =& $this->Application->makeClass('POP3Helper', $connection_info);
+ /* @var $pop3_helper POP3Helper */
+
+ $connection_status = $pop3_helper->initMailbox();
+
+ if (is_string($connection_status)) {
+ return $connection_status;
+ }
+
+ // Figure out if all messages are huge
+ $only_big_messages = true;
+ $max_message_size = $this->maxMegabytes * (1024 * 1024);
+
+ foreach ($pop3_helper->messageSizes as $message_size) {
+ if (($message_size <= $max_message_size) && ($max_message_size > 0)) {
+ $only_big_messages = false;
+ break;
+ }
+ }
+
+ $count = $total_size = 0;
+
+ foreach ($pop3_helper->messageSizes as $message_number => $message_size) {
+ // Too many messages?
+ if (($count++ > $this->maxMessages) && ($this->maxMessages > 0)) {
+ break;
+ }
+
+ // Message too big?
+ if (!$only_big_messages && ($message_size > $max_message_size) && ($max_message_size > 0)) {
+ $this->_displayLogMessage('message <strong>#' . $message_number . '</strong> too big, skipped');
+ continue;
+ }
+
+ // Processed enough for today?
+ if (($total_size > $max_message_size) && ($max_message_size > 0)) {
+ break;
+ }
+
+ $total_size += $message_size;
+ $pop3_helper->getEmail($message_number, $message_source);
+
+ $processed = $this->normalize($message_source, $verify_callback, $process_callback, $callback_params, $include_attachment_contents);
+
+ if ($processed) {
+ // delete message from server immediatly after retrieving & processing
+ $pop3_helper->deleteEmail($message_number);
+ $this->_displayLogMessage('message <strong>#' . $message_number . '</strong>: processed');
+ }
+ else {
+ $this->_displayLogMessage('message <strong>#' . $message_number . '</strong>: skipped');
+ }
+ }
+
+ $pop3_helper->close();
+
+ return 'success';
+ }
+
+ /**
+ * Displays log message
+ *
+ * @param string $text
+ */
+ function _displayLogMessage($text)
+ {
+ if (defined('DEBUG_MODE') && DEBUG_MODE) {
+ echo $text . '<br/>';
+ flush();
+ }
+ }
+
+ /**
+ * Takes an RFC822 formatted date, returns a unix timestamp (allowing for zone)
+ *
+ * @param string $rfcdate
+ * @return int
+ */
+ function rfcToTime($rfcdate)
+ {
+ $date = strtotime($rfcdate);
+
+ if ($date == -1) {
+ return false;
+ }
+
+ return $date;
+ }
+
+ /**
+ * Gets recipients from all possible headers
+ *
+ * @return string
+ */
+ function getRecipients()
+ {
+ $ret = '';
+
+ // headers that could contain recipients
+ $recipient_headers = Array (
+ 'to', 'cc', 'envelope-to', 'resent-to', 'delivered-to',
+ 'apparently-to', 'envelope-to', 'x-envelope-to', 'received',
+ );
+
+ foreach ($recipient_headers as $recipient_header) {
+ if (!array_key_exists($recipient_header, $this->headers)) {
+ continue;
+ }
+
+ if (!is_array($this->headers["$recipient_header"])) {
+ $ret .= ' ' . $this->headers["$recipient_header"];
+ } else {
+ $ret .= ' ' . implode(' ', $this->headers["$recipient_header"]);
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * "Flattens" the multi-demensinal headers array into a single dimension one
+ *
+ * @param Array $input
+ * @param string $add
+ * @return Array
+ */
+ function flattenHeadersArray($input, $add = '')
+ {
+ $output = Array ();
+
+ foreach ($input as $key => $value) {
+ if (!empty($add)) {
+ $newkey = ucfirst( strtolower($add) );
+ } elseif (is_numeric($key)) {
+ $newkey = '';
+ } else {
+ $newkey = ucfirst( strtolower($key) );
+ }
+
+ if (is_array($value)) {
+ $output = array_merge($output, $this->flattenHeadersArray($value, $newkey));
+ } else {
+ $output[] = (!empty($newkey) ? $newkey . ': ' : '') . $value;
+ }
+ }
+
+ return $output;
+ }
+
+ /**
+ * Processes given message using given callbacks
+ *
+ * @param string $message
+ * @param Array $verify_callback
+ * @param Array $process_callback
+ * @param bool $include_attachment_contents
+ * @return bool
+ */
+ function normalize($message, $verify_callback, $process_callback, $callback_params, $include_attachment_contents = true)
+ {
+ // Decode message
+ $this->decodeMime($message, $include_attachment_contents);
+
+ // Init vars; $good will hold all the correct infomation from now on
+ $good = Array ();
+
+ // trim() some stuff now instead of later
+ $this->headers['from'] = trim($this->headers['from']);
+ $this->headers['to'] = trim($this->headers['to']);
+ $this->headers['cc'] = array_key_exists('cc', $this->headers) ? trim($this->headers['cc']) : '';
+ $this->headers['x-forward-to'] = array_key_exists('x-forward-to', $this->headers) ? $this->headers['x-forward-to'] : '';
+ $this->headers['subject'] = trim($this->headers['subject']);
+ $this->headers['received'] = is_array($this->headers['received']) ? $this->headers['received'] : Array ($this->headers['received']);
+
+ if (array_key_exists('return-path', $this->headers) && is_array($this->headers['return-path'])) {
+ $this->headers['return-path'] = implode(' ', $this->flattenHeadersArray($this->headers['return-path']));
+ }
+
+ // Create our own message-ID if it's missing
+ $message_id = array_key_exists('message-id', $this->headers) ? trim($this->headers['message-id']) : '';
+ $good['emailid'] = $message_id ? $message_id : md5($message) . "@in-portal";
+
+ // Stops us looping in stupid conversations with other mail software
+ if (isset($this->headers['x-loop-detect']) && $this->headers['x-loop-detect'] > 2) {
+ return false;
+ }
+
+ $esender =& $this->Application->recallObject('EmailSender');
+ /* @var $esender kEmailSendingHelper */
+
+ // Get the return address
+ $return_path = '';
+
+ if (array_key_exists('return-path', $this->headers)) {
+ $return_path = $esender->ExtractRecipientEmail($this->headers['return-path']);
+ }
+
+ if (!$return_path) {
+ if (array_key_exists('reply-to', $this->headers)) {
+ $return_path = $esender->ExtractRecipientEmail( $this->headers['reply-to'] );
+ }
+ else {
+ $return_path = $esender->ExtractRecipientEmail( $this->headers['from'] );
+ }
+ }
+
+ // Get the sender's name & email
+ $good['fromemail'] = $esender->ExtractRecipientEmail($this->headers['from']);
+ $good['fromname'] = $esender->ExtractRecipientName($this->headers['from'], $good['fromemail']);
+
+ // Get the list of recipients
+ if (!$verify_callback[0]->$verify_callback[1]($callback_params)) {
+ // error: mail is propably spam
+ return false;
+ }
+
+ // Handle the subject
+ $good['subject'] = $this->headers['subject'];
+
+ // Priorities rock
+ $good['priority'] = array_key_exists('x-priority', $this->headers) ? (int)$this->headers['x-priority'] : 0;
+
+ switch ($good['priority']) {
+ case 1: case 5: break;
+ default:
+ $good['priority'] = 3;
+ }
+
+ // If we have attachments it's about time we tell the user about it
+ if (array_key_exists('attachments', $this->parsedMessage) && is_array($this->parsedMessage['attachments'])) {
+ $good['attach'] = count( $this->parsedMessage['attachments'] );
+ } else {
+ $good['attach'] = 0;
+ }
+
+ // prepare message text (for replies, etc)
+ if (isset($this->parsedMessage['text'][0]) && trim($this->parsedMessage['text'][0]['body']) != '') {
+ $message_body = trim($this->parsedMessage['text'][0]['body']);
+ $message_type = 'text';
+ } elseif (isset($this->parsedMessage['html']) && trim($this->parsedMessage['html'][0]['body']) != '') {
+ $message_body = trim($this->parsedMessage['html'][0]['body']);
+ $message_type = 'html';
+ } else {
+ $message_body = '[no message]';
+ $message_type = 'text';
+ }
+
+ // remove scripts
+ $message_body = preg_replace("/<script[^>]*>[^<]+<\/script[^>]*>/is", '', $message_body);
+ $message_body = preg_replace("/<iframe[^>]*>[^<]*<\/iframe[^>]*>/is", '', $message_body);
+
+ if ($message_type == 'html') {
+ $message_body = $esender->ConvertToText($message_body);
+ }
+
+ $mime_decode_helper =& $this->Application->recallObject('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ // convert to site encoding
+ $message_charset = $this->parsedMessage[$message_type][0]['charset'];
+
+ if ($message_charset) {
+ $good['message'] = $mime_decode_helper->convertEncoding($message_charset, $message_body);
+ }
+
+ if (array_key_exists('delivery-date', $this->headers)) {
+ // We found the Delivery-Date header (and it's not too far in the future)
+ $dateline = $this->rfcToTime($this->headers['delivery-date']);
+
+ if ($dateline > TIMENOW + 86400) {
+ unset($dateline);
+ }
+ }
+
+ // We found the latest date from the received headers
+ $received_timestamp = $this->headers['received'][0];
+ $dateline = $this->rfcToTime(trim( substr($received_timestamp, strrpos($received_timestamp, ';') + 1) ));
+
+ if ($dateline == $this->rfcToTime(0)) {
+ unset($dateline);
+ }
+
+ if (!isset($dateline)) {
+ $dateline = TIMENOW;
+ }
+
+ // save collected data to database
+ $fields_hash = Array (
+ 'DeliveryDate' => $dateline, // date, when SMTP server received the message
+ 'ReceivedDate' => TIMENOW, // date, when message was retrieved from POP3 server
+ 'CreatedOn' => $this->rfcToTime($this->headers['date']), // date, when created on sender's computer
+ 'ReturnPath' => $return_path,
+ 'FromEmail' => $good['fromemail'],
+ 'FromName' => $good['fromname'],
+ 'To' => $this->headers['to'],
+ 'Subject' => $good['subject'],
+ 'Message' => $good['message'],
+ 'MessageType' => $message_type,
+ 'AttachmentCount' => $good['attach'],
+ 'MessageId' => $good['emailid'],
+ 'Source' => $message,
+ 'Priority' => $good['priority'],
+ 'Size' => strlen($message),
+ );
+
+ return $process_callback[0]->$process_callback[1]($callback_params, $fields_hash);
+ }
+
+ /**
+ * Function that decodes the MIME message and creates the $this->headers and $this->parsedMessage data arrays
+ *
+ * @param string $message
+ * @param bool $include_attachments
+ *
+ */
+ function decodeMime($message, $include_attachments = true)
+ {
+ $message = preg_replace("/\r?\n/", "\r\n", trim($message));
+
+ $mime_decode_helper =& $this->Application->recallObject('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ // 1. separate headers from bodies
+ $mime_decode_helper->InitHelper($message);
+ $decoded_message = $mime_decode_helper->decode(true, true, true);
+
+ // 2. extract attachments
+ $this->parsedMessage = Array (); // ! reset value
+ $this->parseOutput($decoded_message, $this->parsedMessage, $include_attachments);
+
+ // 3. add "other" attachments (text part, that is not maked as attachment)
+ if (array_key_exists('text', $this->parsedMessage) && count($this->parsedMessage['text']) > 1) {
+ for ($attach = 1; $attach < count($this->parsedMessage['text']); $attach++) {
+ $this->parsedMessage['attachments'][] = Array (
+ 'data' => $this->parsedMessage['text']["$attach"]['body'],
+ );
+ }
+ }
+
+ $this->headers = $this->parsedMessage['headers']; // ! reset value
+
+ if (empty($decoded_message->ctype_parameters['boundary'])) {
+ // when no boundary, then assume all message is it's text
+ $this->parsedMessage['text'][0]['body'] = $decoded_message->body;
+ }
+ }
+
+ /**
+ * Returns content-id's from inline attachments in message
+ *
+ * @return Array
+ */
+ function getContentIds()
+ {
+ $cids = Array();
+
+ if (array_key_exists('attachments', $this->parsedMessage) && is_array($this->parsedMessage['attachments'])) {
+ foreach ($this->parsedMessage['attachments'] as $attachnum => $attachment) {
+ if (!isset($attachment['headers']['content-id'])) {
+ continue;
+ }
+
+ $cid = $attachment['headers']['content-id'];
+
+ if (substr($cid, 0, 1) == '<' && substr($cid, -1) == '>') {
+ $cid = substr($cid, 1, -1);
+ }
+
+ $cids["$attachnum"] = $cid;
+ }
+ }
+
+ return $cids;
+ }
+
+ /**
+ * Get more detailed information about attachments
+ *
+ * @param stdClass $decoded parsed headers & body as object
+ * @param Array $parts parsed parts
+ * @param bool $include_attachments
+ */
+ function parseOutput(&$decoded, &$parts, $include_attachments = true)
+ {
+ $ctype = strtolower($decoded->ctype_primary . '/' . $decoded->ctype_secondary);
+
+ // don't parse attached messages recursevely
+ if (!empty($decoded->parts) && $ctype != 'message/rfc822') {
+ for ($i = 0; $i < count($decoded->parts); $i++) {
+ $this->parseOutput($decoded->parts["$i"], $parts, $include_attachments);
+ }
+ } else/*if (!empty($decoded->disposition) && $decoded->disposition != 'inline' or 1)*/ {
+ switch ($ctype) {
+ case 'text/plain':
+ case 'text/html':
+ if (!empty($decoded->disposition) && ($decoded->disposition == 'attachment')) {
+ $parts['attachments'][] = Array (
+ 'data' => $include_attachments ? $decoded->body : '',
+ 'filename' => array_key_exists('filename', $decoded->d_parameters) ? $decoded->d_parameters['filename'] : '', // from content-disposition
+ 'filename2' => $decoded->ctype_parameters['name'], // from content-type
+ 'type' => $decoded->ctype_primary, // "text"
+ 'encoding' => $decoded->headers['content-transfer-encoding']
+ );
+ } else {
+ $body_type = $decoded->ctype_secondary == 'plain' ? 'text' : 'html';
+ $parts[$body_type][] = Array (
+ 'content-type' => $ctype,
+ 'charset' => array_key_exists('charset', $decoded->ctype_parameters) ? $decoded->ctype_parameters['charset'] : 'ISO-8859-1',
+ 'body' => $decoded->body
+ );
+ }
+ break;
+
+ case 'message/rfc822':
+ // another e-mail as attachment
+ $parts['attachments'][] = Array (
+ 'data' => $include_attachments ? $decoded->body : '',
+ 'filename' => array_key_exists('filename', $decoded->d_parameters) ? $decoded->d_parameters['filename'] : '',
+ 'filename2' => array_key_exists('name', $decoded->ctype_parameters) ? $decoded->ctype_parameters['name'] : $decoded->parts[0]->headers['subject'],
+ 'type' => $decoded->ctype_primary, // "message"
+ 'headers' => $decoded->headers // individual copy of headers with each attachment
+ );
+ break;
+
+ default:
+ if (!stristr($decoded->headers['content-type'], 'signature')) {
+ $parts['attachments'][] = Array (
+ 'data' => $include_attachments ? $decoded->body : '',
+ 'filename' => array_key_exists('filename', $decoded->d_parameters) ? $decoded->d_parameters['filename'] : '', // from content-disposition
+ 'filename2' => $decoded->ctype_parameters['name'], // from content-type
+ 'type' => $decoded->ctype_primary,
+ 'headers' => $decoded->headers // individual copy of headers with each attachment
+ );
+ }
+
+ }
+ }
+
+ $parts['headers'] = $decoded->headers; // headers of next parts overwrite previous part headers
+ }
+
+ }
\ No newline at end of file
Index: units/helpers/mime_decode_helper.php
===================================================================
--- units/helpers/mime_decode_helper.php (revision 0)
+++ units/helpers/mime_decode_helper.php (revision 0)
@@ -0,0 +1,477 @@
+<?php
+
+ /**
+ * The MIME decoding class
+ *
+ */
+ class MimeDecodeHelper extends kHelper {
+
+ /**
+ * Contains headers part of email message
+ *
+ * @var string
+ */
+ var $_headerPart;
+
+ /**
+ * Contains body part of email message
+ *
+ * @var string
+ */
+ var $_bodyPart;
+
+ /**
+ * Last parsing error message (if any)
+ *
+ * @var string
+ */
+ var $_lastErrorMessage = '';
+
+ /**
+ * Decode message headers
+ *
+ * @var bool
+ */
+ var $_decodeHeaders = false;
+
+ /**
+ * Include email body in decoded result
+ *
+ * @var bool
+ */
+ var $_includeBodies = true;
+
+ /**
+ * Decode email body (only in case, when it will be included in result)
+ *
+ * @var bool
+ */
+ var $_decodeBodies = false;
+
+ /**
+ * Displays parsing error
+ *
+ * @param string $str
+ */
+ function raiseError($str)
+ {
+ trigger_error('Error during email parsing: ' . $str, E_USER_WARNING);
+ }
+
+ /**
+ * Initializes mime parsing using given email message
+ *
+ * @param string $message
+ */
+ function InitHelper($message = null)
+ {
+ if (!isset($message)) {
+ return ;
+ }
+
+ list ($header, $body) = $this->_splitBodyHeader($message);
+
+ $this->_headerPart = $header;
+ $this->_bodyPart = $body;
+ }
+
+ /**
+ * Decodes email message, that was previously set using InitHelper method
+ *
+ * @param bool $decode_headers
+ * @param bool $include_bodies
+ * @param bool $decode_bodies
+ * @return stdClass
+ */
+ function decode($decode_headers = false, $include_bodies = false, $decode_bodies = false)
+ {
+ $this->_decodeHeaders = $decode_headers;
+ $this->_includeBodies = $include_bodies;
+ $this->_decodeBodies = $decode_bodies;
+
+ $ret = $this->decodePart($this->_headerPart, $this->_bodyPart);
+
+ if ($ret === false) {
+ $this->raiseError($this->_lastErrorMessage);
+
+ return false;
+ }
+
+ return $ret;
+ }
+
+ function decodePart($headers, $body, $default_ctype = 'text/plain', $only_headers = false)
+ {
+ $return = new stdClass;
+
+ // process headers
+ $return->headers = Array ();
+ $headers = $this->_parseHeaders($headers, $this->_decodeHeaders);
+ $single_headers = Array ('subject', 'from', 'to', 'cc', 'reply-to', 'date');
+
+ foreach ($headers as $value) {
+ $header_name = strtolower($value['name']);
+ $header_value = $only_headers ? $this->_decodeHeader($value['value']) : $value['value'];
+
+ if (array_key_exists($header_name, $return->headers) && !is_array($return->headers[$header_name]) && !in_array($header_name, $single_headers)) {
+ // this is not a single header, so convert it to array, when 2nd value is found
+ $return->headers[$header_name] = Array ( $return->headers[$header_name] );
+ $return->headers[$header_name][] = $header_value;
+ }
+ elseif (array_key_exists($header_name, $return->headers) && !in_array($header_name, $single_headers)) {
+ $return->headers[$header_name][] = $header_value;
+ }
+ else {
+ $return->headers[$header_name] = $header_value;
+ }
+ }
+
+ if ($only_headers) {
+ return $return->headers;
+ }
+
+ foreach ($headers as $value) {
+ $header_name = strtolower($value['name']);
+ $header_value = $value['value'];
+
+ switch ($header_name) {
+ case 'content-type':
+ $content_type = $this->_parseHeaderValue($header_value);
+
+ if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
+ // "text/plain", "text/html", etc.
+ $return->ctype_primary = $regs[1];
+ $return->ctype_secondary = $regs[2];
+ }
+
+ if (array_key_exists('other', $content_type)) {
+ // "charset", etc.
+ foreach ($content_type['other'] as $p_name => $p_value) {
+ $return->ctype_parameters["$p_name"] = $p_value;
+ }
+ }
+ break;
+
+ case 'content-disposition';
+ $content_disposition = $this->_parseHeaderValue($header_value);
+ $return->disposition = $content_disposition['value'];
+
+ if (array_key_exists('other', $content_disposition)) {
+ // "filename", etc.
+ foreach ($content_disposition['other'] as $p_name => $p_value) {
+ $return->d_parameters["$p_name"] = $p_value;
+ }
+ }
+ break;
+
+ case 'content-transfer-encoding':
+ $content_transfer_encoding = $this->_parseHeaderValue($header_value);
+ break;
+ }
+ }
+
+ // process message body
+ if (isset($content_type)) {
+ switch ( strtolower($content_type['value']) ) {
+ case 'text/plain':
+ case 'text/html':
+ if ($this->_includeBodies) {
+ $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+ $return->body = $this->_decodeBodies ? $this->_decodeBody($body, $encoding) : $body;
+ }
+ break;
+
+ case 'multipart/parallel':
+ case 'multipart/report': // RFC1892
+ case 'multipart/signed': // PGP
+ case 'multipart/digest':
+ case 'multipart/alternative':
+ case 'multipart/appledouble':
+ case 'multipart/related':
+ case 'multipart/mixed':
+ if (!isset($content_type['other']['boundary'])) {
+ $this->_lastErrorMessage = 'No boundary found for ' . $content_type['value'] . ' part';
+ return false;
+ }
+
+ $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';
+
+ $parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
+
+ for ($i = 0; $i < count($parts); $i++) {
+ list ($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
+ $part = $this->decodePart($part_header, $part_body, $default_ctype);
+
+ if ($part === false) {
+ // part is broken
+ $this->raiseError($this->_lastErrorMessage);
+ }
+
+ $return->parts[] = $part;
+ }
+ break;
+
+ case 'message/rfc822':
+ case 'message/disposition-notification':
+ // create another instance, not to interfear with main parser
+ $mime_decode_helper =& $this->Application->makeClass('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ $mime_decode_helper->InitHelper($body);
+
+ $return->parts[] = $mime_decode_helper->decode(true, $this->_includeBodies, $this->_decodeBodies);
+ unset($mime_decode_helper);
+ break;
+
+ default:
+ if ($this->_includeBodies) {
+ $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+ $return->body = $this->_decodeBodies ? $this->_decodeBody($body, $encoding) : $body;
+ }
+ break;
+ }
+
+ } else {
+ $ctype = explode('/', $default_ctype);
+ $return->ctype_primary = $ctype[0];
+ $return->ctype_secondary = $ctype[1];
+
+ if ($this->_includeBodies) {
+ $return->body = $this->_decodeBodies ? $this->_decodeBody($body) : $body;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Divides message into header and body parts
+ *
+ * @param string $input
+ * @return Array
+ */
+ function _splitBodyHeader($input)
+ {
+ if (strpos($input, "\r\n\r\n") === false) {
+ return Array ($input, '');
+ } elseif (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
+ return Array ($match[1], $match[2]);
+ } else {
+ $this->_lastErrorMessage = 'Could not split header and body';
+
+ return false;
+ }
+ }
+
+ /**
+ * Parses headers string into array and optionally decode them
+ *
+ * @param string $input
+ * @param bool $decode
+ * @return Array
+ */
+ function _parseHeaders($input, $decode = false)
+ {
+ if (!$input) {
+ return Array ();
+ }
+
+ $ret = Array ();
+
+ // Unfold the input
+ $input = preg_replace("/\r\n/", "\n", $input);
+ $input = preg_replace("/\n(\t| )+/", ' ', $input);
+ $headers = explode("\n", trim($input));
+
+ foreach ($headers as $value) {
+ $pos = strpos($value, ':');
+ $hdr_name = substr($value, 0, $pos);
+ $hdr_value = substr($value, $pos + 1);
+
+ if ($hdr_value[0] == ' ') {
+ $hdr_value = substr($hdr_value, 1);
+ }
+
+ $ret[] = Array (
+ 'name' => $hdr_name,
+ 'value' => $decode ? $this->_decodeHeader($hdr_value) : $hdr_value
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Parses header value in following format (without quotes): "multipart/alternative; boundary=001636c9274051e332048498d8cc"
+ *
+ * @param string $input
+ * @return Array
+ */
+ function _parseHeaderValue($input)
+ {
+ $ret = Array ();
+ $pos = strpos($input, ';');
+
+ if ($pos === false) {
+ $ret['value'] = trim($input);
+
+ return $ret;
+ }
+
+ // get text until first ";"
+ $ret['value'] = trim(substr($input, 0, $pos));
+ $input = trim(substr($input, $pos + 1));
+
+ if (strlen($input) > 0) {
+ // This splits on a semi-colon, if there's no preceeding backslash
+ // Can't handle if it's in double quotes however. (Of course anyone
+ // sending that needs a good slap).
+ $parameters = preg_split('/\s*(?<!\\\\);\s*/i', $input);
+
+ for ($i = 0; $i < count($parameters); $i++) {
+ $pos = strpos($parameters[$i], '=');
+ $param_name = substr($parameters[$i], 0, $pos);
+ $param_value = substr($parameters[$i], $pos + 1);
+
+ if ($param_value[0] == '"') {
+ $param_value = substr($param_value, 1, -1);
+ }
+
+ $ret['other']["$param_name"] = $param_value;
+ $ret['other'][ strtolower($param_name) ] = $param_value;
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Splits input body using given boundary
+ *
+ * @param string $input
+ * @param string $boundary
+ * @return Array
+ */
+ function _boundarySplit($input, $boundary)
+ {
+ $tmp = explode('--' . $boundary, $input);
+
+ for ($i = 1; $i < count($tmp) - 1; $i++) {
+ $parts[] = $tmp[$i];
+ }
+
+ return $parts;
+ }
+
+ /**
+ * Decode message header value
+ *
+ * @param string $input
+ * @return string
+ */
+ function _decodeHeader($input)
+ {
+ // Remove white space between encoded-words
+ $input = preg_replace('/(=\?[^?]+\?(Q|B)\?[^?]*\?=)( |' . "\t|\r?\n" . ')+=\?/i', '\1=?', $input);
+
+ // For each encoded-word...
+ while (preg_match('/(=\?([^?]+)\?(Q|B)\?([^?]*)\?=)/i', $input, $matches)) {
+ $encoded = $matches[1];
+ $charset = $matches[2];
+ $encoding = $matches[3];
+ $text = $matches[4];
+
+ switch (strtoupper($encoding)) {
+ case 'B':
+ $text = base64_decode($text);
+ break;
+
+ case 'Q':
+ // $text = $this->_quotedPrintableDecode($text);
+ $text = str_replace('_', ' ', $text);
+ preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
+
+ foreach($matches[1] as $value) {
+ $text = str_replace('=' . $value, chr(hexdec($value)), $text);
+ }
+ break;
+ }
+
+ $input = $this->convertEncoding($charset, str_replace($encoded, $text, $input));
+ }
+
+ return $input;
+ }
+
+ /**
+ * Converts encoding to one, that site uses
+ *
+ * @param string $from_engoding
+ * @param string $text
+ * @return string
+ * @author Alex
+ */
+ function convertEncoding($from_engoding, $text)
+ {
+ if (!function_exists('mb_convert_encoding')) {
+ // if mbstring extension not installed
+ return $text;
+ }
+
+ static $to_encoding = false;
+
+ if ($to_encoding === false) {
+ $language =& $this->Application->recallObject('lang.current');
+ /* @var $language LanguagesItem */
+ $to_encoding = $language->GetDBField('Charset');
+ }
+
+ return mb_convert_encoding($text, $to_encoding, $from_engoding);
+
+ }
+
+ /**
+ * Decodes message body
+ *
+ * @param string $input
+ * @param string $encoding
+ * @return string
+ */
+ function _decodeBody($input, $encoding = '7bit')
+ {
+ switch (strtolower($encoding)) {
+ case 'quoted-printable':
+ return $this->_quotedPrintableDecode($input);
+ break;
+
+ case 'base64':
+ return base64_decode($input);
+ break;
+ }
+
+ // for 7bit, 8bit, anything else
+ return $input;
+ }
+
+ /**
+ * Decodes "quoted-printable" encoding
+ *
+ * @param string $string
+ * @return string
+ */
+ function _quotedPrintableDecode($string)
+ {
+ // Remove soft line breaks
+ $string = preg_replace("/=\r?\n/", '', $string);
+
+ // Replace encoded characters
+ if (preg_match_all('/=[a-f0-9]{2}/i', $string, $matches)) {
+ $matches = array_unique($matches[0]);
+ foreach ($matches as $value) {
+ $string = str_replace($value, chr(hexdec(substr($value,1))), $string);
+ }
+ }
+
+ return $string;
+ }
+ }
\ No newline at end of file
Index: units/helpers/pop3_helper.php
===================================================================
--- units/helpers/pop3_helper.php (revision 0)
+++ units/helpers/pop3_helper.php (revision 0)
@@ -0,0 +1,339 @@
+<?php
+
+ /**
+ * POP3 connection class, that uses sockets
+ *
+ */
+ class POP3Helper extends kHelper {
+
+ /**
+ * Pointer to socket to POP3 server
+ *
+ * @var resource
+ */
+ var $fp = null;
+
+ /**
+ * Connection to POP3 server established
+ *
+ * @var bool
+ */
+ var $connected = false;
+
+ /**
+ * Connection timeout
+ *
+ * @var int
+ */
+ var $connectionTimeout = 60;
+
+ /**
+ * Server connection information
+ *
+ * @var Array
+ */
+ var $serverInfo = Array ();
+
+ /**
+ * Size of each message in mailbox
+ *
+ * @var Array
+ */
+ var $messageSizes = Array ();
+
+ /**
+ * Sets up the server information array
+ *
+ * @param Array $server_info
+ * @return POP3Helper
+ */
+ function POP3Helper($server_info, $connection_timeout = null)
+ {
+ parent::kHelper();
+
+ $this->serverInfo = $server_info;
+
+ if (isset($connection_timeout)) {
+ $this->connectionTimeout = $connection_timeout;
+ }
+ }
+
+ /**
+ * Check if we can connect and log into the mailbox
+ *
+ * @return string
+ */
+ function initMailbox($dry_run = false)
+ {
+ if ($this->connect() === false) {
+ return 'socket';
+ }
+ elseif ($this->auth() === false) {
+ $this->close();
+ return 'login';
+ }
+ elseif ($this->getMessageList() === false) {
+ $this->close();
+ return 'list';
+ }
+ elseif (empty($this->messageSizes)) {
+ $this->close();
+ return 'empty'; // Still 'good'
+ }
+ elseif ($dry_run) {
+ $this->close();
+ return 'success';
+ }
+
+ return true;
+ }
+
+ /**
+ * Logs failed logins to our server
+ *
+ * @param int $error error code
+ * @param Array $error_array params of error
+ */
+ function error($error, $error_array)
+ {
+ trigger_error('POP3 Error. Code: ' . $error . '; Params: ' . print_r($error_array, true), E_USER_WARNING);
+ }
+
+ /**
+ * Connect to the server
+ *
+ * @return bool
+ */
+ function connect()
+ {
+ // Apparently fsockopen() doesn't return false in these cases:
+ if (empty($this->serverInfo['server'])) {
+ return false;
+ }
+
+ if ($this->connected == true) {
+ return true;
+ }
+
+ $this->fp = @fsockopen($this->serverInfo['server'], intval($this->serverInfo['port']), $error_no, $error_str, $this->connectionTimeout);
+
+ if (!is_resource($this->fp)) {
+ $this->error(101, $this->serverInfo);
+ return false;
+ }
+
+ $this->connected = true;
+ $buffer = fgets($this->fp, 4096);
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->error(101, $this->serverInfo);
+ $this->close();
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ /**
+ * Close connection to the server
+ *
+ */
+ function close()
+ {
+ if ($this->connected == true) { // and is_resource($this->fp)) {
+ $this->connected = false;
+ @fputs($this->fp, "QUIT\r\n");
+ @fclose($this->fp);
+ }
+ }
+
+ /**
+ * Login to the server
+ *
+ * @param bool $dry_run
+ * @return bool
+ */
+ function auth($dry_run = false)
+ {
+ if (!is_resource($this->fp) && ($this->connect() === false)) {
+ return false;
+ }
+
+ fputs($this->fp, 'USER ' . $this->serverInfo['username'] . "\r\n");
+ $buffer = fgets($this->fp, 4096);
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->close();
+ return false;
+ }
+
+ fputs($this->fp, 'PASS ' . $this->serverInfo['password'] . "\r\n");
+ $buffer = fgets($this->fp, 4096);
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->error(102, $this->serverInfo);
+ $this->close();
+
+ return false;
+ }
+ else {
+ if ($dry_run) {
+ $this->close();
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Get the list of messages and their ID's
+ *
+ * @return bool
+ */
+ function getMessageList()
+ {
+ fputs($this->fp, "LIST\r\n");
+
+ if (substr(fgets($this->fp, 4096), 0, 3) != '+OK') {
+ $this->close();
+ return false;
+ }
+
+ // Store the message numbers and sizes
+ $buffer = fgets($this->fp, 4096);
+
+ while ($buffer != ".\r\n") {
+ $msginfo = explode(' ', $buffer);
+ $this->messageSizes[ trim($msginfo[0]) ] = trim($msginfo[1]);
+ $buffer = fgets($this->fp, 4096);
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the size of a message
+ *
+ * @param int $message_number
+ * @return int
+ */
+ function getSize($message_number)
+ {
+ return $this->messageSizes["$message_number"];
+ }
+
+ /**
+ * Gets email number $message_number from the server
+ *
+ * @param int $message_number
+ * @param string $source
+ * @return string
+ */
+ function getEmail($message_number, &$source)
+ {
+ return $this->getData("RETR $message_number\r\n", $source);
+ }
+
+ /**
+ * Gets the top $lines from the message
+ *
+ * @param int $message_number
+ * @param string $source
+ * @param int $lines
+ * @param string $stopat
+ * @param bool $onelineonly
+ * @return string
+ */
+ function getTop($message_number, &$source, $lines = 0, $stopat = '', $onelineonly = false)
+ {
+ return $this->getData("TOP $message_number $lines\r\n", $source, $stopat, $onelineonly);
+ }
+
+ /**
+ * Issues $command and returns the output
+ *
+ * @param string $command
+ * @param string $source
+ * @param string $stopat
+ * @param bool $onelineonly
+ * @return string
+ */
+ function getData($command, &$source, $stopat = '', $onelineonly = false)
+ {
+ fputs($this->fp, $command);
+
+ if (substr(fgets($this->fp, 4096), 0, 3) != '+OK') {
+ return false;
+ }
+
+ $source = '';
+ $buffer = fgets($this->fp, 4096);
+
+ while ($buffer != ".\r\n") {
+ if (!$onelineonly) {
+ $source .= $buffer;
+ }
+
+ if (!empty($stopat)) {
+ if (strtolower(substr(trim($buffer), 0, strlen($stopat))) == strtolower($stopat)) {
+ if ($onelineonly) {
+ $source = $buffer;
+ }
+ else {
+ $onelineonly = true;
+ }
+
+ $stopat = '';
+ }
+ }
+
+ $buffer = fgets($this->fp, 4096);
+ }
+
+ return true;
+ }
+
+ /**
+ * Sends the given command to the server and returns true or false on success
+ *
+ * @param string $command
+ * @return bool
+ */
+ function sendCommand($command)
+ {
+ fputs($this->fp, $command . "\r\n");
+ $buffer = trim(fgets($this->fp, 4096));
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->error(103, Array ('cmd' => $command, 'resp' => $buffer));
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ /**
+ * Delete message number $message_number from the server
+ *
+ * @param int $message_number
+ * @return bool
+ */
+ function deleteEmail($message_number)
+ {
+ return $this->sendCommand("DELE $message_number");
+ }
+
+ /**
+ * Create new instance of object
+ *
+ * @return kBase
+ */
+ function &makeClass($server_info, $connection_timeout = null)
+ {
+ $object = new POP3Helper($server_info, $connection_timeout);
+
+ return $object;
+ }
+ }
\ No newline at end of file
Index: units/submission_log/submission_log_config.php
===================================================================
--- units/submission_log/submission_log_config.php (revision 0)
+++ units/submission_log/submission_log_config.php (revision 0)
@@ -0,0 +1,116 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => 'submission-log',
+ 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
+ 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
+ 'EventHandlerClass' => Array ('class' => 'SubmissionLogEventHandler', 'file' => 'submission_log_eh.php', 'build_event' => 'OnBuild'),
+ 'TagProcessorClass' => Array ('class' => 'SubmissionLogTagProcessor', 'file' => 'submission_log_tp.php', 'build_event' => 'OnBuild'),
+
+ 'AutoLoad' => true,
+
+ 'QueryString' => Array (
+ 1 => 'id',
+ 2 => 'Page',
+ 3 => 'event',
+ 4 => 'form_id'
+ ),
+
+ 'IDField' => 'SubmissionLogId',
+
+ 'TableName' => TABLE_PREFIX . 'SubmissionLog',
+
+ 'StatusField' => Array ('ReplyStatus'),
+
+ 'ParentPrefix' => 'formsubs',
+ 'ForeignKey' => 'FormSubmissionId',
+ 'ParentTableKey' => 'FormSubmissionId',
+ 'AutoDelete' => true,
+ 'AutoClone' => true,
+
+ 'TitleField' => 'Subject',
+
+ 'ListSQLs' => Array (
+ '' => ' SELECT %1$s.* %2$s FROM %1$s',
+ ),
+
+ 'ListSortings' => Array (
+ '' => Array (
+ 'Sorting' => Array ('SubmissionLogId' => 'desc'),
+ )
+ ),
+
+ 'Fields' => Array (
+ 'SubmissionLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'FormSubmissionId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+
+ 'FromEmail' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'regexp' => '/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/',
+ 'not_null' => 1, 'required' => 1, 'default' => ''
+ ),
+
+ 'ToEmail' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'regexp' => '/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/',
+ 'not_null' => 1, 'required' => 1, 'default' => ''
+ ),
+
+ 'Cc' => Array ('type' => 'string', 'default' => NULL),
+ 'Bcc' => Array ('type' => 'string', 'default' => NULL),
+ 'Subject' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'required' => 1, 'default' => ''),
+ 'Message' => Array ('type' => 'string', 'required' => 1, 'using_fck' => 1, 'default' => NULL),
+
+ 'Attachment' => Array (
+ 'type' => 'string',
+ 'formatter' => 'kUploadFormatter', 'upload_dir' => SUBMISSION_LOG_ATTACHMENT_PATH,
+ 'file_types' => '*.*', 'files_description' => '!la_hint_AnyFiles!', 'multiple' => 100,
+ 'default' => NULL
+ ),
+
+ 'ReplyStatus' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0 // create as not replied
+ ),
+
+ 'SentStatus' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No', 2 => 'la_opt_Bounce'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0 // create as not sent
+ ),
+
+ 'SentOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
+ 'RepliedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
+ 'VerifyCode' => Array ('type' => 'string', 'max_len' => 32, 'not_null' => 1, 'default' => ''),
+ 'DraftId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'MessageId' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'BounceInfo' => Array ('type' => 'string', 'default' => NULL),
+ 'BounceDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
+ ),
+
+ 'VirtualFields' => Array (
+ 'ReplyTo' => Array ('type' => 'int', 'default' => null),
+ ),
+
+ 'Grids' => Array (
+ 'Default' => Array (
+ 'Icons' => Array (0 => 'icon16_not_replied.gif', 1 => 'icon16_replied.gif'),
+ 'Fields' => Array (
+ 'SubmissionLogId' => Array ('title' => 'la_col_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', ),
+ 'Subject' => Array ('title' => 'la_col_Subject', 'data_block' => 'grid_subject_td', 'filter_block' => 'grid_like_filter',),
+ 'Message' => Array ('title' => 'la_col_Message', 'filter_block' => 'grid_like_filter', 'first_chars' => 100),
+ 'ReplyStatus' => Array ('title' => 'la_col_ReplyStatus', 'filter_block' => 'grid_options_filter',),
+ 'SentStatus' => Array ('title' => 'la_col_SentStatus', 'filter_block' => 'grid_options_filter',),
+ 'FromEmail' => Array ('title' => 'la_col_FromEmail', 'filter_block' => 'grid_like_filter',),
+ 'ToEmail' => Array ('title' => 'la_col_ToEmail', 'filter_block' => 'grid_like_filter',),
+ 'SentOn' => Array ('title' => 'la_col_SentOn', 'filter_block' => 'grid_date_range_filter',),
+ 'RepliedOn' => Array ('title' => 'la_col_RepliedOn', 'filter_block' => 'grid_date_range_filter',),
+ 'Cc' => Array ('title' => 'la_col_Cc', 'filter_block' => 'grid_like_filter', 'hidden' => 1),
+ 'Bcc' => Array ('title' => 'la_col_Bcc', 'filter_block' => 'grid_like_filter', 'hidden' => 1),
+ 'BounceInfo' => Array ('title' => 'la_col_BounceInfo', 'filter_block' => 'grid_like_filter', 'hidden' => 1),
+ 'BounceDate' => Array ('title' => 'la_col_BounceDate', 'filter_block' => 'grid_date_range_filter', 'hidden' => 1),
+ ),
+ ),
+ ),
+ );
\ No newline at end of file
Index: units/submission_log/submission_log_eh.php
===================================================================
--- units/submission_log/submission_log_eh.php (revision 0)
+++ units/submission_log/submission_log_eh.php (revision 0)
@@ -0,0 +1,672 @@
+<?php
+
+ class SubmissionLogEventHandler extends kDBEventHandler {
+
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+ $permissions = Array (
+ 'OnResendReply' => Array ('subitem' => 'add|edit'),
+ 'OnSaveDraft' => Array ('subitem' => 'add|edit'),
+ 'OnUseDraft' => Array ('subitem' => 'add|edit'),
+ 'OnDeleteDraft' => Array ('subitem' => 'add|edit'),
+
+ 'OnProcessBounceMail' => Array ('subitem' => true),
+ );
+
+ $this->permMapping = array_merge($this->permMapping, $permissions);
+ }
+
+ /**
+ * Checks event permissions
+ *
+ * @param kEvent $event
+ * @return bool
+ */
+ function CheckPermission(&$event)
+ {
+ $section = $event->getSection();
+ $form_id = $this->Application->GetVar('form_id');
+
+ if ($form_id) {
+ // copy form_id to env to be passed info upload links
+ $this->Application->SetVar($event->getPrefixSpecial() . '_form_id', $form_id);
+ }
+ else {
+ $form_id = $this->Application->GetVar($event->getPrefixSpecial() . '_form_id');
+ }
+
+ $event->setEventParam('PermSection', $section . ':' . $form_id);
+
+ return parent::CheckPermission($event);
+ }
+
+ /**
+ * Prepares new kDBItem object
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnNew(&$event)
+ {
+ parent::OnNew($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $form_submission =& $this->Application->recallObject('formsubs');
+ /* @var $form_submission kDBItem */
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+
+ $from_email = $form->GetDBField('ReplyFromEmail');
+ $to_email = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_EMAIL);
+
+ if ($this->Application->GetVar('client_mode')) {
+ // debug code for sending email from client
+ $object->SetDBField('FromEmail', $to_email);
+ $object->SetDBField('ToEmail', $from_email);
+
+ }
+ else {
+ $object->SetDBField('FromEmail', $from_email);
+ $object->SetDBField('ToEmail', $to_email);
+ }
+
+ $object->SetDBField('Cc', $form->GetDBField('ReplyCc'));
+ $object->SetDBField('Bcc', $form->GetDBField('ReplyBcc'));
+
+ $ids = $this->StoreSelectedIDs($event);
+ if ($ids) {
+ $org_message =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
+ /* @var $org_message kDBItem */
+
+ $org_message->Load( array_shift($ids) );
+ // client could reply from different email, so compare to admin email!
+ if ($org_message->GetDBField('ToEmail') == $from_email) {
+ // can reply only to client email, not own :)
+
+ // transform subject
+ $message_subject = $org_message->GetDBField('Subject');
+
+ if ($message_subject) {
+ $object->SetDBField('Subject', $this->_transformSubject($message_subject, 'Re'));
+ }
+
+ // add signature
+ $message_body = $form->GetDBField('ReplyMessageSignature');
+
+ if ($org_message->GetDBField('Message')) {
+ // add replied marks
+ $message_body .= '> ' . preg_replace('/([\r]*\n)/', '\\1> ', $org_message->GetDBField('Message'));
+ }
+
+ $object->SetDBField('ToEmail', $org_message->GetDBField('FromEmail')); // user client's email from reply
+ $object->SetDBField('Message', $message_body);
+ $object->SetDBField('ReplyTo', $org_message->GetID());
+ }
+ }
+ else {
+ $sql = 'SELECT COUNT(*)
+ FROM ' . $object->TableName . '
+ WHERE FormSubmissionId = ' . $form_submission->GetID();
+ $replies_found = $this->Conn->GetOne($sql);
+
+ if (!$replies_found) {
+ // 1st message from admin -> quote subject & text from feedback
+ $message_subject = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_SUBJECT);
+
+ if ($message_subject) {
+ $object->SetDBField('Subject', $this->_transformSubject($message_subject, 'Re'));
+ }
+
+ // add signature
+ $message_body = $form->GetDBField('ReplyMessageSignature');
+
+ // add replied marks
+ $original_message_body = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_BODY);
+
+ if ($original_message_body) {
+ $message_body .= '> ' . preg_replace('/([\r]*\n)/', '\\1> ', $original_message_body);
+ }
+
+ $object->SetDBField('Message', $message_body);
+ }
+ }
+
+ $this->clearSelectedIDs($event);
+ }
+
+ /**
+ * Parses $search string in subject and reformats it
+ * Used for replying and forwarding
+ *
+ * @param string $subject
+ * @param string $search
+ * @return string
+ */
+ function _transformSubject($subject, $search = 'Re')
+ {
+ $regex = '/'.$search.'(\[([\d]+)\]){0,1}:/i';
+ preg_match_all($regex, $subject, $regs);
+
+ if ($regs[2]) {
+ $reply_count = 0; // reply count without numbers (equals to "re[1]")
+ $max_reply_number = 0; // maximal reply number
+ sort($regs[2], SORT_NUMERIC); // sort ascending (non-numeric replies first)
+ foreach ($regs[2] as $match) {
+ if (!$match) {
+ // found "re:"
+ $reply_count++;
+ }
+ elseif ($match > $max_reply) {
+ // found "re:[number]"
+ $max_reply_number = $match;
+ }
+ }
+
+ return $search.'['.($reply_count + $max_reply_number + 1).']: '.trim(preg_replace($regex, '', $subject));
+ }
+
+ return $search.': '.$subject;
+ }
+
+ /**
+ * Resends reply, that was not sent last time
+ *
+ * @param kEvent $event
+ */
+ function OnResendReply(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $form_submission =& $this->_getFormSubmission($object);
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+ $reply_email = $form->GetDBField('ReplyFromEmail');
+
+ $ids = $this->StoreSelectedIDs($event);
+
+ foreach ($ids as $id) {
+ $object->Load($id);
+
+ // allow to send messages, that were successfully sended before :(
+ if (($object->GetDBField('ToEmail') != $reply_email) && ($object->GetDBField('SentStatus') != SUBMISSION_LOG_SENT)) {
+ $object->SetOriginalField('SentStatus', 0); // reset sent status to update sent date automatically
+
+ $this->_sendEmail($object); // resend email here
+ }
+ }
+
+ $this->clearSelectedIDs($event);
+
+ $event->SetRedirectParam('opener', 'u');
+ }
+
+ /**
+ * Updates last operation dates for log record
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $this->_validateRecipients($event);
+ $this->_updateStatusDates($event);
+ }
+
+ /**
+ * Updates last operation dates for log record
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+ parent::OnBeforeItemUpdate($event);
+
+ $this->_validateRecipients($event);
+ $this->_updateStatusDates($event);
+ }
+
+ /**
+ * Validates email recipients
+ *
+ * @param kEvent $event
+ */
+ function _validateRecipients(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $esender =& $this->Application->recallObject('EmailSender');
+ /* @var $esender kEmailSendingHelper */
+
+ $cc = $object->GetDBField('Cc');
+
+ if ($cc && ($esender->GetRecipients($cc) === false)) {
+ $object->SetError('Cc', 'invalid_format');
+ }
+
+ $bcc = $object->GetDBField('Bcc');
+
+ if ($bcc && ($esender->GetRecipients($bcc) === false)) {
+ $object->SetError('Bcc', 'invalid_format');
+ }
+ }
+
+ /**
+ * Generates verification code and sets it inside sent message
+ *
+ * @param kDBItem $object
+ * @return string
+ */
+ function _generateVerificationCode(&$object)
+ {
+ $code = Array (
+ $object->GetDBField('FromEmail'),
+ $object->GetDBField('ToEmail'),
+ $object->GetID(),
+ getmicrotime()
+ );
+
+ $object->SetDBField('VerifyCode', md5( implode('-', $code) ));
+ }
+
+ /**
+ * Sends email based on fields from given submission-log record
+ *
+ * @param kDBItem $object
+ */
+ function _sendEmail(&$object)
+ {
+ if ($this->Application->GetVar('client_mode')) {
+ return ;
+ }
+
+ if (!$object->GetDBField('VerifyCode')) {
+ $this->_generateVerificationCode($object);
+ }
+
+ $form_submission =& $this->_getFormSubmission($object);
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+
+ $send_params = Array (
+ 'from_name' => $form->GetDBField('ReplyFromName'),
+ 'from_email' => $object->GetDBField('FromEmail'),
+
+ 'to_email' => $object->GetDBField('ToEmail'),
+
+ 'subject' => $object->GetDBField('Subject'),
+ 'message' => $object->GetDBField('Message'),
+ );
+
+ $to_name = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_NAME);
+
+ if ($to_name) {
+ $send_params['to_name'] = $to_name;
+ }
+
+ $esender =& $this->Application->recallObject('EmailSender');
+ /* @var $esender kEmailSendingHelper */
+
+ $esender->SetReturnPath( $form->GetDBField('BounceEmail') );
+
+ if ($object->GetDBField('Cc')) {
+ $recipients = $esender->GetRecipients( $object->GetDBField('Cc') );
+
+ foreach ($recipients as $recipient_info) {
+ $esender->AddCc($recipient_info['Email'], $recipient_info['Name']);
+ }
+ }
+
+ if ($object->GetDBField('Bcc')) {
+ $recipients = $esender->GetRecipients( $object->GetDBField('Bcc') );
+
+ foreach ($recipients as $recipient_info) {
+ $esender->AddBcc($recipient_info['Email'], $recipient_info['Name']);
+ }
+ }
+
+ if ($object->GetDBField('Attachment')) {
+ $attachments = explode('|', $object->GetField('Attachment', 'file_paths'));
+
+ foreach ($attachments as $attachment) {
+ $esender->AddAttachment($attachment);
+ }
+ }
+
+ $this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.TO.USER', null, $send_params);
+
+ // mark as sent after sending is finished
+ $object->SetDBField('SentStatus', SUBMISSION_LOG_SENT);
+
+ // reset bounce status before (re-)sending
+ $object->SetDBField('BounceInfo', NULL);
+ $object->SetDBField('BounceDate_date', NULL);
+ $object->SetDBField('BounceDate_time', NULL);
+
+ if ($object->GetDBField('DraftId')) {
+ $temp_handler =& $this->Application->recallObject('draft_TempHandler', 'kTempTablesHandler');
+ /* @var $temp_handler kTempTablesHandler */
+
+ $temp_handler->DeleteItems('draft', '', Array ($object->GetDBField('DraftId')));
+ $object->SetDBField('DraftId', 0);
+ }
+
+ $object->Update();
+ }
+
+ /**
+ * Sends new email after log record was created
+ * Updates last update time for submission
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemCreate(&$event)
+ {
+ parent::OnAfterItemCreate($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $this->_sendEmail($object); // send email
+
+ $this->_updateSubmission($event);
+
+ $reply_to = $object->GetDBField('ReplyTo');
+ if (!$reply_to) {
+ $reply_to = $this->_getLastMessageId($event, !$this->Application->GetVar('client_mode'));
+ }
+
+ if ($reply_to) {
+ // this is reply to other message -> mark it as replied
+ $org_message =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
+ /* @var $org_message kDBItem */
+
+ $org_message->Load($reply_to);
+ $org_message->SetDBField('ReplyStatus', SUBMISSION_LOG_REPLIED);
+ $org_message->Update();
+ }
+
+ if ($this->Application->GetVar('client_mode')) {
+ // new reply from client received -> send notification about it
+ $this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.FROM.USER');
+ }
+ }
+
+ /**
+ * Returns last message id (client OR admin)
+ *
+ * @param kEvent $event
+ * @param bool $from_client
+ * @return int
+ */
+ function _getLastMessageId(&$event, $from_client = false)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $form_submission =& $this->_getFormSubmission($object);
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+ $reply_email = $form->GetDBField('ReplyFromEmail');
+
+ $sql = 'SELECT MAX(' . $object->IDField . ')
+ FROM ' . $object->TableName . '
+ WHERE (FormSubmissionId = ' . $form_submission->GetID() . ') AND (ToEmail' . ($from_client ? ' = ' : ' <> ') . $this->Conn->qstr($reply_email) . ')';
+ return $this->Conn->GetOne($sql);
+ }
+
+ /**
+ * Updates last update time for submission
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemUpdate(&$event)
+ {
+ parent::OnAfterItemUpdate($event);
+
+ $this->_updateSubmission($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ // send out email event to admin for bouncing
+ if ( $object->GetOriginalField('SentStatus') != $object->GetDBField('SentStatus')
+ && $object->GetDBField('SentStatus') == SUBMISSION_LOG_BOUNCE ) {
+
+ $this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED');
+ }
+ }
+
+ /**
+ * Sets last sent/reply dates based on field changes in log record
+ *
+ * @param kEvent $event
+ */
+ function _updateStatusDates(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $now = adodb_mktime();
+
+ $sent_status = $object->GetDBField('SentStatus');
+ if (($sent_status == SUBMISSION_LOG_SENT) && ($sent_status != $object->GetOriginalField('SentStatus'))) {
+ // sent status was set
+ $object->SetDBField('SentOn_date', $now);
+ $object->SetDBField('SentOn_time', $now);
+ }
+
+ $reply_status = $object->GetDBField('ReplyStatus');
+ if (($reply_status == SUBMISSION_LOG_REPLIED) && ($reply_status != $object->GetOriginalField('ReplyStatus'))) {
+ // sent status was set
+ $object->SetDBField('RepliedOn_date', $now);
+ $object->SetDBField('RepliedOn_time', $now);
+ }
+ }
+
+ /**
+ * Returns form submission by given event of submission log
+ *
+ * @param kDBItem $object
+ * @return kDBItem
+ */
+ function &_getFormSubmission(&$object)
+ {
+ $submission_id = $object->GetDBField('FormSubmissionId');
+
+ $form_submission =& $this->Application->recallObject('formsubs.-item', null, Array ('skip_autoload' => true));
+ /* @var $form_submission kDBItem */
+
+ if ($form_submission->isLoaded() && ($form_submission->GetID() == $submission_id)) {
+ // already loaded AND has needed id
+ return $form_submission;
+ }
+
+ $form_submission->Load($submission_id);
+
+ return $form_submission;
+ }
+
+ /**
+ * Sets last updated field for form submission
+ *
+ * @param kEvent $event
+ */
+ function _updateSubmission(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $form_submission =& $this->_getFormSubmission($object);
+
+ // 1. set last updated
+ $last_updated = max ($object->GetDBField('SentOn'), $object->GetDBField('RepliedOn'));
+
+ if ($form_submission->GetDBField('LastUpdatedOn') < $last_updated) {
+ // don't set smaller last update, that currenly set
+ $form_submission->SetDBField('LastUpdatedOn_date', $last_updated);
+ $form_submission->SetDBField('LastUpdatedOn_time', $last_updated);
+ }
+
+ // 2. update submission status
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+ $client_responce = $form->GetDBField('ReplyFromEmail') == $object->GetDBField('ToEmail');
+ $replied = $object->GetDBField('ReplyStatus') == SUBMISSION_LOG_REPLIED;
+
+ if (!$client_responce && !$replied) {
+ // admin sends new email to client
+ $form_submission->SetDBField('LogStatus', SUBMISSION_REPLIED);
+ }
+ elseif ($client_responce) {
+ // client email becomes replied OR receiving new unreplied email from client
+ $form_submission->SetDBField('LogStatus', $replied ? SUBMISSION_REPLIED : SUBMISSION_NEW_EMAIL);
+ }
+
+ if ($object->GetDBField('SentStatus') == SUBMISSION_LOG_BOUNCE) {
+ // propagate bounce status from reply
+ $form_submission->SetDBField('LogStatus', SUBMISSION_BOUNCE);
+ }
+
+ $form_submission->Update();
+ }
+
+ /**
+ * Saves current unsent message as draft
+ *
+ * @param kEvent $event
+ */
+ function OnSaveDraft(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ foreach ($items_info as $id => $field_values) {
+ $object->setID($id);
+ $object->SetFieldsFromHash($field_values);
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+
+ $draft->SetDBField('Message', $object->GetDBField('Message'));
+
+ if ($draft->isLoaded()) {
+ $draft->Update();
+ }
+ else {
+ $draft->SetDBFieldsFromHash($load_keys);
+ $draft->Create();
+ }
+ }
+ }
+
+ $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
+ $event->SetRedirectParam('opener', 'u');
+ }
+
+ /**
+ * Uses found draft instead of submission reply body
+ *
+ * @param kEvent $event
+ */
+ function OnUseDraft(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ foreach ($items_info as $id => $field_values) {
+ $object->setID($id);
+ $object->SetFieldsFromHash($field_values);
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+ if ($draft->isLoaded()) {
+ $object->SetDBField('Message', $draft->GetDBField('Message'));
+ $object->SetDBField('DraftId', $draft->GetID());
+ }
+ }
+ }
+
+ $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
+ $event->redirect = false;
+ }
+
+ /**
+ * Deletes draft, that matches given user and form submission
+ *
+ * @param kEvent $event
+ */
+ function OnDeleteDraft(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ foreach ($items_info as $id => $field_values) {
+ $object->setID($id);
+ $object->SetFieldsFromHash($field_values);
+ $object->SetDBField('DraftId', 0);
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+ if ($draft->isLoaded()) {
+ $temp_handler =& $this->Application->recallObject('draft_TempHandler', 'kTempTablesHandler');
+ /* @var $temp_handler kTempTablesHandler */
+
+ $temp_handler->DeleteItems('draft', '', Array ($draft->GetID()));
+ }
+ }
+ }
+
+ $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
+ $event->redirect = false;
+ }
+ }
\ No newline at end of file
Index: units/submission_log/submission_log_tp.php
===================================================================
--- units/submission_log/submission_log_tp.php (revision 0)
+++ units/submission_log/submission_log_tp.php (revision 0)
@@ -0,0 +1,99 @@
+<?php
+
+ class SubmissionLogTagProcessor extends kDBTagProcessor {
+
+ /**
+ * Checks, that current log record is mail from client to admin and it's not replied
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function IsNewUserReply($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $user_reply = $this->IsUserReply($params);
+
+ return $user_reply && ($object->GetDBField('ReplyStatus') != SUBMISSION_LOG_REPLIED);
+ }
+
+ /**
+ * Checks, that current log record is mail from client to admin
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function IsUserReply($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $reply_email = $this->Application->ConfigValue('SubmissionReplyFromEmail');
+
+ return $object->GetDBField('ToEmail') == $reply_email;
+ }
+
+ /**
+ * Checks if there is draft for given article
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function HasDraft($params)
+ {
+ if (!$this->IsNewItem($params)) {
+ // use drafts only for unsent (new) messages
+ return false;
+ }
+
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+
+ return $draft->isLoaded();
+ }
+
+ /**
+ * Lists all files, uploadeded to given field
+ *
+ * @param Array $params
+ * @return string
+ */
+ function IterateFiles($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $field = $this->SelectParam($params, 'name,field');
+ $value = $object->GetDBField($field);
+
+ if (!$value) {
+ return '';
+ }
+
+ $ret = '';
+ $files = explode('|', $value);
+ $block_params = $this->prepareTagParams($params);
+ $block_params['name'] = $params['render_as'];
+
+ foreach ($files as $file) {
+ $object->SetDBField($field, $file);
+ $ret .= $this->Application->ParseBlock($block_params);
+ }
+
+ $object->SetDBField($field, $value);
+
+ return $ret;
+ }
+ }
\ No newline at end of file
img.rar [^] (132,806 bytes) 2010-04-21 11:09
form_submissions_themes.patch [^] (3,140 bytes) 2010-04-21 11:10
[Show Content]
Index: advanced/platform/designs/form.tpl
===================================================================
--- advanced/platform/designs/form.tpl (revision 13377)
+++ advanced/platform/designs/form.tpl (working copy)
@@ -3,6 +3,11 @@
<DESC>Online Form</DESC>
<SECTION>Platform</SECTION>
##-->
+
+<inp2:m_if check="form_Field" name="RequireLogin" db="db">
+ <inp2:m_RequireLogin login_template="platform/login/register"/>
+</inp2:m_if>
+
<inp2:m_include template="platform/elements/dynamic_forms.elm"/>
<!--## PAGE TITLE ELEMENT ##-->
@@ -51,6 +56,11 @@
<table class="form-data fullwidth">
<inp2:formflds_PrintList render_as="form_field" SourcePrefix="formsubs" per_page="-1"/>
+ <inp2:m_if check="form_Field" name="UseSecurityImage" db="db">
+ <inp2:m_RenderElement name="inp_edit_field_separator" is_last="0"/>
+ <inp2:m_RenderElement name="inp_edit_captcha" prefix="formsubs" is_last="1"/>
+ </inp2:m_if>
+
<inp2:m_RenderElement design="inp_edit_buttons">
<input type="submit" class="button" name="events[formsubs][OnCreate]" value="<inp2:m_Phrase label="lu_send" no_editing="1"/>"/>
Index: default/designs/form.tpl
===================================================================
--- default/designs/form.tpl (revision 13377)
+++ default/designs/form.tpl (working copy)
@@ -40,6 +40,10 @@
<inp2:formflds_PrintList render_as="form_field" SourcePrefix="formsubs" per_page="-1"/>
+ <inp2:m_if check="form_Field" name="UseSecurityImage" db="db">
+ <inp2:m_RenderElement name="inp_edit_captcha" prefix="formsubs"/>
+ </inp2:m_if>
+
<p class="button">
<input type="reset" name="reset" value="<inp2:m_Phrase label='lu_btn_Reset' no_editing='1'/>" />
<input type="submit" name="events[formsubs][OnCreate]" value="<inp2:m_Phrase label='lu_btn_Send' no_editing='1'/>" class="submit"/>
Index: default/elements/dynamic_forms.elm.tpl
===================================================================
--- default/elements/dynamic_forms.elm.tpl (revision 13377)
+++ default/elements/dynamic_forms.elm.tpl (working copy)
@@ -62,4 +62,17 @@
##-->
<inp2:ConfigFormElement field="Value" blocks_prefix="form_field_" element_type_field="ElementType" value_list_field="ValueList" />
</p>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="inp_edit_captcha" style="" title="lu_fld_Captcha" no_editing="1" is_last="0">
+ <p>
+ <label for="<inp2:{$prefix}_InputName field='Captcha'/>" <inp2:m_if check="{$prefix}_HasError" field="Captcha">class="red"</inp2:m_if>>
+ <inp2:m_phrase label="$title"/> <inp2:m_if check="{$prefix}_IsRequired" field="Captcha"><span class="red">*</span></inp2:m_if>
+ </label>
+
+ <em>
+ <img src="<inp2:m_Link template="elements/captcha_image.elm" var="{$prefix}_captcha_code" w="150" h="30"/>" alt="<inp2:m_Phrase name="$title" no_editing="1"/>"/><br />
+ <input type="text" class="field" name="<inp2:{$prefix}_InputName field="Captcha"/>" value="<inp2:{$prefix}_Field field="Captcha"/>">
+ </em>
+ </p>
</inp2:m_DefineElement>
\ No newline at end of file
Mailbox_DBG_output.jpg [^] (144,776 bytes) 2010-04-22 10:11

form_submissions_core_v2.patch [^] (198,050 bytes) 2010-04-22 15:46
[Show Content]
Index: admin/system_presets/simple/form_submissions_formsubs.php
===================================================================
--- admin/system_presets/simple/form_submissions_formsubs.php (revision 13377)
+++ admin/system_presets/simple/form_submissions_formsubs.php (working copy)
@@ -8,7 +8,7 @@
// 'formsubs_list' => Array ('edit', 'delete', 'dbl-click'),
// editing form
-// 'formsubs_view' => Array ('cancel', 'prev', 'next'),
+// 'formsubs_view' => Array ('select', 'cancel', 'prev', 'next'),
);
// fields to hide
Index: core/admin_templates/forms/form_edit_emails.tpl
===================================================================
--- core/admin_templates/forms/form_edit_emails.tpl (revision 0)
+++ core/admin_templates/forms/form_edit_emails.tpl (revision 0)
@@ -0,0 +1,105 @@
+<inp2:adm_SetPopupSize width="800" height="500"/>
+<inp2:m_include t="incs/header" />
+
+<inp2:m_RenderElement name="combined_header" section="in-portal:forms" prefix="form" title_preset="form_edit_emails" tab_preset="Default"/>
+
+<!-- ToolBar -->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+<tbody>
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+ a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
+ submit_event('form','<inp2:form_SaveEvent/>');
+ }
+ ) );
+ a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
+ submit_event('form','OnCancelEdit');
+ }
+ ) );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+ a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
+ go_to_id('form', '<inp2:form_PrevId/>');
+ }
+ ) );
+ a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
+ go_to_id('form', '<inp2:form_NextId/>');
+ }
+ ) );
+
+ //a_toolbar.AddButton( new ToolBarSeparator('sep2') );
+
+ a_toolbar.Render();
+
+ <inp2:m_if check="form_IsSingle" >
+ a_toolbar.HideButton('prev');
+ a_toolbar.HideButton('next');
+ a_toolbar.HideButton('sep1');
+ //a_toolbar.HideButton('sep2');
+ <inp2:m_else/>
+ <inp2:m_if check="form_IsLast" >
+ a_toolbar.DisableButton('next');
+ </inp2:m_if>
+ <inp2:m_if check="form_IsFirst" >
+ a_toolbar.DisableButton('prev');
+ </inp2:m_if>
+ </inp2:m_if>
+ </script>
+ </td>
+ </tr>
+</tbody>
+</table>
+
+<inp2:form_SaveWarning name="grid_save_warning"/>
+<inp2:form_ErrorWarning name="form_error_warning"/>
+
+<div id="scroll_container">
+ <table class="edit-form">
+ <inp2:m_RenderElement name="subsection" title="la_title_General"/>
+ <inp2:m_RenderElement name="inp_edit_checkbox" prefix="form" field="EnableEmailCommunication" title="la_fld_Enable" onclick="reflectFromFields();"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyFromName" title="la_fld_ReplyFromName"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyCc" title="la_fld_ReplyCc"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyBcc" title="la_fld_ReplyBcc"/>
+ <inp2:m_RenderElement name="inp_edit_textarea" prefix="form" field="ReplyMessageSignature" title="la_fld_ReplyMessageSignature"/>
+
+ <inp2:m_RenderElement name="subsection" title="la_title_ReplySettings"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyFromEmail" title="la_fld_ReplyFromEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyServer" title="la_fld_Server" hint_label="la_hint_PopServer"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyPort" title="la_fld_Port" hint_label="la_hint_PopPort"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyUsername" title="la_fld_Username"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="ReplyPassword" title="la_fld_Password"/>
+
+ <inp2:m_RenderElement name="subsection" title="la_title_BounceSettings"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BounceEmail" title="la_fld_BounceEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BounceServer" title="la_fld_Server" hint_label="la_hint_PopServer"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BouncePort" title="la_fld_Port" hint_label="la_hint_PopPort"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BounceUsername" title="la_fld_Username"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="form" field="BouncePassword" title="la_fld_Password"/>
+
+ <inp2:m_RenderElement name="inp_edit_filler"/>
+ </table>
+</div>
+
+<script type="text/javascript">
+ var $field_mask = '<inp2:form_InputName field="#FIELD_NAME#" js_escape="1"/>';
+
+ function reflectFromFields() {
+ var $enabled = get_control($field_mask, 'EnableEmailCommunication', undefined, '_cb').checked;
+ var $fields = [
+ 'ReplyFromEmail', 'ReplyServer', 'ReplyPort', 'ReplyUsername', 'ReplyPassword',
+ 'BounceEmail', 'BounceServer', 'BouncePort', 'BounceUsername', 'BouncePassword',
+ 'ReplyFromName', 'ReplyCc', 'ReplyBcc', 'ReplyMessageSignature'
+ ];
+
+ for (var $i = 0; $i < $fields.length; $i++) {
+ get_control($field_mask, $fields[$i]).disabled = !$enabled;
+ }
+ }
+
+ reflectFromFields();
+</script>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: core/admin_templates/forms/form_field_edit.tpl
===================================================================
--- core/admin_templates/forms/form_field_edit.tpl (revision 13377)
+++ core/admin_templates/forms/form_field_edit.tpl (working copy)
@@ -1,3 +1,5 @@
+<inp2:adm_SetPopupSize width="780" height="570"/>
+
<inp2:m_include t="incs/header" />
<inp2:m_RenderElement name="combined_header" section="in-portal:forms" prefix="form" title_preset="form_field_edit"/>
@@ -37,7 +39,7 @@
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="FieldName" title="!la_prompt_FieldName!" size="40"/>
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="FieldLabel" title="!la_prompt_FieldLabel!" size="40"/>
- <inp2:m_RenderElement name="subsection" prefix="" fields="Prompt,ElementType,Validation,ValueList,DefaultValue,Priority,Required,DisplayInGrid" title="!la_tab_AdminUI!"/>
+ <inp2:m_RenderElement name="subsection" prefix="formflds" fields="Prompt,ElementType,Validation,ValueList,DefaultValue,Priority,Required,DisplayInGrid,Visibility,EmailCommunicationRole" title="!la_tab_AdminUI!"/>
<!--<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="Heading" title="!la_prompt_heading!" size="40"/>-->
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="Prompt" title="!la_prompt_FieldPrompt!" size="40"/>
<inp2:m_RenderElement name="inp_edit_options" prefix="formflds" field="ElementType" title="!la_prompt_InputType!"/>
@@ -47,7 +49,12 @@
<inp2:m_RenderElement name="inp_edit_box" prefix="formflds" field="Priority" title="!la_field_Priority!" size="10"/>
<inp2:m_RenderElement name="inp_edit_checkbox" prefix="formflds" field="Required" title="!la_fld_Required!"/>
<inp2:m_RenderElement name="inp_edit_checkbox" prefix="formflds" field="DisplayInGrid" title="!la_fld_DisplayInGrid!"/>
+ <inp2:m_RenderElement name="inp_edit_radio" prefix="formflds" field="Visibility" title="la_fld_Visibility"/>
+ <inp2:m_if check="form_Field" name="EnableEmailCommunication" db="db">
+ <inp2:m_RenderElement name="inp_edit_options" prefix="formflds" field="EmailCommunicationRole" title="la_fld_EmailCommunicationRole" has_empty="1"/>
+ </inp2:m_if>
+
<inp2:m_if check="m_IsDebugMode">
<inp2:m_RenderElement name="inp_edit_checkbox" prefix="formflds" field="IsSystem" title="!la_fld_IsSystem!"/>
</inp2:m_if>
Index: core/admin_templates/forms/forms_edit.tpl
===================================================================
--- core/admin_templates/forms/forms_edit.tpl (revision 13377)
+++ core/admin_templates/forms/forms_edit.tpl (working copy)
@@ -60,9 +60,29 @@
<table class="edit-form">
<inp2:m_RenderElement name="inp_id_label" prefix="form" field="FormId" title="!la_fld_Id!"/>
<inp2:m_RenderElement name="inp_edit_box" prefix="form" field="Title" title="!la_fld_Title!" size="100"/>
+ <inp2:m_RenderElement name="inp_edit_checkbox" prefix="form" field="RequireLogin" title="la_fld_RequireLogin" onclick="reflectSecurutyImage();"/>
+ <inp2:m_RenderElement name="inp_edit_checkbox" prefix="form" field="UseSecurityImage" title="la_fld_UseSecurityImage"/>
<inp2:m_RenderElement name="inp_edit_textarea" prefix="form" field="Description" title="!la_fld_Description!" cols="60" rows="5"/>
<inp2:m_RenderElement name="inp_edit_filler"/>
</table>
</div>
+<script type="text/javascript">
+ var $field_mask = '<inp2:form_InputName field="#FIELD_NAME#" js_escape="1"/>';
+
+ function reflectSecurutyImage() {
+ var $use_security_image = get_control($field_mask, 'UseSecurityImage', undefined, '_cb');
+
+ if (get_control($field_mask, 'RequireLogin', undefined, '_cb').checked) {
+ $use_security_image.checked = false;
+ $use_security_image.disabled = true;
+ }
+ else {
+ $use_security_image.disabled = false;
+ }
+ }
+
+ reflectSecurutyImage();
+</script>
+
<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: core/admin_templates/img/itemicons/icon16_bounce.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\itemicons\icon16_bounce.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/itemicons/icon16_new_email.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\itemicons\icon16_new_email.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/itemicons/icon16_not_replied.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\itemicons\icon16_not_replied.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/itemicons/icon16_replied.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\itemicons\icon16_replied.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/toolbar/tool_reply.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\toolbar\tool_reply.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/toolbar/tool_reply_f2.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\toolbar\tool_reply_f2.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/toolbar/tool_reply_f3.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\toolbar\tool_reply_f3.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/toolbar/tool_resend.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\toolbar\tool_resend.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/toolbar/tool_resend_f2.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\toolbar\tool_resend_f2.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/img/toolbar/tool_resend_f3.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: core\admin_templates\img\toolbar\tool_resend_f3.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: core/admin_templates/submissions/submission_edit_logs.tpl
===================================================================
--- core/admin_templates/submissions/submission_edit_logs.tpl (revision 0)
+++ core/admin_templates/submissions/submission_edit_logs.tpl (revision 0)
@@ -0,0 +1,149 @@
+<inp2:adm_SetPopupSize width="800" height="640"/>
+
+<inp2:m_include t="incs/header"/>
+<inp2:m_Get var="form_id" result_to_var="form_id"/>
+
+<inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="submission_edit_logs" tab_preset="Default" />
+
+<!-- ToolBar --->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+ <tr>
+ <td>
+ <table width="100%" cellpadding="0" cellspacing="0">
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+
+ a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
+ submit_event('formsubs', '<inp2:formsubs_SaveEvent/>');
+ }
+ ) );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'cancel',
+ '<inp2:m_phrase label="la_ToolTip_Close" escape="1"/>',
+ function() {
+ submit_event('formsubs', 'OnGoBack');
+ }
+ )
+ );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'prev',
+ '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>',
+ function() {
+ go_to_id('formsubs', '<inp2:formsubs_PrevId/>');
+ }
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'next',
+ '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>',
+ function() {
+ go_to_id('formsubs', '<inp2:formsubs_NextId/>');
+ }
+ )
+ );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep2') );
+
+ function edit()
+ {
+ std_edit_temp_item('submission-log', 'submissions/submission_log_edit');
+ }
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'edit',
+ '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>',
+ edit
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'reply',
+ '<inp2:m_phrase label="la_ToolTip_Reply" escape="1"/>',
+ function() {
+ Application.SetVar('client_mode', 0);
+ std_new_item('submission-log', 'submissions/submission_log_edit');
+ }
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'delete',
+ '<inp2:m_phrase label="la_ToolTip_Delete" escape="1"/>',
+ function() {
+ std_delete_items('submission-log')
+ }
+ )
+ );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'resend',
+ '<inp2:m_phrase label="la_ToolTip_Resend" escape="1"/>',
+ function() {
+ Application.SetVar('from_list', 1);
+ submit_event('submission-log', 'OnResendReply');
+ }
+ )
+ );
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep3') );
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'view',
+ '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>',
+ function(id) {
+ show_viewmenu(a_toolbar, 'view');
+ }
+ )
+ );
+
+ a_toolbar.Render();
+
+ <inp2:m_if check="formsubs_IsSingle">
+ a_toolbar.HideButton('prev');
+ a_toolbar.HideButton('next');
+ a_toolbar.HideButton('sep1');
+ <inp2:m_else/>
+ <inp2:m_if check="formsubs_IsLast">
+ a_toolbar.DisableButton('next');
+ </inp2:m_if>
+ <inp2:m_if check="formsubs_IsFirst">
+ a_toolbar.DisableButton('prev');
+ </inp2:m_if>
+ </inp2:m_if>
+ </script>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+
+<inp2:m_DefineElement name="grid_subject_td" format="" nl2br="" first_chars="" td_style="" currency="">
+ <inp2:m_if check="IsNewUserReply">
+ <strong><inp2:Field field="$field" first_chars="$first_chars" currency="$currency" nl2br="$nl2br" grid="$grid" format="$format"/></strong>
+ <inp2:m_else/>
+ <inp2:Field field="$field" first_chars="$first_chars" currency="$currency" nl2br="$nl2br" grid="$grid" format="$format"/>
+ </inp2:m_if>
+</inp2:m_DefineElement>
+
+<inp2:m_RenderElement name="grid" PrefixSpecial="submission-log" IdField="SubmissionLogId" grid="Default"/>
+<script type="text/javascript">
+Grids['submission-log'].SetDependantToolbarButtons( new Array('edit','delete', 'resend') );
+</script>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: core/admin_templates/submissions/submission_log_edit.tpl
===================================================================
--- core/admin_templates/submissions/submission_log_edit.tpl (revision 0)
+++ core/admin_templates/submissions/submission_log_edit.tpl (revision 0)
@@ -0,0 +1,145 @@
+<inp2:adm_SetPopupSize width="820" height="570"/>
+
+<inp2:m_include t="incs/header"/>
+
+<inp2:m_Get var="form_id" result_to_var="form_id"/>
+<inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="submission_log_edit"/>
+
+<!-- ToolBar --->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+
+ <inp2:m_if check="submission-log_IsNewItem">
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'select',
+ '<inp2:m_phrase label="la_ToolTip_Send" escape="1"/>',
+ function() {
+ submit_event('submission-log', '<inp2:submission-log_SaveEvent/>');
+ }
+ )
+ );
+ </inp2:m_if>
+
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'cancel',
+ '<inp2:m_phrase label="la_ToolTip_Close" escape="1"/>',
+ function() {
+ cancel_edit('submission-log', 'OnGoBack', '<inp2:submission-log_SaveEvent/>', '<inp2:m_Phrase label="la_FormCancelConfirmation" escape="1"/>');
+ }
+ )
+ );
+
+ <inp2:m_if check="submission-log_IsUserReply" inverse="inverse">
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'resend',
+ '<inp2:m_phrase label="la_ToolTip_Resend" escape="1"/>',
+ function() {
+ submit_event('submission-log', 'OnResendReply');
+ }
+ )
+ );
+ </inp2:m_if>
+
+ <inp2:m_if check="submission-log_IsNewItem">
+ a_toolbar.AddButton(
+ new ToolBarButton(
+ 'reset_to_user',
+ '<inp2:m_phrase label="la_ToolTip_SaveAsDraft" escape="1"/>',
+ function() {
+ submit_event('submission-log', 'OnSaveDraft');
+ }
+ )
+ );
+ </inp2:m_if>
+
+ a_toolbar.Render();
+ </script>
+
+ <script type="text/javascript" src="js/swfobject.js"></script>
+ <script type="text/javascript" src="js/uploader.js"></script>
+ </td>
+ </tr>
+</table>
+
+<inp2:m_DefineElement name="file_element">
+ <a href="<inp2:Field field='$field' format='full_url'/>" target="_blank"><inp2:Field field="$field"/></a><br/>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="inp_edit_upload_label" is_last="">
+ <tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
+ <inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
+ <td class="control-cell">
+ <inp2:$prefix_IterateFiles render_as="file_element" field="$field"/>
+ </td>
+ <inp2:m_RenderElement name="inp_edit_error" pass_params="1"/>
+ </tr>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="inp_edit_draft" is_last="">
+ <tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
+ <inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="la_DraftAvailableFrom" is_last="$is_last"/>
+ <td class="control-cell">
+ <inp2:draft.related_Field name="CreatedOn"/>
+ [<a href="#" onclick="submit_event('<inp2:m_Param name='prefix'/>', 'OnUseDraft'); return false;"><inp2:m_Phrase name="la_btn_UseDraft"/></a>]
+ [<a href="#" onclick="submit_event('<inp2:m_Param name='prefix'/>', 'OnDeleteDraft'); return false;"><inp2:m_Phrase name="la_btn_DeleteDraft"/></a>]
+ </td>
+ <inp2:m_RenderElement name="inp_edit_error" pass_params="1"/>
+ </tr>
+</inp2:m_DefineElement>
+
+<input type="hidden" name="client_mode" value="<inp2:m_Get name='client_mode'/>"/>
+
+<inp2:submission-log_SaveWarning name="grid_save_warning"/>
+<inp2:submission-log_ErrorWarning name="form_error_warning"/>
+
+<div id="scroll_container">
+ <table class="edit-form">
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="FormSubmissionId"/>
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="DraftId"/>
+ <inp2:m_RenderElement name="inp_id_label" prefix="submission-log" field="SubmissionLogId" title="la_fld_Id"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="FromEmail" title="la_fld_FromEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="ToEmail" size="60" title="la_fld_ToEmail"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="Cc" size="60" title="la_fld_Cc"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="Bcc" size="60" title="la_fld_Bcc"/>
+
+ <inp2:m_if check="submission-log_IsNewItem">
+ <inp2:m_RenderElement name="inp_edit_box" prefix="submission-log" field="Subject" size="80" title="la_fld_Subject"/>
+
+ <inp2:m_if check="submission-log_HasDraft">
+ <inp2:m_RenderElement name="inp_edit_draft" prefix="submission-log" field="DraftId"/>
+ </inp2:m_if>
+
+ <inp2:m_RenderElement name="inp_edit_textarea" prefix="submission-log" field="Message" rows="30" cols="100" title="la_fld_Message"/>
+ <inp2:m_RenderElement name="inp_edit_swf_upload" prefix="submission-log" field="Attachment" title="la_fld_Attachment"/>
+ <inp2:m_else/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="Subject" title="la_fld_Subject"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="Message" title="la_fld_Message" nl2br="1"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="ReplyStatus" title="la_fld_ReplyStatus"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="RepliedOn" title="la_fld_RepliedOn"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="SentStatus" title="la_fld_SentStatus"/>
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="SentOn" title="la_fld_SentOn"/>
+ <inp2:m_RenderElement name="inp_edit_upload_label" prefix="submission-log" field="Attachment" title="la_fld_Attachment"/>
+
+ <inp2:m_if check="submission-log_Field" name="BounceInfo">
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="BounceInfo" title="la_fld_BounceInfo" nl2br="1"/>
+ </inp2:m_if>
+
+ <inp2:m_if check="submission-log_Field" name="BounceDate" db="db">
+ <inp2:m_RenderElement name="inp_label" prefix="submission-log" field="BounceDate" title="la_fld_BounceDate"/>
+ </inp2:m_if>
+ </inp2:m_if>
+
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="FromEmail"/>
+ <inp2:m_RenderElement name="inp_edit_hidden" prefix="submission-log" field="ReplyTo"/>
+
+ <inp2:m_RenderElement name="inp_edit_filler" />
+ </table>
+</div>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: core/admin_templates/submissions/submission_view.tpl
===================================================================
--- core/admin_templates/submissions/submission_view.tpl (revision 13377)
+++ core/admin_templates/submissions/submission_view.tpl (working copy)
@@ -1,8 +1,14 @@
+<inp2:adm_SetPopupSize width="800" height="640"/>
+
<inp2:m_include t="incs/header"/>
-
<inp2:m_Get var="form_id" result_to_var="form_id"/>
-<inp2:m_RenderElement name="combined_header" section="in-portal:submissions:$form_id" prefix="formsubs" title_preset="formsubs_view"/>
+<inp2:m_if check="form_Field" name="EnableEmailCommunication" db="db">
+ <inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="formsubs_view" tab_preset="Default"/>
+<inp2:m_else/>
+ <inp2:m_RenderElement name="combined_header" prefix="formsubs" section="in-portal:submissions:$form_id" title_preset="formsubs_view"/>
+</inp2:m_if>
+
<!-- ToolBar -->
<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
<tbody>
@@ -11,11 +17,16 @@
<script type="text/javascript">
a_toolbar = new ToolBar();
- a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
- submit_event('formsubs','OnCancelEdit');
+ a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
+ submit_event('formsubs', '<inp2:formsubs_SaveEvent/>');
}
) );
+ a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Close" escape="1"/>', function() {
+ submit_event('formsubs', 'OnGoBack');
+ }
+ ) );
+
a_toolbar.AddButton( new ToolBarSeparator('sep1') );
a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
@@ -50,68 +61,99 @@
</tbody>
</table>
-<inp2:m_DefineElement name="form_field_text">
+<!--##<inp2:m_DefineElement name="form_field_text">
<inp2:m_if check="FieldEquals" field="Validation" value="1">
- <a href="mailto:<inp2:SubmissionTag tag="Field"/>"><inp2:SubmissionTag tag="Field"/></a>
+ <a href="mailto:<inp2:SubmissionTag tag='Field'/>"><inp2:SubmissionTag tag="Field"/></a>
<inp2:m_else/>
<inp2:SubmissionTag tag="Field"/>
</inp2:m_if>
+</inp2:m_DefineElement>##-->
+
+<inp2:m_DefineElement name="form_field_text">
+ <input type="text" name="<inp2:CustomInputName/>" id="<inp2:CustomInputName/>" value="<inp2:SubmissionTag tag="Field"/>" <inp2:m_param name="field_params" />/>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_password">
- <inp2:SubmissionTag tag="Field"/>
+ <input type="password" primarytype="password" name="<inp2:CustomInputName/>" id="<inp2:CustomInputName/>" value="" />
+ <input type="password" name="<inp2:CustomInputName verify='1'/>" id="verify_<inp2:CustomInputName verify='1'/>" value="" />
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_option">
- <option value="<inp2:m_param name="key"/>"<inp2:m_param name="selected"/>><inp2:m_param name="option"/></option>
+ <option value="<inp2:m_param name='key'/>"<inp2:m_param name="selected"/>><inp2:m_param name="option"/></option>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_select">
- <inp2:SubmissionTag tag="Field"/>
+ <select name="<inp2:CustomInputName/>" id="<inp2:CustomInputName/>">
+ <inp2:SubmissionTag tag="PredefinedOptions" field="$field" block="form_field_option" selected="selected"/>
+ </select>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_checkbox">
- <input type="hidden" id="<inp2:CustomInputName/>" name="<inp2:CustomInputName/>" value="<inp2:SubmissionTag tag="Field" field="$field" db="db"/>">
- <input disabled="disabled" tabindex="<inp2:m_get param="tab_index"/>" type="checkbox" id="_cb_<inp2:m_param name="field"/>" name="_cb_<inp2:m_param name="field"/>" <inp2:SubmissionTag tag="Field" checked="checked" db="db"/> class="<inp2:m_param name="field_class"/>" onclick="document.getElementById('<inp2:CustomInputName/>').value = this.checked ? 1:0">
+ <input type="hidden" id="<inp2:CustomInputName/>" name="<inp2:CustomInputName/>" value="<inp2:SubmissionTag tag='Field' field='$field' db='db'/>">
+ <input type="checkbox" id="_cb_<inp2:m_param name='field'/>" <inp2:SubmissionTag tag="Field" checked="checked" db="db"/> onchange="update_checkbox(this, document.getElementById('<inp2:CustomInputName/>'));">
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_textarea">
- <inp2:SubmissionTag tag="Field" nl2br="1" no_special="1"/>
+ <textarea name="<inp2:CustomInputName/>" id="<inp2:CustomInputName/>" style="width: 100%;" <inp2:m_param name="field_params" />><inp2:SubmissionTag tag="Field" field="$field" /></textarea>
+
+ <script type="text/javascript">
+ Form.addControl('<inp2:CustomInputName/>', false);
+ </script>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_radio_item">
- <input disabled="disabled" type="radio" <inp2:m_param name="checked"/> name="<inp2:m_param name="field_name"/>" id="<inp2:m_param name="field_name"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>"><label for="<inp2:m_param name="field_name"/>_<inp2:m_param name="key"/>"><inp2:m_param name="option"/></label>
+ <input type="radio" <inp2:m_param name="checked"/> name="<inp2:m_param name="field_name"/>" id="<inp2:m_param name="field_name"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>"><label for="<inp2:m_param name="field_name"/>_<inp2:m_param name="key"/>"><inp2:m_param name="option"/></label>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="form_field_radio">
- <inp2:SubmissionTag tag="PredefinedOptions" field="$field" tabindex="$pass_tabindex" block="form_radio_item" selected="checked"/>
+ <inp2:SubmissionTag tag="PredefinedOptions" field="$field" block="form_radio_item" selected="checked"/>
</inp2:m_DefineElement>
-
<inp2:formsubs_SaveWarning name="grid_save_warning"/>
<inp2:formsubs_ErrorWarning name="form_error_warning"/>
<div id="scroll_container">
<table class="edit-form">
- <inp2:m_RenderElement name="subsection" prefix="formsubs" fields="FormSubmissionId,SubmissionTime" title="!la_section_General!"/>
- <inp2:m_RenderElement name="inp_id_label" prefix="formsubs" field="FormSubmissionId" title="!la_fld_Id!"/>
- <inp2:m_RenderElement name="inp_edit_date_time" prefix="formsubs" field="SubmissionTime" title="!la_fld_SubmissionTime!" />
- <inp2:m_RenderElement name="subsection" title="!la_section_Data!"/>
+ <inp2:m_RenderElement name="subsection" prefix="formsubs" fields="FormSubmissionId,SubmissionTime,IPAddress,ReferrerURL,LogStatus,LastUpdatedOn" title="la_section_General"/>
+ <inp2:m_RenderElement name="inp_id_label" prefix="formsubs" field="FormSubmissionId" title="la_fld_Id"/>
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="SubmissionTime" title="la_fld_SubmissionTime" />
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="IPAddress" title="la_fld_IPAddress" />
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="ReferrerURL" title="la_fld_ReferrerURL" />
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="LogStatus" title="la_fld_Status" />
- <inp2:m_DefineElement name="form_field">
+ <inp2:m_if check="formsubs_Field" name="LastUpdatedOn" db="db">
+ <inp2:m_RenderElement name="inp_label" prefix="formsubs" field="LastUpdatedOn" title="la_fld_LastUpdatedOn" />
+ </inp2:m_if>
+
+ <inp2:m_RenderElement name="subsection" title="la_section_Data"/>
+
+ <inp2:m_DefineElement name="form_field" prefix="formsubs">
<tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
<inp2:m_inc param="tab_index" by="1"/>
- <td class="label-cell">
- <inp2:Field field="Prompt" plus_or_as_label="1" no_special="no_special"/>:
+ <td class="label-cell" onmouseover="show_form_error('<inp2:m_Param name='prefix' js_escape='1'/>', 'fld_<inp2:Field name='FormFieldId'/>')" onmouseout="hide_form_error('<inp2:m_Param name='prefix' js_escape='1'/>')">
+ <inp2:Field field="Prompt" plus_or_as_label="1" no_special="no_special"/><inp2:m_if check="Field" name="Required" db="db"><span class="field-required"> *</span></inp2:m_if>:
</td>
<td class="control-mid"> </td>
+ <script type="text/javascript">
+ if (typeof(fields['<inp2:m_Param name="prefix" js_escape="1"/>']) == 'undefined') {
+ fields['<inp2:m_Param name="prefix" js_escape="1"/>'] = new Object();
+ }
+ fields['<inp2:m_Param name="prefix" js_escape="1"/>']['fld_<inp2:Field name="FormFieldId"/>'] = '<inp2:Field field="Prompt" plus_or_as_label="1" no_special="no_special" js_escape="1"/>'
+ </script>
<td class="control-cell">
<inp2:ConfigFormElement field="Value" blocks_prefix="form_field_" element_type_field="ElementType" value_list_field="ValueList" /><br/>
</td>
</tr>
+ <script type="text/javascript">
+ add_form_error('<inp2:m_Param name="prefix" js_escape="1"/>', 'fld_<inp2:Field name="FormFieldId"/>', '<inp2:CustomInputName/>', '<inp2:SubmissionTag tag="Error" js_escape="1"/>')
+ </script>
</inp2:m_DefineElement>
<inp2:formflds_PrintList render_as="form_field" SourcePrefix="formsubs" per_page="-1"/>
+
+ <inp2:m_RenderElement name="subsection" prefix="formsubs" fields="Notes" title="la_section_SubmissionNotes"/>
+ <inp2:m_RenderElement name="inp_edit_textarea" prefix="formsubs" field="Notes" title="la_fld_Notes" />
+
<inp2:m_RenderElement name="inp_edit_filler"/>
</table>
</div>
Index: core/admin_templates/submissions/submissions_list.tpl
===================================================================
--- core/admin_templates/submissions/submissions_list.tpl (revision 13377)
+++ core/admin_templates/submissions/submissions_list.tpl (working copy)
@@ -12,7 +12,8 @@
//do not rename - this function is used in default grid for double click!
function edit()
{
- std_edit_item('formsubs', 'submissions/submission_view');
+ // don't use temp tables, since we can receive user replies while reviewing form submission
+ std_edit_temp_item('formsubs', 'submissions/submission_view');
}
var a_toolbar = new ToolBar();
Index: core/install/english.lang
===================================================================
--- core/install/english.lang (revision 13377)
+++ core/install/english.lang (working copy)
@@ -20,6 +20,7 @@
<PHRASE Label="la_btn_Change" Module="Core" Type="1">Q2hhbmdl</PHRASE>
<PHRASE Label="la_btn_ContentMode" Module="Core" Type="1">Q29udGVudCBNb2Rl</PHRASE>
<PHRASE Label="la_btn_Delete" Module="Core" Type="1">RGVsZXRl</PHRASE>
+ <PHRASE Label="la_btn_DeleteDraft" Module="Core" Type="1">RGVsZXRl</PHRASE>
<PHRASE Label="la_btn_DesignMode" Module="Core" Type="1">RGVzaWduIE1vZGU=</PHRASE>
<PHRASE Label="la_btn_Down" Module="Core" Type="1">RG93bg==</PHRASE>
<PHRASE Label="la_btn_Edit" Module="Core" Type="1">RWRpdA==</PHRASE>
@@ -33,6 +34,7 @@
<PHRASE Label="la_btn_SectionProperties" Module="Core" Type="1">U2VjdGlvbiBQcm9wZXJ0aWVz</PHRASE>
<PHRASE Label="la_btn_SectionTemplate" Module="Core" Type="1">U2VjdGlvbiBUZW1wbGF0ZQ==</PHRASE>
<PHRASE Label="la_btn_Up" Module="Core" Type="1">VXA=</PHRASE>
+ <PHRASE Label="la_btn_UseDraft" Module="Core" Type="1">VXNl</PHRASE>
<PHRASE Label="la_Cancel" Module="Core" Type="1">Q2FuY2Vs</PHRASE>
<PHRASE Label="la_category" Module="Core" Type="1">U2VjdGlvbg==</PHRASE>
<PHRASE Label="la_category_daysnew_prompt" Module="Core" Type="1">TnVtYmVyIG9mIGRheXMgZm9yIGEgY2F0LiB0byBiZSBORVc=</PHRASE>
@@ -61,10 +63,12 @@
<PHRASE Label="la_col_Duration" Module="Core" Type="1">RHVyYXRpb24=</PHRASE>
<PHRASE Label="la_col_Effective" Module="Core" Type="1">RWZmZWN0aXZl</PHRASE>
<PHRASE Label="la_col_Email" Module="Core" Type="1">RW1haWw=</PHRASE>
+ <PHRASE Label="la_col_EmailCommunicationRole" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24gUm9sZQ==</PHRASE>
<PHRASE Label="la_col_EmailsQueued" Module="Core" Type="1">UXVldWU=</PHRASE>
<PHRASE Label="la_col_EmailsSent" Module="Core" Type="1">U2VudA==</PHRASE>
<PHRASE Label="la_col_EmailsTotal" Module="Core" Type="1">VG90YWw=</PHRASE>
<PHRASE Label="la_col_Enabled" Module="Core" Type="1">RW5hYmxlZA==</PHRASE>
+ <PHRASE Label="la_col_EnableEmailCommunication" Module="Core" Type="1">RW5hYmxlIEUtbWFpbCBDb21tdW5pY2F0aW9u</PHRASE>
<PHRASE Label="la_col_EndDate" Module="Core" Type="1">RW5kIERhdGU=</PHRASE>
<PHRASE Label="la_col_Error" Module="Core" Type="1">Jm5ic3A7</PHRASE>
<PHRASE Label="la_col_Event" Module="Core" Type="1">RXZlbnQ=</PHRASE>
@@ -75,6 +79,7 @@
<PHRASE Label="la_col_FileName" Module="Core" Type="1">RmlsZW5hbWU=</PHRASE>
<PHRASE Label="la_col_FilePath" Module="Core" Type="1">UGF0aA==</PHRASE>
<PHRASE Label="la_col_FirstName" Module="Core" Type="1">Rmlyc3QgTmFtZQ==</PHRASE>
+ <PHRASE Label="la_col_FromEmail" Module="Core" Type="1">RnJvbSBFLW1haWw=</PHRASE>
<PHRASE Label="la_col_FromToUser" Module="Core" Type="1">RnJvbSAvIFRvIFVzZXI=</PHRASE>
<PHRASE Label="la_col_FrontEndOnly" Module="Core" Type="1">RnJvbnQtRW5kIE9ubHk=</PHRASE>
<PHRASE Label="la_col_FrontRegistration" Module="Core" Type="1">QWxsb3cgUmVnaXN0cmF0aW9u</PHRASE>
@@ -106,6 +111,7 @@
<PHRASE Label="la_col_LastRunOn" Module="Core" Type="1">TGFzdCBSdW4gT24=</PHRASE>
<PHRASE Label="la_col_LastRunStatus" Module="Core" Type="1">TGFzdCBSdW4gU3RhdHVz</PHRASE>
<PHRASE Label="la_col_LastSendRetry" Module="Core" Type="1">TGFzdCBBdHRlbXB0</PHRASE>
+ <PHRASE Label="la_col_LastUpdatedOn" Module="Core" Type="1">TGFzdCBVcGRhdGVkIE9u</PHRASE>
<PHRASE Label="la_col_LinkUrl" Module="Core" Type="1">TGluayBVUkw=</PHRASE>
<PHRASE Label="la_col_LocalName" Module="Core" Type="1">TmFtZQ==</PHRASE>
<PHRASE Label="la_col_Location" Module="Core" Type="1">TG9jYXRpb24=</PHRASE>
@@ -114,6 +120,7 @@
<PHRASE Label="la_col_MasterId" Module="Core" Type="1">TWFzdGVyIElE</PHRASE>
<PHRASE Label="la_col_MasterPrefix" Module="Core" Type="1">TWFzdGVyIFByZWZpeA==</PHRASE>
<PHRASE Label="la_col_MembershipExpires" Module="Core" Type="1">TWVtYmVyc2hpcCBFeHBpcmVz</PHRASE>
+ <PHRASE Label="la_col_Message" Module="Core" Type="1">TWVzc2FnZQ==</PHRASE>
<PHRASE Label="la_col_MessageHeaders" Module="Core" Type="1">TWVzc2FnZSBIZWFkZXJz</PHRASE>
<PHRASE Label="la_col_MessageHtml" Module="Core" Type="1">SFRNTA==</PHRASE>
<PHRASE Label="la_col_MessageText" Module="Core" Type="1">UGxhaW4gVGV4dA==</PHRASE>
@@ -145,7 +152,11 @@
<PHRASE Label="la_col_Rating" Module="Core" Type="1">UmF0aW5n</PHRASE>
<PHRASE Label="la_col_RecipientType" Module="Core" Type="1">UmVjaXBpZW50IFR5cGU=</PHRASE>
<PHRASE Label="la_col_Referer" Module="Core" Type="1">UmVmZXJlcg==</PHRASE>
+ <PHRASE Label="la_col_ReferrerURL" Module="Core" Type="1">UmVmZXJyZXIgVVJM</PHRASE>
<PHRASE Label="la_col_RelationshipType" Module="Core" Type="1">UmVsYXRpb24gVHlwZQ==</PHRASE>
+ <PHRASE Label="la_col_RepliedOn" Module="Core" Type="1">UmVwbGllZCBPbg==</PHRASE>
+ <PHRASE Label="la_col_ReplyStatus" Module="Core" Type="1">UmVwbGllZA==</PHRASE>
+ <PHRASE Label="la_col_RequireLogin" Module="Core" Type="1">UmVxdWlyZSBMb2dpbg==</PHRASE>
<PHRASE Label="la_col_ResetToDefaultSorting" Module="Core" Type="1">UmVzZXQgdG8gZGVmYXVsdA==</PHRASE>
<PHRASE Label="la_col_ReviewCount" Module="Core" Type="1">Q29tbWVudHM=</PHRASE>
<PHRASE Label="la_col_ReviewedBy" Module="Core" Type="1">Q3JlYXRlZCBieQ==</PHRASE>
@@ -156,6 +167,8 @@
<PHRASE Label="la_col_SearchTerm" Module="Core" Type="1">U2VhcmNoIFRlcm0=</PHRASE>
<PHRASE Label="la_col_SelectorName" Module="Core" Type="1">U2VsZWN0b3I=</PHRASE>
<PHRASE Label="la_col_SendRetries" Module="Core" Type="1">QXR0ZW1wdHMg</PHRASE>
+ <PHRASE Label="la_col_SentOn" Module="Core" Type="1">U2VudCBPbg==</PHRASE>
+ <PHRASE Label="la_col_SentStatus" Module="Core" Type="1">U2VudA==</PHRASE>
<PHRASE Label="la_col_SessionEnd" Module="Core" Type="1">U2Vzc2lvbiBFbmQ=</PHRASE>
<PHRASE Label="la_col_SessionLogId" Module="Core" Type="1">U2Vzc2lvbiBMb2cgSUQ=</PHRASE>
<PHRASE Label="la_col_SessionStart" Module="Core" Type="1">U2Vzc2lvbiBTdGFydA==</PHRASE>
@@ -173,13 +186,16 @@
<PHRASE Label="la_col_ThesaurusTerm" Module="Core" Type="1">VGhlc2F1cnVzIFRlcm0=</PHRASE>
<PHRASE Label="la_col_ThesaurusType" Module="Core" Type="1">VGhlc2F1cnVzIFR5cGU=</PHRASE>
<PHRASE Label="la_col_Title" Module="Core" Type="1">VGl0bGU=</PHRASE>
+ <PHRASE Label="la_col_ToEmail" Module="Core" Type="1">VG8gRS1tYWls</PHRASE>
<PHRASE Label="la_col_Translation" Module="Core" Type="1">VmFsdWU=</PHRASE>
<PHRASE Label="la_col_Type" Module="Core" Type="1">VHlwZQ==</PHRASE>
<PHRASE Label="la_col_UserCount" Module="Core" Type="1">VXNlcnM=</PHRASE>
<PHRASE Label="la_col_UserFirstLastName" Module="Core" Type="1">TGFzdG5hbWUgRmlyc3RuYW1l</PHRASE>
<PHRASE Label="la_col_Username" Module="Core" Type="1">VXNlcm5hbWU=</PHRASE>
+ <PHRASE Label="la_col_UseSecurityImage" Module="Core" Type="1">VXNlIFNlY3VyaXR5IEltYWdl</PHRASE>
<PHRASE Label="la_col_Value" Module="Core" Type="1">RmllbGQgVmFsdWU=</PHRASE>
<PHRASE Label="la_col_Version" Module="Core" Type="1">VmVyc2lvbg==</PHRASE>
+ <PHRASE Label="la_col_Visibility" Module="Core" Type="1">VmlzaWJpbGl0eQ==</PHRASE>
<PHRASE Label="la_col_Visible" Module="Core" Type="1">VmlzaWJsZQ==</PHRASE>
<PHRASE Label="la_col_VisitDate" Module="Core" Type="1">VmlzaXQgRGF0ZQ==</PHRASE>
<PHRASE Label="la_common_ascending" Module="Core" Type="1">QXNjZW5kaW5n</PHRASE>
@@ -504,6 +520,7 @@
<PHRASE Label="la_DownloadCSV" Module="Core" Type="1">RG93bmxvYWQgQ1NW</PHRASE>
<PHRASE Label="la_DownloadExportFile" Module="Core" Type="1">RG93bmxvYWQgRXhwb3J0IEZpbGU=</PHRASE>
<PHRASE Label="la_DownloadLanguageExport" Module="Core" Type="1">RG93bmxvYWQgTGFuZ3VhZ2UgRXhwb3J0</PHRASE>
+ <PHRASE Label="la_DraftAvailableFrom" Module="Core" Type="1">RHJhZnQgQXZhaWxhYmxl</PHRASE>
<PHRASE Label="la_EditingContent" Module="Core" Type="1">Q29udGVudCBFZGl0b3I=</PHRASE>
<PHRASE Label="la_EditingInProgress" Module="Core" Type="1">WW91IGhhdmUgbm90IHNhdmVkIGNoYW5nZXMgdG8gdGhlIGl0ZW0geW91IGFyZSBlZGl0aW5nITxiciAvPkNsaWNrIE9LIHRvIGxvb3NlIGNoYW5nZXMgYW5kIGdvIHRvIHRoZSBzZWxlY3RlZCBzZWN0aW9uPGJyIC8+b3IgQ2FuY2VsIHRvIHN0YXkgaW4gdGhlIGN1cnJlbnQgc2VjdGlvbi4=</PHRASE>
<PHRASE Label="la_editor_default_style" Module="Core" Type="1">RGVmYXVsdCB0ZXh0</PHRASE>
@@ -512,11 +529,13 @@
<PHRASE Label="la_empty_file" Module="Core" Type="1">RmlsZSBpcyBlbXB0eQ==</PHRASE>
<PHRASE Label="la_Enabled" Module="Core" Type="1">RW5hYmxlZA==</PHRASE>
<PHRASE Label="la_error_cant_save_file" Module="Core" Type="1">Q2FuJ3Qgc2F2ZSBhIGZpbGU=</PHRASE>
+ <PHRASE Label="la_error_ConnectionFailed" Module="Core" Type="1">Q29ubmVjdGlvbiBGYWlsZWQ=</PHRASE>
<PHRASE Label="la_error_copy_subcategory" Module="Core" Type="1">RXJyb3IgY29weWluZyBzdWJzZWN0aW9ucw==</PHRASE>
<PHRASE Label="la_error_CustomExists" Module="Core" Type="1">Q3VzdG9tIGZpZWxkIHdpdGggaWRlbnRpY2FsIG5hbWUgYWxyZWFkeSBleGlzdHM=</PHRASE>
<PHRASE Label="la_error_FileTooLarge" Module="Core" Type="1">RmlsZSBpcyB0b28gbGFyZ2U=</PHRASE>
<PHRASE Label="la_error_InvalidFileFormat" Module="Core" Type="1">SW52YWxpZCBGaWxlIEZvcm1hdA==</PHRASE>
<PHRASE Label="la_error_invalidoption" Module="Core" Type="1">aW52YWxpZCBvcHRpb24=</PHRASE>
+ <PHRASE Label="la_error_LoginFailed" Module="Core" Type="1">TG9naW4gRmFpbGVk</PHRASE>
<PHRASE Label="la_error_move_subcategory" Module="Core" Type="1">RXJyb3IgbW92aW5nIHN1YnNlY3Rpb24=</PHRASE>
<PHRASE Label="la_error_NoInheritancePossible" Module="Core" Type="1">Q2FuJ3QgaW5oZXJpdCB0ZW1wbGF0ZSBmcm9tIHRvcCBjYXRlZ29yeQ==</PHRASE>
<PHRASE Label="la_error_PasswordMatch" Module="Core" Type="1">UGFzc3dvcmRzIGRvIG5vdCBtYXRjaCE=</PHRASE>
@@ -570,17 +589,22 @@
<PHRASE Label="la_fld_BackgroundImage" Module="Core" Type="1">QmFja2dyb3VuZCBJbWFnZQ==</PHRASE>
<PHRASE Label="la_fld_BackgroundPosition" Module="Core" Type="1">QmFja2dyb3VuZCBQb3NpdGlvbg==</PHRASE>
<PHRASE Label="la_fld_BackgroundRepeat" Module="Core" Type="1">QmFja2dyb3VuZCBSZXBlYXQ=</PHRASE>
+ <PHRASE Label="la_fld_Bcc" Module="Core" Type="1">QmNj</PHRASE>
<PHRASE Label="la_fld_BlockPosition" Module="Core" Type="1">RWxlbWVudCBQb3NpdGlvbg==</PHRASE>
<PHRASE Label="la_fld_BorderBottom" Module="Core" Type="1">Qm9yZGVyIEJvdHRvbQ==</PHRASE>
<PHRASE Label="la_fld_BorderLeft" Module="Core" Type="1">Qm9yZGVyIExlZnQ=</PHRASE>
<PHRASE Label="la_fld_BorderRight" Module="Core" Type="1">Qm9yZGVyIFJpZ2h0</PHRASE>
<PHRASE Label="la_fld_Borders" Module="Core" Type="1">Qm9yZGVycw==</PHRASE>
<PHRASE Label="la_fld_BorderTop" Module="Core" Type="1">Qm9yZGVyIFRvcA==</PHRASE>
+ <PHRASE Label="la_fld_BounceDate" Module="Core" Type="1">Qm91bmNlIERhdGU=</PHRASE>
+ <PHRASE Label="la_fld_BounceEmail" Module="Core" Type="1">Qm91bmNlIEVtYWls</PHRASE>
+ <PHRASE Label="la_fld_BounceInfo" Module="Core" Type="1">Qm91bmNlIEluZm8=</PHRASE>
<PHRASE Label="la_fld_Category" Module="Core" Type="1">U2VjdGlvbg==</PHRASE>
<PHRASE Label="la_fld_CategoryFormat" Module="Core" Type="1">U2VjdGlvbiBGb3JtYXQ=</PHRASE>
<PHRASE Label="la_fld_CategoryId" Module="Core" Type="1">U2VjdGlvbiBJRA==</PHRASE>
<PHRASE Label="la_fld_CategorySeparator" Module="Core" Type="1">U2VjdGlvbiBzZXBhcmF0b3I=</PHRASE>
<PHRASE Label="la_fld_CategoryTemplate" Module="Core" Type="1">U2VjdGlvbiBUZW1wbGF0ZQ==</PHRASE>
+ <PHRASE Label="la_fld_Cc" Module="Core" Type="1">Q2M=</PHRASE>
<PHRASE Label="la_fld_Changes" Module="Core" Type="1">Q2hhbmdlcw==</PHRASE>
<PHRASE Label="la_fld_Charset" Module="Core" Type="1">Q2hhcnNldA==</PHRASE>
<PHRASE Label="la_fld_CheckDuplicatesMethod" Module="Core" Type="1">Q2hlY2sgRHVwbGljYXRlcyBieQ==</PHRASE>
@@ -607,9 +631,11 @@
<PHRASE Label="la_fld_EditorsPick" Module="Core" Type="1">RWRpdG9ycyBQaWNr</PHRASE>
<PHRASE Label="la_fld_ElapsedTime" Module="Core" Type="1">RWxhcHNlZCBUaW1l</PHRASE>
<PHRASE Label="la_fld_Email" Module="Core" Type="1">RS1tYWls</PHRASE>
+ <PHRASE Label="la_fld_EmailCommunicationRole" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24gUm9sZQ==</PHRASE>
<PHRASE Label="la_fld_EmailsQueued" Module="Core" Type="1">RW1haWxzIGluIFF1ZXVl</PHRASE>
<PHRASE Label="la_fld_EmailsSent" Module="Core" Type="1">RW1haWxzIFNlbnQ=</PHRASE>
<PHRASE Label="la_fld_EmailsTotal" Module="Core" Type="1">RW1haWxzIFRvdGFs</PHRASE>
+ <PHRASE Label="la_fld_Enable" Module="Core" Type="1">RW5hYmxl</PHRASE>
<PHRASE Label="la_fld_Enabled" Module="Core" Type="1">RW5hYmxlZA==</PHRASE>
<PHRASE Label="la_fld_ErrorTag" Module="Core" Type="1">RXJyb3IgVGFn</PHRASE>
<PHRASE Label="la_fld_EstimatedTime" Module="Core" Type="1">RXN0aW1hdGVkIFRpbWU=</PHRASE>
@@ -647,6 +673,7 @@
<PHRASE Label="la_fld_Form" Module="Core" Type="1">T25saW5lIEZvcm0=</PHRASE>
<PHRASE Label="la_fld_FormSubmittedTemplate" Module="Core" Type="1">T25saW5lIEZvcm0gU3VibWl0dGVkIFRlbXBsYXRl</PHRASE>
<PHRASE Label="la_fld_FriendlyURL" Module="Core" Type="1">U2hvcnQgVVJM</PHRASE>
+ <PHRASE Label="la_fld_FromEmail" Module="Core" Type="1">RnJvbSBFbWFpbA==</PHRASE>
<PHRASE Label="la_fld_FromToUser" Module="Core" Type="1">RnJvbSAvIFRvIFVzZXI=</PHRASE>
<PHRASE Label="la_fld_FrontEndOnly" Module="Core" Type="1">RnJvbnQtRW5kIE9ubHk=</PHRASE>
<PHRASE Label="la_fld_FrontRegistration" Module="Core" Type="1">QWxsb3cgUmVnaXN0cmF0aW9uIG9uIEZyb250LWVuZA==</PHRASE>
@@ -668,6 +695,7 @@
<PHRASE Label="la_fld_InputTimeFormat" Module="Core" Type="1">SW5wdXQgVGltZSBGb3JtYXQ=</PHRASE>
<PHRASE Label="la_fld_InstallModules" Module="Core" Type="1">SW5zdGFsbCBNb2R1bGVz</PHRASE>
<PHRASE Label="la_fld_InstallPhraseTypes" Module="Core" Type="1">SW5zdGFsbCBQaHJhc2UgVHlwZXM=</PHRASE>
+ <PHRASE Label="la_fld_IPAddress" Module="Core" Type="1">SVAgQWRkcmVzcw==</PHRASE>
<PHRASE Label="la_fld_IsBaseCategory" Module="Core" Type="1">VXNlIGN1cnJlbnQgc2VjdGlvbiBhcyByb290IGZvciB0aGUgZXhwb3J0</PHRASE>
<PHRASE Label="la_fld_IsPrimary" Module="Core" Type="1">UHJpbWFyeQ==</PHRASE>
<PHRASE Label="la_fld_IsRequired" Module="Core" Type="1">UmVxdWlyZWQ=</PHRASE>
@@ -682,6 +710,7 @@
<PHRASE Label="la_fld_LastName" Module="Core" Type="1">TGFzdCBOYW1l</PHRASE>
<PHRASE Label="la_fld_LastRunOn" Module="Core" Type="1">TGFzdCBSdW4gT24=</PHRASE>
<PHRASE Label="la_fld_LastRunStatus" Module="Core" Type="1">TGFzdCBSdW4gU3RhdHVz</PHRASE>
+ <PHRASE Label="la_fld_LastUpdatedOn" Module="Core" Type="1">TGFzdCBVcGRhdGVkIE9u</PHRASE>
<PHRASE Label="la_fld_Left" Module="Core" Type="1">TGVmdA==</PHRASE>
<PHRASE Label="la_fld_LineEndings" Module="Core" Type="1">TGluZSBlbmRpbmdz</PHRASE>
<PHRASE Label="la_fld_LineEndingsInside" Module="Core" Type="1">TGluZSBFbmRpbmdzIEluc2lkZSBGaWVsZHM=</PHRASE>
@@ -702,6 +731,7 @@
<PHRASE Label="la_fld_MaxCategories" Module="Core" Type="1">TWF4aW11bSBudW1iZXIgb2YgU2VjdGlvbnMgb24gSXRlbSBjYW4gYmUgYWRkZWQgdG8=</PHRASE>
<PHRASE Label="la_fld_MenuIcon" Module="Core" Type="1">Q3VzdG9tIE1lbnUgSWNvbiAoaWUuIGltZy9tZW51X3Byb2R1Y3RzLmdpZik=</PHRASE>
<PHRASE Label="la_fld_MenuStatus" Module="Core" Type="1">TWVudSBTdGF0dXM=</PHRASE>
+ <PHRASE Label="la_fld_Message" Module="Core" Type="1">TWVzc2FnZQ==</PHRASE>
<PHRASE Label="la_fld_MessageBody" Module="Core" Type="1">TWVzc2FnZSBCb2R5</PHRASE>
<PHRASE Label="la_fld_MessageText" Module="Core" Type="1">UGxhaW4gVGV4dCBWZXJzaW9u</PHRASE>
<PHRASE Label="la_fld_MessageType" Module="Core" Type="1">TWVzc2FnZSBUeXBl</PHRASE>
@@ -715,6 +745,7 @@
<PHRASE Label="la_fld_Name" Module="Core" Type="1">TmFtZQ==</PHRASE>
<PHRASE Label="la_fld_New" Module="Core" Type="1">TmV3</PHRASE>
<PHRASE Label="la_fld_NextRunOn" Module="Core" Type="1">TmV4dCBSdW4gT24=</PHRASE>
+ <PHRASE Label="la_fld_Notes" Module="Core" Type="1">Tm90ZXM=</PHRASE>
<PHRASE Label="la_fld_OccuredOn" Module="Core" Type="1">T2NjdXJlZCBPbg==</PHRASE>
<PHRASE Label="la_fld_Options" Module="Core" Type="1">T3B0aW9ucw==</PHRASE>
<PHRASE Label="la_fld_OptionTitle" Module="Core" Type="1">T3B0aW9uIFRpdGxl</PHRASE>
@@ -735,6 +766,7 @@
<PHRASE Label="la_fld_PhraseType" Module="Core" Type="1">UGhyYXNlIFR5cGU=</PHRASE>
<PHRASE Label="la_fld_Pop" Module="Core" Type="1">UG9w</PHRASE>
<PHRASE Label="la_fld_Popular" Module="Core" Type="1">UG9wdWxhcg==</PHRASE>
+ <PHRASE Label="la_fld_Port" Module="Core" Type="1">UG9ydA==</PHRASE>
<PHRASE Label="la_fld_Position" Module="Core" Type="1">UG9zaXRpb24=</PHRASE>
<PHRASE Label="la_fld_Prefix" Module="Core" Type="1">UHJlZml4</PHRASE>
<PHRASE Label="la_fld_Primary" Module="Core" Type="1">UHJpbWFyeQ==</PHRASE>
@@ -743,11 +775,19 @@
<PHRASE Label="la_fld_PrimaryTranslation" Module="Core" Type="1">UHJpbWFyeSBMYW5ndWFnZSBQaHJhc2U=</PHRASE>
<PHRASE Label="la_fld_Priority" Module="Core" Type="1">T3JkZXI=</PHRASE>
<PHRASE Label="la_fld_Rating" Module="Core" Type="1">UmF0aW5n</PHRASE>
+ <PHRASE Label="la_fld_ReferrerURL" Module="Core" Type="1">UmVmZXJyZXIgVVJM</PHRASE>
<PHRASE Label="la_fld_RelatedSearchKeyword" Module="Core" Type="1">S2V5d29yZA==</PHRASE>
<PHRASE Label="la_fld_RelationshipType" Module="Core" Type="1">VHlwZQ==</PHRASE>
<PHRASE Label="la_fld_RemoteUrl" Module="Core" Type="1">UmVtb3RlIFVSTA==</PHRASE>
<PHRASE Label="la_fld_ReplaceDuplicates" Module="Core" Type="1">UmVwbGFjZSBEdXBsaWNhdGVz</PHRASE>
<PHRASE Label="la_fld_ReplacementTags" Module="Core" Type="1">UmVwbGFjZW1lbnQgVGFncw==</PHRASE>
+ <PHRASE Label="la_fld_RepliedOn" Module="Core" Type="1">UmVwbGllZCBPbg==</PHRASE>
+ <PHRASE Label="la_fld_ReplyBcc" Module="Core" Type="1">UmVwbHkgQmNj</PHRASE>
+ <PHRASE Label="la_fld_ReplyCc" Module="Core" Type="1">UmVwbHkgQ2M=</PHRASE>
+ <PHRASE Label="la_fld_ReplyFromEmail" Module="Core" Type="1">UmVwbHkgRnJvbSBFLW1haWw=</PHRASE>
+ <PHRASE Label="la_fld_ReplyFromName" Module="Core" Type="1">UmVwbHkgRnJvbSBOYW1l</PHRASE>
+ <PHRASE Label="la_fld_ReplyMessageSignature" Module="Core" Type="1">UmVwbHkgTWVzc2FnZSBTaWduYXR1cmU=</PHRASE>
+ <PHRASE Label="la_fld_ReplyStatus" Module="Core" Type="1">UmVwbGllZA==</PHRASE>
<PHRASE Label="la_fld_Required" Module="Core" Type="1">UmVxdWlyZWQ=</PHRASE>
<PHRASE Label="la_fld_ReviewText" Module="Core" Type="1">Q29tbWVudA==</PHRASE>
<PHRASE Label="la_fld_RuleType" Module="Core" Type="1">UnVsZSBUeXBl</PHRASE>
@@ -760,6 +800,9 @@
<PHRASE Label="la_fld_SelectorData" Module="Core" Type="1">U3R5bGU=</PHRASE>
<PHRASE Label="la_fld_SelectorId" Module="Core" Type="1">U2VsZWN0b3IgSUQ=</PHRASE>
<PHRASE Label="la_fld_SelectorName" Module="Core" Type="1">U2VsZWN0b3IgTmFtZQ==</PHRASE>
+ <PHRASE Label="la_fld_SentOn" Module="Core" Type="1">U2VudCBPbg==</PHRASE>
+ <PHRASE Label="la_fld_SentStatus" Module="Core" Type="1">U2VudA==</PHRASE>
+ <PHRASE Label="la_fld_Server" Module="Core" Type="1">U2VydmVy</PHRASE>
<PHRASE Label="la_fld_SessionLogId" Module="Core" Type="1">U2Vzc2lvbiBMb2cgSUQ=</PHRASE>
<PHRASE Label="la_fld_SimpleSearch" Module="Core" Type="1">U2ltcGxlIFNlYXJjaA==</PHRASE>
<PHRASE Label="la_fld_SkinName" Module="Core" Type="1">TmFtZQ==</PHRASE>
@@ -786,6 +829,7 @@
<PHRASE Label="la_fld_TimeFormat" Module="Core" Type="1">VGltZSBGb3JtYXQ=</PHRASE>
<PHRASE Label="la_fld_Title" Module="Core" Type="1">VGl0bGU=</PHRASE>
<PHRASE Label="la_fld_To" Module="Core" Type="1">VG8=</PHRASE>
+ <PHRASE Label="la_fld_ToEmail" Module="Core" Type="1">VG8gRS1tYWls</PHRASE>
<PHRASE Label="la_fld_Top" Module="Core" Type="1">VG9w</PHRASE>
<PHRASE Label="la_fld_TrackingCode" Module="Core" Type="1">VHJhY2tpbmcgQ29kZQ==</PHRASE>
<PHRASE Label="la_fld_Translation" Module="Core" Type="1">UGhyYXNl</PHRASE>
@@ -798,6 +842,7 @@
<PHRASE Label="la_fld_UserDocsUrl" Module="Core" Type="1">VXNlciBEb2N1bWVudGF0aW9uIFVSTA==</PHRASE>
<PHRASE Label="la_fld_UserGroups" Module="Core" Type="1">VXNlciBHcm91cHM=</PHRASE>
<PHRASE Label="la_fld_Username" Module="Core" Type="1">VXNlcm5hbWU=</PHRASE>
+ <PHRASE Label="la_fld_UseSecurityImage" Module="Core" Type="1">VXNlIFNlY3VyaXR5IEltYWdl</PHRASE>
<PHRASE Label="la_fld_VerifyPassword" Module="Core" Type="1">UmUtZW50ZXIgUGFzc3dvcmQ=</PHRASE>
<PHRASE Label="la_fld_Version" Module="Core" Type="1">VmVyc2lvbg==</PHRASE>
<PHRASE Label="la_fld_Visibility" Module="Core" Type="1">VmlzaWJpbGl0eQ==</PHRASE>
@@ -815,6 +860,8 @@
<PHRASE Label="la_hint_AllFiles" Module="Core" Type="1">QWxsIEZpbGVz</PHRASE>
<PHRASE Label="la_hint_CSVFiles" Module="Core" Type="1">Q1NWIEZpbGVz</PHRASE>
<PHRASE Label="la_hint_ImageFiles" Module="Core" Type="1">SW1hZ2UgRmlsZXM=</PHRASE>
+ <PHRASE Label="la_hint_PopPort" Module="Core" Type="1">UE9QMyBTZXJ2ZXIgUG9ydC4gRm9yIGV4LiAiMTEwIiBmb3IgcmVndWxhciBjb25uZWN0aW9uLCAiOTk1IiBmb3Igc2VjdXJlIGNvbm5lY3Rpb24u</PHRASE>
+ <PHRASE Label="la_hint_PopServer" Module="Core" Type="1">UE9QMyBTZXJ2ZXIgQWRkcmVzcy4gRm9yIGV4LiB1c2UgInNzbDovL3BvcC5nbWFpbC5jb20iIGZvciBHbWFpbCwgInBvcC5tYWlsLnlhaG9vLmNvbSIgZm9yIFlhaG9vLg==</PHRASE>
<PHRASE Label="la_Hot" Module="Core" Type="1">SG90</PHRASE>
<PHRASE Label="la_Html" Module="Core" Type="1">SFRNTA==</PHRASE>
<PHRASE Label="la_IDField" Module="Core" Type="1">SUQgRmllbGQ=</PHRASE>
@@ -880,6 +927,7 @@
<PHRASE Label="la_opt_After" Module="Core" Type="1">QWZ0ZXI=</PHRASE>
<PHRASE Label="la_opt_Allow" Module="Core" Type="1">QWxsb3c=</PHRASE>
<PHRASE Label="la_opt_Before" Module="Core" Type="1">QmVmb3Jl</PHRASE>
+ <PHRASE Label="la_opt_Bounce" Module="Core" Type="1">Qm91bmNlZA==</PHRASE>
<PHRASE Label="la_opt_Cancelled" Module="Core" Type="1">Q2FuY2VsZWQ=</PHRASE>
<PHRASE Label="la_opt_City" Module="Core" Type="1">Q2l0eQ==</PHRASE>
<PHRASE Label="la_opt_Colon" Module="Core" Type="1">Q29sb24=</PHRASE>
@@ -891,11 +939,15 @@
<PHRASE Label="la_opt_Description" Module="Core" Type="1">RGVzY3JpcHRpb24=</PHRASE>
<PHRASE Label="la_opt_Disabled" Module="Core" Type="1">RGlzYWJsZWQ=</PHRASE>
<PHRASE Label="la_opt_EditorsPick" Module="Core" Type="1">RWRpdG9yJ3MgUGljaw==</PHRASE>
- <PHRASE Label="la_opt_Email" Module="Core" Type="1">RW1haWw=</PHRASE>
+ <PHRASE Label="la_opt_Email" Module="Core" Type="1">RS1tYWls</PHRASE>
+ <PHRASE Label="la_opt_EmailBody" Module="Core" Type="1">RS1tYWlsIEJvZHk=</PHRASE>
+ <PHRASE Label="la_opt_EmailSubject" Module="Core" Type="1">RS1tYWlsIFN1YmplY3Q=</PHRASE>
+ <PHRASE Label="la_opt_Everyone" Module="Core" Type="1">RXZlcnlvbmU=</PHRASE>
<PHRASE Label="la_opt_Exact" Module="Core" Type="1">RXhhY3Q=</PHRASE>
<PHRASE Label="la_opt_Expired" Module="Core" Type="1">RXhwaXJlZA==</PHRASE>
<PHRASE Label="la_opt_Failed" Module="Core" Type="1">RmFpbGVk</PHRASE>
<PHRASE Label="la_opt_FirstName" Module="Core" Type="1">Rmlyc3QgTmFtZQ==</PHRASE>
+ <PHRASE Label="la_opt_GuestsOnly" Module="Core" Type="1">R3Vlc3RzIE9ubHk=</PHRASE>
<PHRASE Label="la_opt_hour" Module="Core" Type="1">aG91cihzKQ==</PHRASE>
<PHRASE Label="la_opt_InheritFromParent" Module="Core" Type="1">SW5oZXJpdCBmcm9tIFBhcmVudA==</PHRASE>
<PHRASE Label="la_opt_IP_Address" Module="Core" Type="1">SVAgQWRkcmVzcw==</PHRASE>
@@ -904,12 +956,17 @@
<PHRASE Label="la_opt_min" Module="Core" Type="1">bWludXRlKHMp</PHRASE>
<PHRASE Label="la_opt_ModalWindow" Module="Core" Type="1">TW9kYWwgV2luZG93</PHRASE>
<PHRASE Label="la_opt_month" Module="Core" Type="1">bW9udGgocyk=</PHRASE>
+ <PHRASE Label="la_opt_NewEmail" Module="Core" Type="1">TmV3IEUtbWFpbA==</PHRASE>
<PHRASE Label="la_opt_NotProcessed" Module="Core" Type="1">Tm90IFByb2Nlc3NlZA==</PHRASE>
+ <PHRASE Label="la_opt_NotReplied" Module="Core" Type="1">Tm90IFJlcGxpZWQ=</PHRASE>
<PHRASE Label="la_opt_PartiallyProcessed" Module="Core" Type="1">UGFydGlhbGx5IFByb2Nlc3NlZA==</PHRASE>
<PHRASE Label="la_opt_Phone" Module="Core" Type="1">UGhvbmU=</PHRASE>
<PHRASE Label="la_opt_PopupWindow" Module="Core" Type="1">UG9wdXAgV2luZG93</PHRASE>
<PHRASE Label="la_opt_Processed" Module="Core" Type="1">UHJvY2Vzc2Vk</PHRASE>
<PHRASE Label="la_opt_Rating" Module="Core" Type="1">UmF0aW5n</PHRASE>
+ <PHRASE Label="la_opt_RecipientEmail" Module="Core" Type="1">UmVjaXBpZW50IEUtbWFpbA==</PHRASE>
+ <PHRASE Label="la_opt_RecipientName" Module="Core" Type="1">UmVjaXBpZW50IE5hbWU=</PHRASE>
+ <PHRASE Label="la_opt_Replied" Module="Core" Type="1">UmVwbGllZA==</PHRASE>
<PHRASE Label="la_opt_Running" Module="Core" Type="1">UnVubmluZw==</PHRASE>
<PHRASE Label="la_opt_SameWindow" Module="Core" Type="1">U2FtZSBXaW5kb3c=</PHRASE>
<PHRASE Label="la_opt_sec" Module="Core" Type="1">c2Vjb25kKHMp</PHRASE>
@@ -1114,6 +1171,7 @@
<PHRASE Label="la_section_SettingsSSL" Module="Core" Type="1">U1NMIFNldHRpbmdz</PHRASE>
<PHRASE Label="la_section_SettingsSystem" Module="Core" Type="1">U3lzdGVtIFNldHRpbmdz</PHRASE>
<PHRASE Label="la_section_SettingsWebsite" Module="Core" Type="1">V2Vic2l0ZSBTZXR0aW5ncw==</PHRASE>
+ <PHRASE Label="la_section_SubmissionNotes" Module="Core" Type="1">U3VibWlzc2lvbiBOb3Rlcw==</PHRASE>
<PHRASE Label="la_section_Templates" Module="Core" Type="1">VGVtcGxhdGVz</PHRASE>
<PHRASE Label="la_section_ThumbnailImage" Module="Core" Type="1">VGh1bWJuYWlsIEltYWdl</PHRASE>
<PHRASE Label="la_section_Translation" Module="Core" Type="1">VHJhbnNsYXRpb24=</PHRASE>
@@ -1231,6 +1289,7 @@
<PHRASE Label="la_tab_ConfigSettings" Module="Core" Type="1">R2VuZXJhbA==</PHRASE>
<PHRASE Label="la_tab_Custom" Module="Core" Type="1">Q3VzdG9t</PHRASE>
<PHRASE Label="la_tab_E-mails" Module="Core" Type="1">RS1tYWlsIFRlbXBsYXRlcw==</PHRASE>
+ <PHRASE Label="la_tab_EmailCommunication" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24=</PHRASE>
<PHRASE Label="la_tab_EmailEvents" Module="Core" Type="1">RW1haWwgRXZlbnRz</PHRASE>
<PHRASE Label="la_tab_EmailLog" Module="Core" Type="1">RS1tYWlsIExvZw==</PHRASE>
<PHRASE Label="la_tab_EmailQueue" Module="Core" Type="1">RW1haWwgUXVldWU=</PHRASE>
@@ -1245,6 +1304,7 @@
<PHRASE Label="la_tab_ImportData" Module="Core" Type="1">SW1wb3J0IERhdGE=</PHRASE>
<PHRASE Label="la_tab_Items" Module="Core" Type="1">SXRlbXM=</PHRASE>
<PHRASE Label="la_tab_Labels" Module="Core" Type="1">TGFiZWxz</PHRASE>
+ <PHRASE Label="la_tab_Messages" Module="Core" Type="1">TWVzc2FnZXM=</PHRASE>
<PHRASE Label="la_tab_PackageContent" Module="Core" Type="1">UGFja2FnZSBDb250ZW50</PHRASE>
<PHRASE Label="la_tab_Permissions" Module="Core" Type="1">UGVybWlzc2lvbnM=</PHRASE>
<PHRASE Label="la_tab_Properties" Module="Core" Type="1">UHJvcGVydGllcw==</PHRASE>
@@ -1374,6 +1434,7 @@
<PHRASE Label="la_title_Agents" Module="Core" Type="1">QWdlbnRz</PHRASE>
<PHRASE Label="la_title_BaseStyles" Module="Core" Type="1">QmFzZSBTdHlsZXM=</PHRASE>
<PHRASE Label="la_title_BlockStyles" Module="Core" Type="1">QmxvY2sgU3R5bGVz</PHRASE>
+ <PHRASE Label="la_title_BounceSettings" Module="Core" Type="1">Qm91bmNlIFBPUDMgU2VydmVyIFNldHRpbmdz</PHRASE>
<PHRASE Label="la_title_Categories" Module="Core" Type="1">U2VjdGlvbnM=</PHRASE>
<PHRASE Label="la_title_category_select" Module="Core" Type="1">U2VsZWN0IHNlY3Rpb24=</PHRASE>
<PHRASE Label="la_title_ColumnPicker" Module="Core" Type="1">Q29sdW1uIFBpY2tlcg==</PHRASE>
@@ -1413,6 +1474,7 @@
<PHRASE Label="la_title_Editing_Stylesheet" Module="Core" Type="1">RWRpdGluZyBTdHlsZXNoZWV0</PHRASE>
<PHRASE Label="la_title_Editing_Theme" Module="Core" Type="1">RWRpdGluZyBUaGVtZQ==</PHRASE>
<PHRASE Label="la_title_Editing_User" Module="Core" Type="1">RWRpdGluZyBVc2Vy</PHRASE>
+ <PHRASE Label="la_title_EmailCommunication" Module="Core" Type="1">RS1tYWlsIENvbW11bmljYXRpb24=</PHRASE>
<PHRASE Label="la_title_EmailEvents" Module="Core" Type="1">RS1tYWlsIEV2ZW50cw==</PHRASE>
<PHRASE Label="la_title_EmailMessages" Module="Core" Type="1">RS1tYWlscw==</PHRASE>
<PHRASE Label="la_title_EmailSettings" Module="Core" Type="1">RS1tYWlsIFNldHRpbmdz</PHRASE>
@@ -1434,9 +1496,11 @@
<PHRASE Label="la_title_LanguagesManagement" Module="Core" Type="1">TGFuZ3VhZ2VzIE1hbmFnZW1lbnQ=</PHRASE>
<PHRASE Label="la_title_Loading" Module="Core" Type="1">TG9hZGluZyAuLi4=</PHRASE>
<PHRASE Label="la_title_MailingLists" Module="Core" Type="1">TWFpbGluZ3M=</PHRASE>
+ <PHRASE Label="la_title_Messages" Module="Core" Type="1">TWVzc2FnZXM=</PHRASE>
<PHRASE Label="la_title_Module_Status" Module="Core" Type="1">TW9kdWxlcw==</PHRASE>
<PHRASE Label="la_title_NewAgent" Module="Core" Type="1">TmV3IEFnZW50</PHRASE>
<PHRASE Label="la_title_NewFile" Module="Core" Type="1">TmV3IEZpbGU=</PHRASE>
+ <PHRASE Label="la_title_NewReply" Module="Core" Type="1">TmV3IFJlcGx5</PHRASE>
<PHRASE Label="la_title_NewTheme" Module="Core" Type="1">TmV3IFRoZW1l</PHRASE>
<PHRASE Label="la_title_NewThemeFile" Module="Core" Type="1">TmV3IFRoZW1lIFRlbXBsYXRl</PHRASE>
<PHRASE Label="la_title_New_BaseStyle" Module="Core" Type="1">TmV3IEJhc2UgU3R5bGU=</PHRASE>
@@ -1454,6 +1518,7 @@
<PHRASE Label="la_title_Properties" Module="Core" Type="1">UHJvcGVydGllcw==</PHRASE>
<PHRASE Label="la_title_RelatedSearches" Module="Core" Type="1">UmVsYXRlZCBTZWFyY2hlcw==</PHRASE>
<PHRASE Label="la_title_Relations" Module="Core" Type="1">UmVsYXRpb25z</PHRASE>
+ <PHRASE Label="la_title_ReplySettings" Module="Core" Type="1">UmVwbHkgUE9QMyBTZXJ2ZXIgU2V0dGluZ3M=</PHRASE>
<PHRASE Label="la_title_Reviews" Module="Core" Type="1">Q29tbWVudHM=</PHRASE>
<PHRASE Label="la_title_SelectGroup" Module="Core" Type="1">U2VsZWN0IEdyb3VwKHMp</PHRASE>
<PHRASE Label="la_title_SelectUser" Module="Core" Type="1">U2VsZWN0IFVzZXI=</PHRASE>
@@ -1471,6 +1536,7 @@
<PHRASE Label="la_title_Users" Module="Core" Type="1">VXNlcnM=</PHRASE>
<PHRASE Label="la_title_ViewingFormSubmission" Module="Core" Type="1">Vmlld2luZyBmb3JtIHN1Ym1pc3Npb24=</PHRASE>
<PHRASE Label="la_title_ViewingMailingList" Module="Core" Type="1">Vmlld2luZyBNYWlsaW5nIExpc3Q=</PHRASE>
+ <PHRASE Label="la_title_ViewingReply" Module="Core" Type="1">Vmlld2luZyBSZXBseQ==</PHRASE>
<PHRASE Label="la_title_Visits" Module="Core" Type="1">VmlzaXRz</PHRASE>
<PHRASE Label="la_title_Website" Module="Core" Type="1">V2Vic2l0ZQ==</PHRASE>
<PHRASE Label="la_ToolTipShort_Edit_Current_Category" Module="Core" Type="1">Q3Vyci4gU2VjdGlvbg==</PHRASE>
@@ -1537,12 +1603,15 @@
<PHRASE Label="la_ToolTip_RebuildCategoryCache" Module="Core" Type="1">UmVidWlsZCBTZWN0aW9uIENhY2hl</PHRASE>
<PHRASE Label="la_ToolTip_RecalculatePriorities" Module="Core" Type="1">UmVjYWxjdWxhdGUgUHJpb3JpdGllcw==</PHRASE>
<PHRASE Label="la_ToolTip_Refresh" Module="Core" Type="1">UmVmcmVzaA==</PHRASE>
+ <PHRASE Label="la_ToolTip_Reply" Module="Core" Type="1">UmVwbHk=</PHRASE>
<PHRASE Label="la_ToolTip_RescanThemes" Module="Core" Type="1">UmVzY2FuIFRoZW1lcw==</PHRASE>
+ <PHRASE Label="la_ToolTip_Resend" Module="Core" Type="1">UmVzZW5k</PHRASE>
<PHRASE Label="la_ToolTip_Reset" Module="Core" Type="1">UmVzZXQ=</PHRASE>
<PHRASE Label="la_ToolTip_ResetSettings" Module="Core" Type="1">UmVzZXQgUGVyc2lzdGVudCBTZXR0aW5ncw==</PHRASE>
<PHRASE Label="la_ToolTip_ResetToBase" Module="Core" Type="1">UmVzZXQgVG8gQmFzZQ==</PHRASE>
<PHRASE Label="la_ToolTip_RunSQL" Module="Core" Type="1">UnVuIFNRTA==</PHRASE>
<PHRASE Label="la_ToolTip_save" Module="Core" Type="1">U2F2ZQ==</PHRASE>
+ <PHRASE Label="la_ToolTip_SaveAsDraft" Module="Core" Type="1">U2F2ZSBhcyBEcmFmdA==</PHRASE>
<PHRASE Label="la_ToolTip_Search" Module="Core" Type="1">U2VhcmNo</PHRASE>
<PHRASE Label="la_ToolTip_SearchReset" Module="Core" Type="1">UmVzZXQ=</PHRASE>
<PHRASE Label="la_ToolTip_SelectUser" Module="Core" Type="1">U2VsZWN0IFVzZXI=</PHRASE>
@@ -1662,6 +1731,9 @@
<EVENT MessageType="html" Event="CATEGORY.APPROVE" Type="0">U3ViamVjdDogQSBjYXRlZ29yeSBoYXMgYmVlbiBhcHByb3ZlZAoKWW91ciBzdWdnZXN0ZWQgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYXBwcm92ZWQu</EVENT>
<EVENT MessageType="html" Event="CATEGORY.DENY" Type="0">U3ViamVjdDogWW91ciBDYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBEZW5pZWQKCllvdXIgY2F0ZWdvcnkgc3VnZ2VzdGlvbiAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBkZW5pZWQu</EVENT>
<EVENT MessageType="html" Event="COMMON.FOOTER" Type="1">U3ViamVjdDogQ29tbW9uIEZvb3RlciBUZW1wbGF0ZQoKPGJyLz48YnIvPg0KDQpTaW5jZXJlbHksPGJyLz48YnIvPg0KDQpXZWJzaXRlIGFkbWluaXN0cmF0aW9uLg==</EVENT>
+ <EVENT MessageType="html" Event="FORM.SUBMISSION.REPLY.FROM.USER" Type="1">U3ViamVjdDogTmV3IEVtYWlsIFJFUExZIFJlY2VpdmVkIGluICJGZWVkYmFjayBNYW5hZ2VyIiAoPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRmllbGQgbmFtZT0iRm9ybVN1Ym1pc3Npb25JZCIvPikKCk5ldyBFbWFpbCBSRVBMWSBSZWNlaXZlZCBpbiAmcXVvdDtGZWVkYmFjayBNYW5hZ2VyJnF1b3Q7LjxiciAvPg0KPGJyIC8+DQpPcmlnaW5hbCBGZWVkYmFja0lkOiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9GaWVsZCBuYW1lPSJGb3JtU3VibWlzc2lvbklkIi8+IDxiciAvPg0KT3JpZ2luYWwgU3ViamVjdDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRm9ybUZpZWxkIHJvbGU9InN1YmplY3QiLz4gPGJyIC8+DQo8YnIgLz4NClBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIGluIG9yZGVyIHRvIHJldmlldyBhbmQgcmVwbHkgdG8gdGhlIHVzZXIu</EVENT>
+ <EVENT MessageType="html" Event="FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED" Type="1">U3ViamVjdDogTmV3IEVtYWlsIC0gRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAiRmVlZGJhY2sgTWFuYWdlciIgKDxpbnAyOmZvcm1zdWJzLi1pdGVtX0ZpZWxkIG5hbWU9IkZvcm1TdWJtaXNzaW9uSWQiLz4pCgpOZXcgRW1haWwgRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAmcXVvdDtGZWVkYmFjayBNYW5hZ2VyJnF1b3Q7LjxiciAvPg0KPGJyIC8+DQpPcmlnaW5hbCBGZWVkYmFja0lkOiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9GaWVsZCBuYW1lPSJGb3JtU3VibWlzc2lvbklkIi8+IDxiciAvPg0KT3JpZ2luYWwgU3ViamVjdDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRm9ybUZpZWxkIHJvbGU9InN1YmplY3QiLz4gPGJyIC8+DQo8YnIgLz4NClBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIGluIG9yZGVyIHRvIHJldmlldyBhbmQgcmVwbHkgdG8gdGhlIHVzZXIu</EVENT>
+ <EVENT MessageType="html" Event="FORM.SUBMISSION.REPLY.TO.USER" Type="1">U3ViamVjdDogPGlucDI6bV9QYXJhbSBuYW1lPSJzdWJqZWN0Ii8+ICN2ZXJpZnk8aW5wMjpzdWJtaXNzaW9uLWxvZ19GaWVsZCBuYW1lPSJWZXJpZnlDb2RlIi8+Cgo8aW5wMjptX1BhcmFtIG5hbWU9Im1lc3NhZ2UiLz4=</EVENT>
<EVENT MessageType="html" Event="FORM.SUBMITTED" Type="0">U3ViamVjdDogVGhhbmsgWW91IGZvciBDb250YWN0aW5nIFVzIQoKPHA+VGhhbmsgeW91IGZvciBjb250YWN0aW5nIHVzLiBXZSdsbCBiZSBpbiB0b3VjaCB3aXRoIHlvdSBzaG9ydGx5ITwvcD4=</EVENT>
<EVENT MessageType="html" Event="FORM.SUBMITTED" Type="1">U3ViamVjdDogTmV3IGZvcm0gc3VibWlzc2lvbgoKPHA+Rm9ybSBoYXMgYmVlbiBzdWJtaXR0ZWQuIFBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIHRvIHJldmlldyB0aGUgc3VibWlzc2lvbiE8L3A+</EVENT>
<EVENT MessageType="html" Event="USER.ADD" Type="0">U3ViamVjdDogSW4tcG9ydGFsIHJlZ2lzdHJhdGlvbgoKRGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIgLz4gPGlucDI6dV9GaWVsZCBuYW1lPSJMYXN0TmFtZSIgLz4sDQoNClRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9CYXNlVXJsLz4uIFlvdXIgcmVnaXN0cmF0aW9uIGlzIG5vdyBhY3RpdmUu</EVENT>
Index: core/install/install_data.sql
===================================================================
--- core/install/install_data.sql (revision 13377)
+++ core/install/install_data.sql (working copy)
@@ -160,6 +160,9 @@
INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'COMMON.FOOTER', NULL, 1, 0, NULL, 'Core', 'Common Footer Template', 1);
INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, NULL, 'Core:Category', 'This e-mail is sent to a user after filling in the Contact Us form', 1);
INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, NULL, 'Core:Category', 'This e-mail is sent to a user after filling in the Contact Us form', 0);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.TO.USER', NULL, 1, 0, NULL, 'Core:Category', 'Admin Reply to User Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER', NULL, 1, 0, NULL, 'Core:Category', 'User Replied to It\'s Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED', NULL, 1, 0, NULL, 'Core:Category', 'Form Submission Admin Reply Delivery Failure', 1);
INSERT INTO IdGenerator VALUES ('100');
Index: core/install/install_schema.sql
===================================================================
--- core/install/install_schema.sql (revision 13377)
+++ core/install/install_schema.sql (working copy)
@@ -1064,28 +1064,102 @@
DisplayInGrid tinyint(1) NOT NULL DEFAULT '1',
DefaultValue text,
Validation tinyint(4) NOT NULL DEFAULT '0',
+ Visibility tinyint(4) NOT NULL DEFAULT '1',
+ EmailCommunicationRole tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (FormFieldId),
KEY `Type` (`Type`),
KEY FormId (FormId),
KEY Priority (Priority),
KEY IsSystem (IsSystem),
- KEY DisplayInGrid (DisplayInGrid)
+ KEY DisplayInGrid (DisplayInGrid),
+ KEY Visibility (Visibility),
+ KEY EmailCommunicationRole (EmailCommunicationRole)
);
CREATE TABLE FormSubmissions (
FormSubmissionId int(11) NOT NULL AUTO_INCREMENT,
FormId int(11) NOT NULL DEFAULT '0',
SubmissionTime int(11) DEFAULT NULL,
+ IPAddress varchar(15) NOT NULL DEFAULT '',
+ ReferrerURL varchar(255) NOT NULL DEFAULT '',
+ LogStatus tinyint(3) unsigned NOT NULL DEFAULT '2',
+ LastUpdatedOn int(10) unsigned DEFAULT NULL,
+ Notes text,
PRIMARY KEY (FormSubmissionId),
KEY FormId (FormId),
- KEY SubmissionTime (SubmissionTime)
+ KEY SubmissionTime (SubmissionTime),
+ KEY LogStatus (LogStatus),
+ KEY LastUpdatedOn (LastUpdatedOn)
);
+CREATE TABLE SubmissionLog (
+ SubmissionLogId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL,
+ FromEmail varchar(255) NOT NULL DEFAULT '',
+ ToEmail varchar(255) NOT NULL DEFAULT '',
+ Cc text,
+ Bcc text,
+ `Subject` varchar(255) NOT NULL DEFAULT '',
+ Message text,
+ Attachment text,
+ ReplyStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentOn int(10) unsigned DEFAULT NULL,
+ RepliedOn int(10) unsigned DEFAULT NULL,
+ VerifyCode varchar(32) NOT NULL DEFAULT '',
+ DraftId int(10) unsigned NOT NULL DEFAULT '0',
+ MessageId varchar(255) NOT NULL DEFAULT '',
+ BounceInfo text,
+ BounceDate int(11) DEFAULT NULL,
+ PRIMARY KEY (SubmissionLogId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY ReplyStatus (ReplyStatus),
+ KEY SentStatus (SentStatus),
+ KEY SentOn (SentOn),
+ KEY RepliedOn (RepliedOn),
+ KEY VerifyCode (VerifyCode),
+ KEY DraftId (DraftId),
+ KEY BounceDate (BounceDate),
+ KEY MessageId (MessageId)
+);
+
+CREATE TABLE Drafts (
+ DraftId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL DEFAULT '0',
+ CreatedOn int(10) unsigned DEFAULT NULL,
+ CreatedById int(11) NOT NULL,
+ Message text,
+ PRIMARY KEY (DraftId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY CreatedOn (CreatedOn),
+ KEY CreatedById (CreatedById)
+);
+
CREATE TABLE Forms (
- FormId int(11) NOT NULL auto_increment,
- Title VARCHAR(255) NOT NULL DEFAULT '',
+ FormId int(11) NOT NULL AUTO_INCREMENT,
+ Title varchar(255) NOT NULL DEFAULT '',
Description text,
- PRIMARY KEY (FormId)
+ RequireLogin tinyint(4) NOT NULL DEFAULT '0',
+ UseSecurityImage tinyint(4) NOT NULL DEFAULT '0',
+ EnableEmailCommunication tinyint(4) NOT NULL DEFAULT '0',
+ ReplyFromName varchar(255) NOT NULL DEFAULT '',
+ ReplyFromEmail varchar(255) NOT NULL DEFAULT '',
+ ReplyCc varchar(255) NOT NULL DEFAULT '',
+ ReplyBcc varchar(255) NOT NULL DEFAULT '',
+ ReplyMessageSignature text,
+ ReplyServer varchar(255) NOT NULL DEFAULT '',
+ ReplyPort int(11) NOT NULL DEFAULT '110',
+ ReplyUsername varchar(255) NOT NULL DEFAULT '',
+ ReplyPassword varchar(255) NOT NULL DEFAULT '',
+ BounceEmail varchar(255) NOT NULL DEFAULT '',
+ BounceServer varchar(255) NOT NULL DEFAULT '',
+ BouncePort int(11) NOT NULL DEFAULT '110',
+ BounceUsername varchar(255) NOT NULL DEFAULT '',
+ BouncePassword varchar(255) NOT NULL DEFAULT '',
+ PRIMARY KEY (FormId),
+ KEY UseSecurityImage (UseSecurityImage),
+ KEY RequireLogin (RequireLogin),
+ KEY EnableEmailCommunication (EnableEmailCommunication)
);
CREATE TABLE Semaphores (
Index: core/install/remove_schema.sql
===================================================================
--- core/install/remove_schema.sql (revision 13377)
+++ core/install/remove_schema.sql (working copy)
@@ -65,6 +65,8 @@
DROP TABLE PageContent;
DROP TABLE FormFields;
DROP TABLE FormSubmissions;
+DROP TABLE SubmissionLog;
+DROP TABLE Drafts;
DROP TABLE Forms;
DROP TABLE Semaphores;
DROP TABLE CachedUrls;
Index: core/install/upgrades.sql
===================================================================
--- core/install/upgrades.sql (revision 13377)
+++ core/install/upgrades.sql (working copy)
@@ -1710,4 +1710,88 @@
cv.GroupDisplayOrder = (SELECT ca7.GroupDisplayOrder FROM <%TABLE_PREFIX%>ConfigurationAdmin ca7 WHERE ca7.VariableName = cv.VariableName),
cv.`Install` = (SELECT ca8.`Install` FROM <%TABLE_PREFIX%>ConfigurationAdmin ca8 WHERE ca8.VariableName = cv.VariableName);
-DROP TABLE ConfigurationAdmin;
\ No newline at end of file
+DROP TABLE ConfigurationAdmin;
+
+ALTER TABLE Forms
+ ADD RequireLogin TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (RequireLogin),
+ ADD UseSecurityImage TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (UseSecurityImage),
+ ADD EnableEmailCommunication TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (EnableEmailCommunication),
+ ADD ReplyFromName VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyFromEmail VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyCc VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyBcc VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyMessageSignature TEXT,
+ ADD ReplyServer VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyPort INT(10) NOT NULL DEFAULT '110',
+ ADD ReplyUsername VARCHAR(255) NOT NULL DEFAULT '',
+ ADD ReplyPassword VARCHAR(255) NOT NULL DEFAULT ''
+ ADD BounceEmail VARCHAR(255) NOT NULL DEFAULT '',
+ ADD BounceServer VARCHAR(255) NOT NULL DEFAULT '',
+ ADD BouncePort INT(10) NOT NULL DEFAULT '110',
+ ADD BounceUsername VARCHAR(255) NOT NULL DEFAULT '',
+ ADD BouncePassword VARCHAR(255) NOT NULL DEFAULT '';
+
+ALTER TABLE FormFields
+ ADD Visibility TINYINT NOT NULL DEFAULT '1',
+ ADD INDEX (Visibility),
+ ADD EmailCommunicationRole TINYINT NOT NULL DEFAULT '0',
+ ADD INDEX (EmailCommunicationRole);
+
+ALTER TABLE FormSubmissions
+ ADD IPAddress VARCHAR(15) NOT NULL DEFAULT '' AFTER SubmissionTime,
+ ADD ReferrerURL VARCHAR(255) NOT NULL DEFAULT '' AFTER IPAddress,
+ ADD LogStatus TINYINT UNSIGNED NOT NULL DEFAULT '2' AFTER ReferrerURL,
+ ADD LastUpdatedOn INT UNSIGNED NULL AFTER LogStatus,
+ ADD Notes TEXT NULL AFTER LastUpdatedOn,
+ ADD INDEX (LogStatus),
+ ADD INDEX (LastUpdatedOn);
+
+CREATE TABLE SubmissionLog (
+ SubmissionLogId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL,
+ FromEmail varchar(255) NOT NULL DEFAULT '',
+ ToEmail varchar(255) NOT NULL DEFAULT '',
+ Cc text,
+ Bcc text,
+ `Subject` varchar(255) NOT NULL DEFAULT '',
+ Message text,
+ Attachment text,
+ ReplyStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentStatus tinyint(3) unsigned NOT NULL DEFAULT '0',
+ SentOn int(10) unsigned DEFAULT NULL,
+ RepliedOn int(10) unsigned DEFAULT NULL,
+ VerifyCode varchar(32) NOT NULL DEFAULT '',
+ DraftId int(10) unsigned NOT NULL DEFAULT '0',
+ MessageId varchar(255) NOT NULL DEFAULT '',
+ BounceInfo text,
+ BounceDate int(11) DEFAULT NULL,
+ PRIMARY KEY (SubmissionLogId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY ReplyStatus (ReplyStatus),
+ KEY SentStatus (SentStatus),
+ KEY SentOn (SentOn),
+ KEY RepliedOn (RepliedOn),
+ KEY VerifyCode (VerifyCode),
+ KEY DraftId (DraftId),
+ KEY BounceDate (BounceDate),
+ KEY MessageId (MessageId)
+);
+
+CREATE TABLE Drafts (
+ DraftId int(11) NOT NULL AUTO_INCREMENT,
+ FormSubmissionId int(10) unsigned NOT NULL DEFAULT '0',
+ CreatedOn int(10) unsigned DEFAULT NULL,
+ CreatedById int(11) NOT NULL,
+ Message text,
+ PRIMARY KEY (DraftId),
+ KEY FormSubmissionId (FormSubmissionId),
+ KEY CreatedOn (CreatedOn),
+ KEY CreatedById (CreatedById)
+);
+
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.TO.USER', NULL, 1, 0, NULL, 'Core:Category', 'Admin Reply to User Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER', NULL, 1, 0, NULL, 'Core:Category', 'User Replied to It\'s Form Submission', 1);
+INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED', NULL, 1, 0, NULL, 'Core:Category', 'Form Submission Admin Reply Delivery Failure', 1);
\ No newline at end of file
Index: core/kernel/constants.php
===================================================================
--- core/kernel/constants.php (revision 13377)
+++ core/kernel/constants.php (working copy)
@@ -129,3 +129,28 @@
define('SESSION_LOG_ACTIVE', 0);
define('SESSION_LOG_LOGGED_OUT', 1);
define('SESSION_LOG_EXPIRED', 2);
+
+ // form field visibility
+ define('FORM_FIELD_EVERYONE', 1);
+ define('FORM_FIELD_UNREGISTERED', 2);
+
+ // form field e-mail communication roles
+ define('EMAIL_COMMUNICATION_ROLE_NAME', 1);
+ define('EMAIL_COMMUNICATION_ROLE_EMAIL', 2);
+ define('EMAIL_COMMUNICATION_ROLE_SUBJECT', 3);
+ define('EMAIL_COMMUNICATION_ROLE_BODY', 4);
+
+ // form submission statuses
+ define('SUBMISSION_REPLIED', 1); // submission was replied by admin
+ define('SUBMISSION_NOT_REPLIED', 2); // submission has no client replies (no messages at all)
+ define('SUBMISSION_NEW_EMAIL', 3); // submission have new reply/email from client
+ define('SUBMISSION_BOUNCE', 4); // submission have bounce from client
+
+ // submission log statuses
+ define('SUBMISSION_LOG_SENT', 1);
+ define('SUBMISSION_LOG_BOUNCE', 2);
+ define('SUBMISSION_LOG_REPLIED', 1);
+
+ define('SUBMISSION_LOG_ATTACHMENT_PATH', WRITEBALE_BASE . '/user_files/submission_log/');
+
+ define('TIMENOW', adodb_mktime()); // for faster message processing
\ No newline at end of file
Index: core/units/drafts/draft_eh.php
===================================================================
--- core/units/drafts/draft_eh.php (revision 0)
+++ core/units/drafts/draft_eh.php (revision 0)
@@ -0,0 +1,43 @@
+<?php
+
+ class DraftEventHandler extends kDBEventHandler
+ {
+
+ /**
+ * Sets user, who created draft
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $user_id = $this->Application->RecallVar('user_id');
+
+ $object->SetDBField('CreatedById', $user_id);
+ }
+
+ /**
+ * Allows to load draft, that best matches given form submission
+ *
+ * @param kEvent $event
+ * @return int
+ */
+ function getPassedID(&$event)
+ {
+ if ($event->Special == 'related') {
+ $form_submission =& $this->Application->recallObject('formsubs');
+ /* @var $form_submission kDBItem */
+
+ return Array (
+ 'FormSubmissionId' => $form_submission->GetID(),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+ }
+
+ return parent::getPassedID($event);
+ }
+ }
\ No newline at end of file
Index: core/units/drafts/drafts_config.php
===================================================================
--- core/units/drafts/drafts_config.php (revision 0)
+++ core/units/drafts/drafts_config.php (revision 0)
@@ -0,0 +1,48 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => 'draft',
+ 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
+ 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
+ 'EventHandlerClass' => Array ('class' => 'DraftEventHandler', 'file' => 'draft_eh.php', 'build_event' => 'OnBuild'),
+ 'TagProcessorClass' => Array ('class' => 'kDBTagProcessor', 'file' => '', 'build_event' => 'OnBuild'),
+
+ 'AutoLoad' => true,
+
+ 'QueryString' => Array (
+ 1 => 'id',
+ 2 => 'Page',
+ 3 => 'event',
+ 4 => 'mode',
+ ),
+
+ 'IDField' => 'DraftId',
+
+ 'ParentPrefix' => 'formsubs',
+ 'ForeignKey' => 'FormSubmissionId',
+ 'ParentTableKey' => 'FormSubmissionId',
+ 'AutoDelete' => true,
+ 'AutoClone' => true,
+
+ 'TableName' => TABLE_PREFIX . 'Drafts',
+
+ 'TitleField' => 'DraftId',
+
+ 'ListSQLs' => Array (
+ '' => ' SELECT %1$s.* %2$s FROM %1$s',
+ ),
+
+ 'ListSortings' => Array (
+ '' => Array (
+ 'Sorting' => Array ('DraftId' => 'desc'),
+ )
+ ),
+
+ 'Fields' => Array (
+ 'DraftId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'FormSubmissionId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'CreatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
+ 'CreatedById' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'Message' => Array ('type' => 'string', 'default' => NULL),
+ ),
+ );
\ No newline at end of file
Index: core/units/form_fields/form_field_eh.php
===================================================================
--- core/units/form_fields/form_field_eh.php (revision 0)
+++ core/units/form_fields/form_field_eh.php (revision 0)
@@ -0,0 +1,35 @@
+<?php
+
+ class FormFieldEventHandler extends kDBEventHandler {
+
+ /**
+ * Returns form field visibility filter
+ *
+ * @return string
+ */
+ function getVisiblilityFilter()
+ {
+ if ($this->Application->LoggedIn() && !$this->Application->isAdminUser) {
+ return '%1$s.Visibility = ' . FORM_FIELD_EVERYONE;
+ }
+
+ return '';
+ }
+
+ /**
+ * Shows fields based on user logged-in status
+ *
+ * @param kEvent $event
+ */
+ function SetCustomQuery(&$event)
+ {
+ parent::SetCustomQuery($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBList */
+
+ $visibility_filter = $this->getVisiblilityFilter();
+
+ $object->addFilter('visibility_filter', $visibility_filter);
+ }
+ }
Index: core/units/form_fields/form_fields_config.php
===================================================================
--- core/units/form_fields/form_fields_config.php (revision 13377)
+++ core/units/form_fields/form_fields_config.php (working copy)
@@ -18,7 +18,7 @@
'Prefix' => 'formflds',
'ItemClass' => Array('class'=>'kDBItem','file'=>'','build_event'=>'OnItemBuild'),
'ListClass' => Array('class'=>'kDBList','file'=>'','build_event'=>'OnListBuild'),
- 'EventHandlerClass' => Array('class'=>'kDBEventHandler','file'=>'','build_event'=>'OnBuild'),
+ 'EventHandlerClass' => Array('class'=>'FormFieldEventHandler','file'=>'form_field_eh.php','build_event'=>'OnBuild'),
'TagProcessorClass' => Array('class'=>'FormFieldsTagProcessor','file'=>'form_fields_tp.php'),
'AutoLoad' => true,
'QueryString' => Array(
@@ -77,6 +77,16 @@
'DisplayInGrid' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array(0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1),
'DefaultValue' => Array('type' => 'string', 'default' => NULL),
'Validation' => Array('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array(0 => 'la_None', 1 => 'la_ValidationEmail'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0),
+ 'Visibility' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_Everyone', 2 => 'la_opt_GuestsOnly'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 1
+ ),
+ 'EmailCommunicationRole' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_RecipientName', 2 => 'la_opt_RecipientEmail', 3 => 'la_opt_EmailSubject', 4 => 'la_opt_EmailBody'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
),
'VirtualFields' => Array(
@@ -96,6 +106,8 @@
'ElementType' => Array('title' => 'la_prompt_ElementType', 'filter_block' => 'grid_options_filter'),
'Required' => Array('title' => 'la_prompt_Required', 'filter_block' => 'grid_options_filter'),
'DisplayInGrid' => Array('title' => 'la_prompt_DisplayInGrid', 'filter_block' => 'grid_options_filter', 'width' => 150 ),
+ 'Visibility' => Array('title' => 'la_col_Visibility', 'filter_block' => 'grid_options_filter', 'width' => 100),
+ 'EmailCommunicationRole' => Array('title' => 'la_col_EmailCommunicationRole', 'filter_block' => 'grid_options_filter', 'width' => 150),
),
),
),
Index: core/units/form_fields/form_fields_tp.php
===================================================================
--- core/units/form_fields/form_fields_tp.php (revision 13377)
+++ core/units/form_fields/form_fields_tp.php (working copy)
@@ -45,7 +45,17 @@
*/
function PrepareListElementParams(&$object, &$block_params)
{
- $object->SetDBField('DirectOptions', false);
+ if (!array_key_exists('SourcePrefix', $block_params)) {
+ // don't have source prefix in administrative console
+ $object->SetDBField('DirectOptions', false);
+ return ;
+ }
+
+ $submission =& $this->Application->recallObject( $block_params['SourcePrefix'] );
+ /* @var $submission kDBItem */
+
+ $options = $submission->GetFieldOptions('fld_' . $object->GetID());
+ $object->SetDBField('DirectOptions', array_key_exists('options', $options) ? $options['options'] : false);
}
}
\ No newline at end of file
Index: core/units/form_submissions/form_submission_tp.php
===================================================================
--- core/units/form_submissions/form_submission_tp.php (revision 13377)
+++ core/units/form_submissions/form_submission_tp.php (working copy)
@@ -19,4 +19,28 @@
return $this->Application->Phrase($phrase_name);
}
+
+ /**
+ * Allows to retrieve for submission field by it's name or role in email communications
+ *
+ * @param Array $params
+ * @return string
+ */
+ function FormField($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $formatted = !(array_key_exists('db', $params) && $params['db']);
+ $format = $formatted ? (array_key_exists('format', $params) ? $params['format'] : null) : null;
+
+ if (array_key_exists('role', $params)) {
+ return $form_submission_helper->getFieldByRole($object, $params['role'], $formatted, $format);
+ }
+
+ return $form_submission_helper->getFieldByName($params['name'], $formatted, $format);
+ }
}
Index: core/units/form_submissions/form_submissions_config.php
===================================================================
--- core/units/form_submissions/form_submissions_config.php (revision 13377)
+++ core/units/form_submissions/form_submissions_config.php (working copy)
@@ -32,39 +32,70 @@
Array(
'Mode' => hAFTER,
'Conditional' => false,
- 'HookToPrefix' => 'formsubs', //self
+ 'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnAfterConfigRead'),
'DoPrefix' => '',
'DoSpecial' => '',
'DoEvent' => 'OnBuildFormFields',
),
- ),
- 'TitlePresets' => Array(
- 'default' => Array( 'new_status_labels' => Array('form'=>'!la_title_Adding_Form!'),
- 'edit_status_labels' => Array('form'=>'!la_title_Editing_Form!'),
- 'new_titlefield' => Array('form'=>''),
+ // Captcha processing
+ Array (
+ 'Mode' => hAFTER,
+ 'Conditional' => false,
+ 'HookToPrefix' => '',
+ 'HookToSpecial' => '*',
+ 'HookToEvent' => Array('OnAfterConfigRead'),
+ 'DoPrefix' => 'captcha',
+ 'DoSpecial' => '*',
+ 'DoEvent' => 'OnPrepareCaptcha',
+ ),
),
+ 'TitlePresets' => Array(
+ 'default' => Array(
+ 'new_status_labels' => Array('form'=>'!la_title_Adding_Form!'),
+ 'edit_status_labels' => Array('form'=>'!la_title_Editing_Form!'),
+ ),
+
'formsubs_list' => Array (
- 'prefixes' => Array('form', 'formsubs_List'),
- 'format' => "!la_title_FormSubmissions! '#form_titlefield#'",
- 'toolbar_buttons' => Array ('edit', 'delete', 'dbl-click'),
- ),
+ 'prefixes' => Array('form', 'formsubs_List'),
+ 'format' => "!la_title_FormSubmissions! '#form_titlefield#'",
+ 'toolbar_buttons' => Array ('edit', 'delete', 'dbl-click'),
+ ),
'formsubs_view' => Array(
- 'prefixes' => Array('formsubs'),
- 'format' => "!la_title_ViewingFormSubmission!",
- 'toolbar_buttons' => Array ('cancel', 'prev', 'next'),
- ),
+ 'prefixes' => Array('formsubs'),
+ 'format' => "!la_title_ViewingFormSubmission!",
+ 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'),
+ ),
- ),
+ 'submission_edit_logs' => Array (
+ 'prefixes' => Array ('formsubs', 'submission-log_List'),
+ 'format' => "!la_title_ViewingFormSubmission! - !la_title_Messages! (#submission-log_recordcount#)"
+ ),
+ 'submission_log_edit' => Array (
+ 'new_status_labels' => Array ('submission-log' => '!la_title_NewReply!'),
+ 'edit_status_labels' => Array ('submission-log' => '!la_title_ViewingReply!'),
+
+ 'prefixes' => Array ('submission-log'), 'format' => "!la_title_ViewingFormSubmission! - #submission-log_status#"
+ ),
+ ),
+
+ 'EditTabPresets' => Array (
+ 'Default' => Array (
+ Array ('title' => 'la_tab_General', 't' => 'submissions/submission_view', 'priority' => 1),
+ Array ('title' => 'la_tab_Messages', 't' => 'submissions/submission_edit_logs', 'priority' => 2),
+ ),
+ ),
+
'PermSection' => Array('main' => 'in-portal:submissions'),
'IDField' => 'FormSubmissionId',
/*'TitleField' => 'Name',*/
+ 'StatusField' => Array ('LogStatus'),
'TableName' => TABLE_PREFIX.'FormSubmissions',
'ListSQLs' => Array(
''=>' SELECT %1$s.* %2$s FROM %1$s',
@@ -79,16 +110,29 @@
'AutoDelete' => true,
'AutoClone' => true,*/
+ 'SubItems' => Array ('submission-log', 'draft'),
+
'ListSortings' => Array(
'' => Array(
'Sorting' => Array('SubmissionTime' => 'desc'),
)
),
- 'Fields' => Array(
- 'FormSubmissionId' => Array('type' => 'int', 'not_null' => 1,'default' => 0),
- 'FormId' => Array('type' => 'int','not_null' => '1','default' => 0),
- 'SubmissionTime' => Array('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
+ 'Fields' => Array(
+ 'FormSubmissionId' => Array('type' => 'int', 'not_null' => 1,'default' => 0),
+ 'FormId' => Array('type' => 'int','not_null' => '1','default' => 0),
+ 'SubmissionTime' => Array('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
+ 'IPAddress' => Array ('type' => 'string', 'max_len' => 15, 'not_null' => 1, 'default' => ''),
+ 'ReferrerURL' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+
+ 'LogStatus' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_Replied', 2 => 'la_opt_NotReplied', 3 => 'la_opt_NewEmail', 4 => 'la_opt_Bounce'), 'use_phrases' => 1,
+ 'not_null' => 1, 'required' => 1, 'default' => 2
+ ),
+
+ 'LastUpdatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
+ 'Notes' => Array ('type' => 'string', 'default' => NULL),
),
'VirtualFields' => Array(
),
@@ -96,10 +140,14 @@
),
'Grids' => Array(
'Default' => Array(
- 'Icons' => Array('default' => 'icon16_item.png'),
+ 'Icons' => Array('default' => 'icon16_item.png', 1 => 'icon16_replied.gif', 2 => 'icon16_not_replied.gif', 3 => 'icon16_new_email.gif', 4 => 'icon16_bounce.gif'),
'Fields' => Array(
'FormSubmissionId' => Array( 'title'=>'la_col_Id', 'data_block' => 'grid_checkbox_td', 'sort_field' => 'FormFieldId', 'filter_block' => 'grid_range_filter', 'width' => 60 ),
'SubmissionTime' => Array( 'title'=>'la_prompt_SumbissionTime', 'filter_block' => 'grid_date_range_filter', 'width' => 145 ),
+ 'IPAddress' => Array ('title' => 'la_col_IPAddress', 'filter_block' => 'grid_like_filter', 'width' => 100 ),
+ 'ReferrerURL' => Array ('title' => 'la_col_ReferrerURL', 'filter_block' => 'grid_like_filter', 'first_chars' => 100, 'width' => 200 ),
+ 'LogStatus' => Array ('title' => 'la_col_Status', 'filter_block' => 'grid_options_filter', 'width' => 100 ),
+ 'LastUpdatedOn' => Array ('title' => 'la_col_LastUpdatedOn', 'filter_block' => 'grid_date_range_filter', 'width' => 145 ),
),
),
),
Index: core/units/form_submissions/form_submissions_eh.php
===================================================================
--- core/units/form_submissions/form_submissions_eh.php (revision 13377)
+++ core/units/form_submissions/form_submissions_eh.php (working copy)
@@ -24,15 +24,28 @@
return true;
}
}
+
+ $section = $event->getSection();
+ $form_id = $this->Application->GetVar('form_id');
+
+ $event->setEventParam('PermSection', $section . ':' . $form_id);
+
return parent::CheckPermission($event);
}
+ /**
+ * Always allow to view feedback form
+ *
+ */
function mapPermissions()
{
parent::mapPermissions();
+
$permissions = Array(
- 'OnEdit' => Array('self' => 'view', 'subitem' => 'view'),
+ 'OnItemBuild' => Array ('self' => true),
+ 'OnEdit' => Array ('self' => 'view', 'subitem' => 'view'),
);
+
$this->permMapping = array_merge($this->permMapping, $permissions);
}
@@ -66,6 +79,7 @@
$conf_grids = $this->Application->getUnitOption($event->Prefix, 'Grids');
$helper =& $this->Application->recallObject('InpCustomFieldsHelper');
+ /* @var $helper InpCustomFieldsHelper */
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'FormFields
@@ -73,36 +87,58 @@
ORDER BY Priority DESC';
$fields = $this->Conn->Query($sql, 'FormFieldId');
+ $use_options = Array ('radio', 'select', 'checkbox');
+ $check_visibility = $this->Application->LoggedIn() && !$this->Application->isAdminUser;
+
foreach ($fields as $field_id => $options) {
- $conf_fields['fld_'.$field_id] = Array('type'=>'string', 'default'=>$options['DefaultValue']);
- if ($options['Required']) {
- $conf_fields['fld_'.$field_id]['required'] = 1;
+ $field_visible = $check_visibility ? $options['Visibility'] == FORM_FIELD_EVERYONE : true;
+ $field_options = Array('type' => 'string', 'default' => $options['DefaultValue']);
+
+ if ($options['Required'] && $field_visible) {
+ $field_options['required'] = 1;
}
+
if ($options['Validation'] == 1) {
- $conf_fields['fld_'.$field_id]['formatter'] = 'kFormatter';
- $conf_fields['fld_'.$field_id]['regexp'] = '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i';
+ $field_options['formatter'] = 'kFormatter';
+ $field_options['regexp'] = '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i';
}
+
if ($options['DisplayInGrid']) {
$title = $options['Prompt'];
- if (substr($title, 0,1) == '+') {
- $this->Application->Phrases->AddCachedPhrase('form_col_title'.$field_id, substr($title,1));
- $title = 'form_col_title'.$field_id;
+
+ if (substr($title, 0, 1) == '+') {
+ $this->Application->Phrases->AddCachedPhrase('form_col_title' . $field_id, substr($title, 1));
+ $title = 'form_col_title' . $field_id;
}
- $conf_grids['Default']['Fields']['fld_'.$field_id] = Array('title'=>$title, 'no_special' => 1, 'nl2br' => 1, 'first_chars' => 200, 'filter_block' => $this->_getFilterBlock($options['ElementType']));
- if ($options['Validation'] == 1)
- {
- $conf_grids['Default']['Fields']['fld_'.$field_id]['data_block'] = 'grid_email_td';
+
+ $conf_grids['Default']['Fields']['fld_' . $field_id] = Array (
+ 'title' => $title, 'no_special' => 1, 'nl2br' => 1, 'first_chars' => 200,
+ 'filter_block' => $this->_getFilterBlock($options['ElementType'])
+ );
+
+ if ($options['Validation'] == 1) {
+ $conf_grids['Default']['Fields']['fld_' . $field_id]['data_block'] = 'grid_email_td';
}
}
- if ($options['ElementType'] == 'radio' || $options['ElementType'] == 'select') {
- $conf_fields['fld_'.$field_id]['options'] = $helper->GetValuesHash( $options['ValueList'] );
- $conf_fields['fld_'.$field_id]['formatter'] = 'kOptionsFormatter';
+
+ if ($options['ElementType'] == 'checkbox' && !$options['ValueList']) {
+ // fix case, when user haven't defined any options for checkbox
+ $options['ValueList'] = '1=la_Yes||0=la_No';
}
+
+ if (in_array($options['ElementType'], $use_options) && $options['ValueList']) {
+ // field type can have options and user have defined them too
+ $field_options['options'] = $helper->GetValuesHash( $options['ValueList'] );
+ $field_options['formatter'] = 'kOptionsFormatter';
+ }
+
if ($options['ElementType'] == 'password') {
- $conf_fields['fld_'.$field_id]['formatter'] = 'kPasswordFormatter';
- $conf_fields['fld_'.$field_id]['encryption_method'] = 'plain';
- $conf_fields['fld_'.$field_id]['verify_field'] = 'fld_'.$field_id.'_verify';
+ $field_options['formatter'] = 'kPasswordFormatter';
+ $field_options['encryption_method'] = 'plain';
+ $field_options['verify_field'] = 'fld_' . $field_id . '_verify';
}
+
+ $conf_fields['fld_' . $field_id] = $field_options;
}
$this->Application->setUnitOption($event->Prefix, 'Fields', $conf_fields);
@@ -116,14 +152,26 @@
$object->addFilter('form_filter','%1$s.FormId = '.$form_id);
}
+ /**
+ * Allows user to see it's last feedback form data
+ *
+ * @param kEvent $event
+ * @return int
+ */
function getPassedID(&$event)
{
- if (!$this->Application->isAdminUser) {
- // no way to see other user's form submission by giving it's ID directly in url
- return 0;
+ if ($event->Special == 'last') {
+ // allow user to see his last submitted form
+ return $this->Application->RecallVar('last_submission_id');
}
- return parent::getPassedID($event);
+ if ($this->Application->isAdminUser) {
+ // don't check ids in admin
+ return parent::getPassedID($event);
+ }
+
+ // no way to see other user's form submission by giving it's ID directly in url
+ return 0;
}
/**
@@ -139,6 +187,12 @@
return ;
}
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ // allows user to view only it's last submission
+ $this->Application->StoreVar('last_submission_id', $object->GetID());
+
$this->Application->EmailEventAdmin('FORM.SUBMITTED');
// $this->Application->EmailEventUser('FORM.SUBMITTED', null, 'to_email' => '');
@@ -153,4 +207,62 @@
$event->redirect = $alias_template ? $alias_template : $template;
}
+
+ /**
+ * Processes Captcha code
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $object->SetDBField('IPAddress', $_SERVER['REMOTE_ADDR']);
+ $object->SetDBField('ReferrerURL', $_SERVER['HTTP_REFERER']);
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($object);
+
+ // validate captcha code
+ if ($form->GetDBField('UseSecurityImage') && !$this->Application->LoggedIn()) {
+ $captcha_helper =& $this->Application->recallObject('CaptchaHelper');
+ /* @var $captcha_helper kCaptchaHelper */
+
+ $captcha_helper->validateCode($event, false);
+ }
+ }
+
+ /**
+ * Passes form_id, when using "Prev"/"Next" toolbar buttons
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGo(&$event)
+ {
+ parent::OnPreSaveAndGo($event);
+
+ if ($event->status == erSUCCESS) {
+ $event->SetRedirectParam('pass', 'm,form,formsubs');
+ }
+ }
+
+ /**
+ * Saves edited item in temp table and goes
+ * to passed tabs, by redirecting to it with OnPreSave event
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGoToTab(&$event)
+ {
+ parent::OnPreSaveAndGoToTab($event);
+
+ if ($event->status == erSUCCESS) {
+ $event->SetRedirectParam('pass', 'm,form,formsubs');
+ }
+ }
}
\ No newline at end of file
Index: core/units/forms/forms_config.php
===================================================================
--- core/units/forms/forms_config.php (revision 13377)
+++ core/units/forms/forms_config.php (working copy)
@@ -20,6 +20,7 @@
'ListClass' => Array('class'=>'kDBList','file'=>'','build_event'=>'OnListBuild'),
'EventHandlerClass' => Array('class'=>'FormsEventHandler','file'=>'forms_eh.php','build_event'=>'OnBuild'),
'TagProcessorClass' => Array('class'=>'FormsTagProcessor','file'=>'forms_tp.php','build_event'=>'OnBuild'),
+
'AutoLoad' => true,
'QueryString' => Array(
1 => 'id',
@@ -28,6 +29,12 @@
4 => 'event',
5 => 'mode',
),
+
+ 'RegularEvents' => Array (
+ 'check_submission_repies' => Array('EventName' => 'OnProcessReplies', 'RunInterval' => 3600, 'Type' => reAFTER),
+ 'check_bounced_submission_repies' => Array('EventName' => 'OnProcessBouncedReplies', 'RunInterval' => 18000, 'Type' => reAFTER),
+ ),
+
'Hooks' => Array(
Array(
'Mode' => hAFTER,
@@ -82,6 +89,12 @@
'toolbar_buttons' => Array('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'move_up', 'move_down', 'view', 'dbl-click'),
),
+ 'form_edit_emails' => Array (
+ 'prefixes' => Array('form'),
+ 'format' => "#form_status# '#form_titlefield#' - !la_title_EmailCommunication!",
+ 'toolbar_buttons' => Array('select', 'cancel', 'prev', 'next'),
+ ),
+
'form_field_edit' => Array (
'prefixes' => Array('form', 'formflds'),
'new_status_labels' => Array('formflds'=>"!la_title_Adding_FormField!"),
@@ -100,6 +113,7 @@
'Default' => Array (
'general' => Array ('title' => 'la_tab_General', 't' => 'forms/forms_edit', 'priority' => 1),
'fields' => Array ('title' => 'la_tab_Fields', 't' => 'forms/forms_edit_fields', 'priority' => 2),
+ 'emails' => Array ('title' => 'la_tab_EmailCommunication', 't' => 'forms/form_edit_emails', 'priority' => 3),
),
),
@@ -118,10 +132,65 @@
)
),
- 'Fields' => Array(
+ 'Fields' => Array(
'FormId' => Array('type' => 'int', 'not_null' => 1, 'default' => 0, 'filter_type' => 'equals'),
'Title' => Array('type' => 'string','not_null' => 1, 'default' => '','required' => 1),
'Description' => Array('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null),
+ 'RequireLogin' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
+ 'UseSecurityImage' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
+ 'EnableEmailCommunication' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
+ 'ReplyFromName' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyFromEmail' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyCc' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyBcc' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'ReplyMessageSignature' => Array ('type' => 'string', 'default' => NULL),
+ 'ReplyServer' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'connection_failed' => '!la_error_ConnectionFailed!',
+ 'message_listing_failed' => '!la_error_MessageListingFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'ReplyPort' => Array ('type' => 'int', 'not_null' => 1, 'default' => 110),
+ 'ReplyUsername' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'login_failed' => '!la_error_LoginFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'ReplyPassword' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'BounceEmail' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'BounceServer' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'connection_failed' => '!la_error_ConnectionFailed!',
+ 'message_listing_failed' => '!la_error_MessageListingFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'BouncePort' => Array ('type' => 'int', 'not_null' => 1, 'default' => 110),
+ 'BounceUsername' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array (
+ 'login_failed' => '!la_error_LoginFailed!',
+ ),
+ 'not_null' => 1, 'default' => ''
+ ),
+ 'BouncePassword' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
),
'Grids' => Array(
'Default' => Array(
@@ -133,8 +202,11 @@
),
'Fields' => Array(
'FormId' => Array( 'title'=>'la_col_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
- 'Title' => Array( 'title' => 'la_col_Title', 'filter_block' => 'grid_like_filter', 'width' => 250, ),
+ 'Title' => Array( 'title' => 'la_col_Title', 'filter_block' => 'grid_like_filter', 'width' => 220, ),
'Description' => Array( 'title' => 'la_col_Description', 'filter_block' => 'grid_like_filter', 'width' => 300, ),
+ 'RequireLogin' => Array ('title' => 'la_col_RequireLogin', 'filter_block' => 'grid_options_filter', 'width' => 80,),
+ 'UseSecurityImage' => Array ('title' => 'la_col_UseSecurityImage', 'filter_block' => 'grid_options_filter', 'width' => 110,),
+ 'EnableEmailCommunication' => Array ('title' => 'la_col_EnableEmailCommunication', 'filter_block' => 'grid_options_filter', 'width' => 120,),
),
),
),
Index: core/units/forms/forms_eh.php
===================================================================
--- core/units/forms/forms_eh.php (revision 13377)
+++ core/units/forms/forms_eh.php (working copy)
@@ -96,55 +96,43 @@
}
/**
- * Dynamically fills customdata config
- *
- * @param kEvent $event
- */
- function OnCreateFormFields(&$event)
- {
- $cur_fields = $this->Conn->Query('DESCRIBE '.TABLE_PREFIX.'FormSubmissions', 'Field');
- $cur_fields = array_keys($cur_fields);
+ * Dynamically fills customdata config
+ *
+ * @param kEvent $event
+ */
+ function OnCreateFormFields(&$event)
+ {
+ $cur_fields = $this->Conn->Query('DESCRIBE '.TABLE_PREFIX.'FormSubmissions', 'Field');
+ $cur_fields = array_keys($cur_fields);
- // keep all fields, that are not created on the fly (includes ones, that are added during customizations)
- foreach ($cur_fields as $field_index => $field_name) {
- if (!preg_match('/^fld_[\d]+/', $field_name)) {
- unset($cur_fields[$field_index]);
- }
+ // keep all fields, that are not created on the fly (includes ones, that are added during customizations)
+ foreach ($cur_fields as $field_index => $field_name) {
+ if (!preg_match('/^fld_[\d]+/', $field_name)) {
+ unset($cur_fields[$field_index]);
}
+ }
- $desired_fields = $this->Conn->GetCol('SELECT CONCAT(\'fld_\', FormFieldId) FROM '.TABLE_PREFIX.'FormFields ORDER BY FormFieldId');
+ $desired_fields = $this->Conn->GetCol('SELECT CONCAT(\'fld_\', FormFieldId) FROM '.TABLE_PREFIX.'FormFields ORDER BY FormFieldId');
- $sql = array();
+ $sql = array();
- $fields_to_add = array_diff($desired_fields, $cur_fields);
- foreach ($fields_to_add as $field) {
- $field_expression = $field.' Text NULL';
- $sql[] = 'ADD COLUMN '.$field_expression;
- }
+ $fields_to_add = array_diff($desired_fields, $cur_fields);
+ foreach ($fields_to_add as $field) {
+ $field_expression = $field.' Text NULL';
+ $sql[] = 'ADD COLUMN '.$field_expression;
+ }
- $fields_to_drop = array_diff($cur_fields, $desired_fields);
- foreach ($fields_to_drop as $field) {
- $sql[] = 'DROP COLUMN '.$field;
- }
+ $fields_to_drop = array_diff($cur_fields, $desired_fields);
+ foreach ($fields_to_drop as $field) {
+ $sql[] = 'DROP COLUMN '.$field;
+ }
- if ($sql) {
- $query = 'ALTER TABLE '.TABLE_PREFIX.'FormSubmissions '.implode(', ', $sql);
- $this->Conn->Query($query);
- }
+ if ($sql) {
+ $query = 'ALTER TABLE '.TABLE_PREFIX.'FormSubmissions '.implode(', ', $sql);
+ $this->Conn->Query($query);
}
-
- /*function GetPassedId($event)
- {
- return 0;
}
- function LoadItem(&$event)
- {
- $object =& $event->getObject();
- $object->SetField('Id',0);
- $object->SetId(0);
- }
-*/
/**
* Enter description here...
*
@@ -210,4 +198,310 @@
$event->status = erFAIL;
}
}
+
+ /**
+ * Don't use security image, when form requires login
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $this->_validatePopSettings($event);
+ $this->_disableSecurityImage($event);
+ $this->_setRequired($event);
+ }
+
+ /**
+ * Don't use security image, when form requires login
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+ parent::OnBeforeItemUpdate($event);
+
+ $this->_validatePopSettings($event);
+ $this->_disableSecurityImage($event);
+ $this->_setRequired($event);
+ }
+
+ /**
+ * Validates POP3 settings (performs test connect)
+ *
+ * @param kEvent $event
+ */
+ function _validatePopSettings(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $modes = Array ('Reply', 'Bounce');
+ $fields = Array ('Server', 'Port', 'Username', 'Password');
+ $changed_fields = array_keys( $object->GetChangedFields() );
+
+ foreach ($modes as $mode) {
+ $set = true;
+ $changed = false;
+
+ foreach ($fields as $field) {
+ $value = $object->GetDBField($mode . $field);
+
+ if (strlen( trim($value) ) == 0) {
+ $set = false;
+ break;
+ }
+
+ if (!$changed && in_array($mode . $field, $changed_fields)) {
+ $changed = true;
+ }
+ }
+
+ if ($set && $changed) {
+ // fields are set and at least on of them is changed
+ $connection_info = Array ();
+
+ foreach ($fields as $field) {
+ $connection_info[ strtolower($field) ] = $object->GetDBField($mode . $field);
+ }
+
+ $pop3_helper =& $this->Application->makeClass('POP3Helper', $connection_info, 10);
+ /* @var $pop3_helper POP3Helper */
+
+ switch ( $pop3_helper->initMailbox(true) ) {
+ case 'socket':
+ $object->SetError($mode . 'Server', 'connection_failed');
+ break;
+
+ case 'login':
+ $object->SetError($mode . 'Username', 'login_failed');
+ break;
+
+ case 'list':
+ $object->SetError($mode . 'Server', 'message_listing_failed');
+ break;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Makes email communication fields required, when form uses email communication
+ *
+ * @param kEvent $event
+ */
+ function _setRequired(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $required = $object->GetDBField('EnableEmailCommunication');
+ $fields = Array (
+ 'ReplyFromName', 'ReplyFromEmail', 'ReplyServer', 'ReplyPort', 'ReplyUsername', 'ReplyPassword',
+ );
+
+ if ($required && $object->GetDBField('BounceEmail')) {
+ $bounce_fields = Array ('BounceEmail', 'BounceServer', 'BouncePort', 'BounceUsername', 'BouncePassword');
+ $fields = array_merge($fields, $bounce_fields);
+ }
+
+ foreach ($fields as $field) {
+ $object->setRequired($field, $required);
+ }
+ }
+
+ /**
+ * Don't use security image, when form requires login
+ *
+ * @param kEvent $event
+ */
+ function _disableSecurityImage(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ if ($object->GetDBField('RequireLogin')) {
+ $object->SetDBField('UseSecurityImage', 0);
+ }
+ }
+
+ /**
+ * Queries pop3 server about new incoming mail
+ *
+ * @param kEvent $event
+ */
+ function OnProcessReplies(&$event)
+ {
+ $this->_processMailbox($event, false);
+ }
+
+ /**
+ * Queries pop3 server about new incoming mail
+ *
+ * @param kEvent $event
+ */
+ function OnProcessBouncedReplies(&$event)
+ {
+ $this->_processMailbox($event, true);
+ }
+
+ /**
+ * Queries pop3 server about new incoming mail
+ *
+ * @param kEvent $event
+ */
+ function _processMailbox(&$event, $bounce_mode = false)
+ {
+ $this->Application->SetVar('client_mode', 1);
+
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
+ $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
+
+ $sql = 'SELECT *
+ FROM ' . $table_name . '
+ WHERE EnableEmailCommunication = 1';
+ $forms = $this->Conn->Query($sql, $id_field);
+
+ $mailbox_helper =& $this->Application->recallObject('MailboxHelper');
+ /* @var $mailbox_helper MailboxHelper */
+
+ $field_prefix = $bounce_mode ? 'Bounce' : 'Reply';
+
+ foreach ($forms as $form_id => $form_info) {
+ $recipient_email = $bounce_mode ? $form_info['BounceEmail'] : $form_info['ReplyFromEmail'];
+
+ if (!$recipient_email) {
+ continue;
+ }
+
+ $mailbox_helper->process(
+ Array (
+ 'server' => $form_info[$field_prefix . 'Server'],
+ 'port' => $form_info[$field_prefix . 'Port'],
+ 'username' => $form_info[$field_prefix . 'Username'],
+ 'password' => $form_info[$field_prefix . 'Password']
+ ),
+ Array (&$this, 'isValidRecipient'),
+ Array (&$this, 'processEmail'),
+ Array (
+ 'recipient_email' => $recipient_email,
+ 'bounce_mode' => $bounce_mode,
+ )
+ );
+ }
+ }
+
+ function isValidRecipient($params)
+ {
+ $mailbox_helper =& $this->Application->recallObject('MailboxHelper');
+ /* @var $mailbox_helper MailboxHelper */
+
+ $recipients = $mailbox_helper->getRecipients();
+ $recipient_email = $params['recipient_email'];
+
+ $emails_found = preg_match_all('/((' . REGEX_EMAIL_USER . ')(@' . REGEX_EMAIL_DOMAIN . '))/i', $recipients, $all_emails);
+
+ if (is_array($all_emails)) {
+ for ($i = 0; $i < $emails_found; $i++) {
+ if ($all_emails[1][$i] == $recipient_email) {
+ // only read messages, that are addresses to submission reply email
+ return true;
+ }
+ }
+ }
+
+ // If this is a forwarded message - we drop all the other aliases and deliver only to the x-forward to address;
+ if (preg_match('/((' . REGEX_EMAIL_USER . ')(@' . REGEX_EMAIL_DOMAIN . '))/i', $mailbox_helper->headers['x-forward-to'], $get_to_email)) {
+ if ($get_to_email[1] == $recipient_email) {
+ // only read messages, that are addresses to submission reply email
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function processEmail($params, &$fields_hash)
+ {
+ if ($params['bounce_mode']) {
+ // mark original message as bounced
+
+ $mailbox_helper =& $this->Application->recallObject('MailboxHelper');
+ /* @var $mailbox_helper MailboxHelper */
+
+ if (!array_key_exists('attachments', $mailbox_helper->parsedMessage)) {
+ // for now only parse bounces based on attachments, skip other bounce types
+ return false;
+ }
+
+ for ($i = 0; $i < count($mailbox_helper->parsedMessage['attachments']); $i++) {
+ $attachment =& $mailbox_helper->parsedMessage['attachments'][$i];
+
+ switch ($attachment['headers']['content-type']) {
+ case 'message/delivery-status':
+ // save as BounceInfo
+ $mime_decode_helper =& $this->Application->recallObject('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ $charset = $mailbox_helper->parsedMessage[ $fields_hash['MessageType'] ][0]['charset'];
+ $fields_hash['Message'] = $mime_decode_helper->convertEncoding($charset, $attachment['data']);
+ break;
+
+ case 'message/rfc822':
+ // undelivered message
+ $fields_hash['Subject'] = $attachment['filename2'] ? $attachment['filename2'] : $attachment['filename'];
+ break;
+ }
+ }
+ }
+
+ if (!preg_match('/^(.*) #verify(.*)$/', $fields_hash['Subject'], $regs)) {
+ // incorrect subject, no verification code
+ return false;
+ }
+
+ $sql = 'SELECT ' . $this->Application->getUnitOption('submission-log', 'IDField') . '
+ FROM ' . $this->Application->getUnitOption('submission-log', 'TableName') . '
+ WHERE MessageId = ' . $this->Conn->qstr($fields_hash['MessageId']);
+ $found = $this->Conn->GetOne($sql);
+
+ if ($found) {
+ // don't process same message twice
+ return false;
+ }
+
+ $reply_to =& $this->Application->recallObject('submission-log.-reply-to', null, Array ('skip_autoload' => true));
+ /* @var $reply_to kDBItem */
+
+ $reply_to->Load($regs[2], 'VerifyCode');
+ if (!$reply_to->isLoaded()) {
+ // fake verification code OR feedback, containing submission log was deleted
+ return false;
+ }
+
+ if ($params['bounce_mode']) {
+ // mark original message as bounced
+ $reply_to->SetDBField('BounceInfo', $fields_hash['Message']);
+ $reply_to->SetDBField('BounceDate_date', TIMENOW);
+ $reply_to->SetDBField('BounceDate_time', TIMENOW);
+ $reply_to->SetDBField('SentStatus', SUBMISSION_LOG_BOUNCE);
+ $reply_to->Update();
+
+ return true;
+ }
+
+ $reply =& $this->Application->recallObject('submission-log.-reply', null, Array ('skip_autoload' => true));
+ /* @var $reply kDBItem */
+
+ $reply->SetDBFieldsFromHash($fields_hash);
+ $reply->SetDBField('ReplyTo', $reply_to->GetID());
+ $reply->SetDBField('FormSubmissionId', $reply_to->GetDBField('FormSubmissionId'));
+ $reply->SetDBField('ToEmail', $params['recipient_email']);
+ $reply->SetDBField('Subject', $regs[1]); // save subject without verification code
+ $reply->SetDBField('SentStatus', SUBMISSION_LOG_SENT);
+
+ return $reply->Create();
+ }
}
\ No newline at end of file
Index: core/units/helpers/form_submission_helper.php
===================================================================
--- core/units/helpers/form_submission_helper.php (revision 0)
+++ core/units/helpers/form_submission_helper.php (revision 0)
@@ -0,0 +1,105 @@
+<?php
+
+ class FormSubmissionHelper extends kHelper {
+
+ /**
+ * Role names for easy usage via FormField tag
+ *
+ * @var Array
+ */
+ var $roleNames = Array (
+ 'name' => EMAIL_COMMUNICATION_ROLE_NAME,
+ 'email' => EMAIL_COMMUNICATION_ROLE_EMAIL,
+ 'subject' => EMAIL_COMMUNICATION_ROLE_SUBJECT,
+ 'body' => EMAIL_COMMUNICATION_ROLE_BODY,
+ );
+
+ /**
+ * Returns submission field based on given role
+ *
+ * @param kDBItem $form_submission
+ * @param string $role
+ * @return string
+ */
+ function getFieldByRole(&$form_submission, $role, $formatted = false, $format = null)
+ {
+ static $cache = Array ();
+
+ $form_id = $form_submission->GetDBField('FormId');
+
+ if (!array_key_exists($form_id, $cache)) {
+ $id_field = $this->Application->getUnitOption('formflds', 'IDField');
+ $table_name = $this->Application->getUnitOption('formflds', 'TableName');
+
+ $sql = 'SELECT ' . $id_field . ', EmailCommunicationRole
+ FROM ' . $table_name . '
+ WHERE FormId = ' . $form_id . ' AND EmailCommunicationRole <> 0';
+ $cache[$form_id] = $this->Conn->GetCol($sql, 'EmailCommunicationRole');
+ }
+
+ // convert string representation of role to numeric
+ if (!is_numeric($role)) {
+ $role = strtolower($role);
+ $role = array_key_exists($role, $this->roleNames) ? $this->roleNames[$role] : false;
+ }
+
+ // get field by role
+ $field_id = array_key_exists($role, $cache[$form_id]) ? $cache[$form_id][$role] : false;
+
+ if ($field_id) {
+ return $formatted ? $form_submission->GetField('fld_' . $field_id, $format) : $form_submission->GetDBField('fld_' . $field_id);
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns submission field based on given name
+ *
+ * @param kDBItem $form_submission
+ * @param string $name
+ * @return string
+ */
+ function getFieldByName(&$form_submission, $name, $formatted = false, $format = null)
+ {
+ static $cache = Array ();
+
+ $form_id = $form_submission->GetDBField('FormId');
+
+ if (!array_key_exists($form_id, $cache)) {
+ $id_field = $this->Application->getUnitOption('formflds', 'IDField');
+ $table_name = $this->Application->getUnitOption('formflds', 'TableName');
+
+ $sql = 'SELECT ' . $id_field . ', FieldName
+ FROM ' . $table_name . '
+ WHERE FormId = ' . $form_id;
+ $cache[$form_id] = $this->Conn->GetCol($sql, 'FieldName');
+ }
+
+ if ($field_id) {
+ return $formatted ? $form_submission->GetField('fld_' . $field_id, $format) : $form_submission->GetDBField('fld_' . $field_id);
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns form object field based on form submission
+ *
+ * @param $form_submission kDBItem
+ * @return kDBItem
+ */
+ function &getForm(&$form_submission)
+ {
+ $form_id = $form_submission->GetDBField('FormId');
+
+ $form =& $this->Application->recallObject('form', null, Array ('skip_autoload' => true));
+ /* @var $form kDBItem */
+
+ if (!$form->isLoaded() || ($form->GetID() != $form_id)) {
+ $form->Load($form_id);
+ }
+
+ return $form;
+ }
+ }
\ No newline at end of file
Index: core/units/helpers/helpers_config.php
===================================================================
--- core/units/helpers/helpers_config.php (revision 13377)
+++ core/units/helpers/helpers_config.php (working copy)
@@ -49,15 +49,20 @@
Array ('pseudo' => 'JSONHelper', 'class' => 'JSONHelper', 'file' => 'json_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
Array ('pseudo' => 'LanguageImportHelper', 'class' => 'LanguageImportHelper', 'file' => 'language_import_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
Array ('pseudo' => 'SkinHelper', 'class' => 'SkinHelper', 'file' => 'skin_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'SiteConfigHelper', 'pseudo' => 'SiteConfigHelper', 'file' => 'site_config_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'MenuHelper', 'pseudo' => 'MenuHelper', 'file' => 'menu_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'SiteConfigHelper', 'class' => 'SiteConfigHelper', 'file' => 'site_config_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'MenuHelper', 'class' => 'MenuHelper', 'file' => 'menu_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'InpCustomFieldsHelper', 'pseudo' => 'InpCustomFieldsHelper', 'file' => 'custom_fields_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kCountryStatesHelper', 'pseudo' => 'CountryStatesHelper', 'file' => 'country_states_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kBracketsHelper', 'pseudo' => 'BracketsHelper', 'file' => 'brackets_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kXMLHelper', 'pseudo' => 'kXMLHelper', 'file' => 'xml_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'kCatDBItemExportHelper', 'pseudo' => 'CatItemExportHelper', 'file' => 'cat_dbitem_export_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'EmailMessageHelper', 'pseudo' => 'EmailMessageHelper', 'file' => 'email_message_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('class' => 'ListHelper', 'pseudo' => 'ListHelper', 'file' => 'list_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'InpCustomFieldsHelper', 'class' => 'InpCustomFieldsHelper', 'file' => 'custom_fields_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'CountryStatesHelper', 'class' => 'kCountryStatesHelper', 'file' => 'country_states_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'BracketsHelper', 'class' => 'kBracketsHelper', 'file' => 'brackets_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'kXMLHelper', 'class' => 'kXMLHelper', 'file' => 'xml_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'CatItemExportHelper', 'class' => 'kCatDBItemExportHelper', 'file' => 'cat_dbitem_export_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'EmailMessageHelper', 'class' => 'EmailMessageHelper', 'file' => 'email_message_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'ListHelper', 'class' => 'ListHelper', 'file' => 'list_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+
+ Array ('pseudo' => 'FormSubmissionHelper', 'class' => 'FormSubmissionHelper', 'file' => 'form_submission_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'MailboxHelper', 'class' => 'MailboxHelper', 'file' => 'mailbox_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'POP3Helper', 'class' => 'POP3Helper', 'file' => 'pop3_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'MimeDecodeHelper', 'class' => 'MimeDecodeHelper', 'file' => 'mime_decode_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
),
);
\ No newline at end of file
Index: core/units/helpers/mailbox_helper.php
===================================================================
--- core/units/helpers/mailbox_helper.php (revision 0)
+++ core/units/helpers/mailbox_helper.php (revision 0)
@@ -0,0 +1,480 @@
+<?php
+
+
+ class MailboxHelper extends kHelper {
+
+ var $headers = Array ();
+
+ var $parsedMessage = Array ();
+
+ /**
+ * Maximal megabytes of data to process
+ *
+ * @var int
+ */
+ var $maxMegabytes = 2;
+
+ /**
+ * Maximal message count to process
+ *
+ * @var int
+ */
+ var $maxMessages = 50;
+
+ /**
+ * Reads mailbox and gives messages to processing callback
+ *
+ * @param Array $connection_info
+ * @param Array $verify_callback
+ * @param Array $process_callback
+ * @param Array $callback_params
+ * @param bool $include_attachment_contents
+ * @return string
+ */
+ function process($connection_info, $verify_callback, $process_callback, $callback_params = Array (), $include_attachment_contents = true)
+ {
+ $pop3_helper =& $this->Application->makeClass('POP3Helper', $connection_info);
+ /* @var $pop3_helper POP3Helper */
+
+ $connection_status = $pop3_helper->initMailbox();
+
+ if (is_string($connection_status)) {
+ return $connection_status;
+ }
+
+ if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
+ $this->Application->Debugger->appendHTML('Reading MAILBOX: ' . $connection_info['username']);
+ }
+
+ // Figure out if all messages are huge
+ $only_big_messages = true;
+ $max_message_size = $this->maxMegabytes * (1024 * 1024);
+
+ foreach ($pop3_helper->messageSizes as $message_size) {
+ if (($message_size <= $max_message_size) && ($max_message_size > 0)) {
+ $only_big_messages = false;
+ break;
+ }
+ }
+
+ $count = $total_size = 0;
+
+ foreach ($pop3_helper->messageSizes as $message_number => $message_size) {
+ // Too many messages?
+ if (($count++ > $this->maxMessages) && ($this->maxMessages > 0)) {
+ break;
+ }
+
+ // Message too big?
+ if (!$only_big_messages && ($message_size > $max_message_size) && ($max_message_size > 0)) {
+ $this->_displayLogMessage('message <strong>#' . $message_number . '</strong> too big, skipped');
+ continue;
+ }
+
+ // Processed enough for today?
+ if (($total_size > $max_message_size) && ($max_message_size > 0)) {
+ break;
+ }
+
+ $total_size += $message_size;
+ $pop3_helper->getEmail($message_number, $message_source);
+
+ $processed = $this->normalize($message_source, $verify_callback, $process_callback, $callback_params, $include_attachment_contents);
+
+ if ($processed) {
+ // delete message from server immediatly after retrieving & processing
+ $pop3_helper->deleteEmail($message_number);
+ $this->_displayLogMessage('message <strong>#' . $message_number . '</strong>: processed');
+ }
+ else {
+ $this->_displayLogMessage('message <strong>#' . $message_number . '</strong>: skipped');
+ }
+ }
+
+ $pop3_helper->close();
+
+ return 'success';
+ }
+
+ /**
+ * Displays log message
+ *
+ * @param string $text
+ */
+ function _displayLogMessage($text)
+ {
+ if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
+ $this->Application->Debugger->appendHTML($text);
+ }
+ }
+
+ /**
+ * Takes an RFC822 formatted date, returns a unix timestamp (allowing for zone)
+ *
+ * @param string $rfcdate
+ * @return int
+ */
+ function rfcToTime($rfcdate)
+ {
+ $date = strtotime($rfcdate);
+
+ if ($date == -1) {
+ return false;
+ }
+
+ return $date;
+ }
+
+ /**
+ * Gets recipients from all possible headers
+ *
+ * @return string
+ */
+ function getRecipients()
+ {
+ $ret = '';
+
+ // headers that could contain recipients
+ $recipient_headers = Array (
+ 'to', 'cc', 'envelope-to', 'resent-to', 'delivered-to',
+ 'apparently-to', 'envelope-to', 'x-envelope-to', 'received',
+ );
+
+ foreach ($recipient_headers as $recipient_header) {
+ if (!array_key_exists($recipient_header, $this->headers)) {
+ continue;
+ }
+
+ if (!is_array($this->headers["$recipient_header"])) {
+ $ret .= ' ' . $this->headers["$recipient_header"];
+ } else {
+ $ret .= ' ' . implode(' ', $this->headers["$recipient_header"]);
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * "Flattens" the multi-demensinal headers array into a single dimension one
+ *
+ * @param Array $input
+ * @param string $add
+ * @return Array
+ */
+ function flattenHeadersArray($input, $add = '')
+ {
+ $output = Array ();
+
+ foreach ($input as $key => $value) {
+ if (!empty($add)) {
+ $newkey = ucfirst( strtolower($add) );
+ } elseif (is_numeric($key)) {
+ $newkey = '';
+ } else {
+ $newkey = ucfirst( strtolower($key) );
+ }
+
+ if (is_array($value)) {
+ $output = array_merge($output, $this->flattenHeadersArray($value, $newkey));
+ } else {
+ $output[] = (!empty($newkey) ? $newkey . ': ' : '') . $value;
+ }
+ }
+
+ return $output;
+ }
+
+ /**
+ * Processes given message using given callbacks
+ *
+ * @param string $message
+ * @param Array $verify_callback
+ * @param Array $process_callback
+ * @param bool $include_attachment_contents
+ * @return bool
+ */
+ function normalize($message, $verify_callback, $process_callback, $callback_params, $include_attachment_contents = true)
+ {
+ // Decode message
+ $this->decodeMime($message, $include_attachment_contents);
+
+ // Init vars; $good will hold all the correct infomation from now on
+ $good = Array ();
+
+ // trim() some stuff now instead of later
+ $this->headers['from'] = trim($this->headers['from']);
+ $this->headers['to'] = trim($this->headers['to']);
+ $this->headers['cc'] = array_key_exists('cc', $this->headers) ? trim($this->headers['cc']) : '';
+ $this->headers['x-forward-to'] = array_key_exists('x-forward-to', $this->headers) ? $this->headers['x-forward-to'] : '';
+ $this->headers['subject'] = trim($this->headers['subject']);
+ $this->headers['received'] = is_array($this->headers['received']) ? $this->headers['received'] : Array ($this->headers['received']);
+
+ if (array_key_exists('return-path', $this->headers) && is_array($this->headers['return-path'])) {
+ $this->headers['return-path'] = implode(' ', $this->flattenHeadersArray($this->headers['return-path']));
+ }
+
+ // Create our own message-ID if it's missing
+ $message_id = array_key_exists('message-id', $this->headers) ? trim($this->headers['message-id']) : '';
+ $good['emailid'] = $message_id ? $message_id : md5($message) . "@in-portal";
+
+ // Stops us looping in stupid conversations with other mail software
+ if (isset($this->headers['x-loop-detect']) && $this->headers['x-loop-detect'] > 2) {
+ return false;
+ }
+
+ $esender =& $this->Application->recallObject('EmailSender');
+ /* @var $esender kEmailSendingHelper */
+
+ // Get the return address
+ $return_path = '';
+
+ if (array_key_exists('return-path', $this->headers)) {
+ $return_path = $esender->ExtractRecipientEmail($this->headers['return-path']);
+ }
+
+ if (!$return_path) {
+ if (array_key_exists('reply-to', $this->headers)) {
+ $return_path = $esender->ExtractRecipientEmail( $this->headers['reply-to'] );
+ }
+ else {
+ $return_path = $esender->ExtractRecipientEmail( $this->headers['from'] );
+ }
+ }
+
+ // Get the sender's name & email
+ $good['fromemail'] = $esender->ExtractRecipientEmail($this->headers['from']);
+ $good['fromname'] = $esender->ExtractRecipientName($this->headers['from'], $good['fromemail']);
+
+ // Get the list of recipients
+ if (!$verify_callback[0]->$verify_callback[1]($callback_params)) {
+ // error: mail is propably spam
+ return false;
+ }
+
+ // Handle the subject
+ $good['subject'] = $this->headers['subject'];
+
+ // Priorities rock
+ $good['priority'] = array_key_exists('x-priority', $this->headers) ? (int)$this->headers['x-priority'] : 0;
+
+ switch ($good['priority']) {
+ case 1: case 5: break;
+ default:
+ $good['priority'] = 3;
+ }
+
+ // If we have attachments it's about time we tell the user about it
+ if (array_key_exists('attachments', $this->parsedMessage) && is_array($this->parsedMessage['attachments'])) {
+ $good['attach'] = count( $this->parsedMessage['attachments'] );
+ } else {
+ $good['attach'] = 0;
+ }
+
+ // prepare message text (for replies, etc)
+ if (isset($this->parsedMessage['text'][0]) && trim($this->parsedMessage['text'][0]['body']) != '') {
+ $message_body = trim($this->parsedMessage['text'][0]['body']);
+ $message_type = 'text';
+ } elseif (isset($this->parsedMessage['html']) && trim($this->parsedMessage['html'][0]['body']) != '') {
+ $message_body = trim($this->parsedMessage['html'][0]['body']);
+ $message_type = 'html';
+ } else {
+ $message_body = '[no message]';
+ $message_type = 'text';
+ }
+
+ // remove scripts
+ $message_body = preg_replace("/<script[^>]*>[^<]+<\/script[^>]*>/is", '', $message_body);
+ $message_body = preg_replace("/<iframe[^>]*>[^<]*<\/iframe[^>]*>/is", '', $message_body);
+
+ if ($message_type == 'html') {
+ $message_body = $esender->ConvertToText($message_body);
+ }
+
+ $mime_decode_helper =& $this->Application->recallObject('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ // convert to site encoding
+ $message_charset = $this->parsedMessage[$message_type][0]['charset'];
+
+ if ($message_charset) {
+ $good['message'] = $mime_decode_helper->convertEncoding($message_charset, $message_body);
+ }
+
+ if (array_key_exists('delivery-date', $this->headers)) {
+ // We found the Delivery-Date header (and it's not too far in the future)
+ $dateline = $this->rfcToTime($this->headers['delivery-date']);
+
+ if ($dateline > TIMENOW + 86400) {
+ unset($dateline);
+ }
+ }
+
+ // We found the latest date from the received headers
+ $received_timestamp = $this->headers['received'][0];
+ $dateline = $this->rfcToTime(trim( substr($received_timestamp, strrpos($received_timestamp, ';') + 1) ));
+
+ if ($dateline == $this->rfcToTime(0)) {
+ unset($dateline);
+ }
+
+ if (!isset($dateline)) {
+ $dateline = TIMENOW;
+ }
+
+ // save collected data to database
+ $fields_hash = Array (
+ 'DeliveryDate' => $dateline, // date, when SMTP server received the message
+ 'ReceivedDate' => TIMENOW, // date, when message was retrieved from POP3 server
+ 'CreatedOn' => $this->rfcToTime($this->headers['date']), // date, when created on sender's computer
+ 'ReturnPath' => $return_path,
+ 'FromEmail' => $good['fromemail'],
+ 'FromName' => $good['fromname'],
+ 'To' => $this->headers['to'],
+ 'Subject' => $good['subject'],
+ 'Message' => $good['message'],
+ 'MessageType' => $message_type,
+ 'AttachmentCount' => $good['attach'],
+ 'MessageId' => $good['emailid'],
+ 'Source' => $message,
+ 'Priority' => $good['priority'],
+ 'Size' => strlen($message),
+ );
+
+ return $process_callback[0]->$process_callback[1]($callback_params, $fields_hash);
+ }
+
+ /**
+ * Function that decodes the MIME message and creates the $this->headers and $this->parsedMessage data arrays
+ *
+ * @param string $message
+ * @param bool $include_attachments
+ *
+ */
+ function decodeMime($message, $include_attachments = true)
+ {
+ $message = preg_replace("/\r?\n/", "\r\n", trim($message));
+
+ $mime_decode_helper =& $this->Application->recallObject('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ // 1. separate headers from bodies
+ $mime_decode_helper->InitHelper($message);
+ $decoded_message = $mime_decode_helper->decode(true, true, true);
+
+ // 2. extract attachments
+ $this->parsedMessage = Array (); // ! reset value
+ $this->parseOutput($decoded_message, $this->parsedMessage, $include_attachments);
+
+ // 3. add "other" attachments (text part, that is not maked as attachment)
+ if (array_key_exists('text', $this->parsedMessage) && count($this->parsedMessage['text']) > 1) {
+ for ($attach = 1; $attach < count($this->parsedMessage['text']); $attach++) {
+ $this->parsedMessage['attachments'][] = Array (
+ 'data' => $this->parsedMessage['text']["$attach"]['body'],
+ );
+ }
+ }
+
+ $this->headers = $this->parsedMessage['headers']; // ! reset value
+
+ if (empty($decoded_message->ctype_parameters['boundary'])) {
+ // when no boundary, then assume all message is it's text
+ $this->parsedMessage['text'][0]['body'] = $decoded_message->body;
+ }
+ }
+
+ /**
+ * Returns content-id's from inline attachments in message
+ *
+ * @return Array
+ */
+ function getContentIds()
+ {
+ $cids = Array();
+
+ if (array_key_exists('attachments', $this->parsedMessage) && is_array($this->parsedMessage['attachments'])) {
+ foreach ($this->parsedMessage['attachments'] as $attachnum => $attachment) {
+ if (!isset($attachment['headers']['content-id'])) {
+ continue;
+ }
+
+ $cid = $attachment['headers']['content-id'];
+
+ if (substr($cid, 0, 1) == '<' && substr($cid, -1) == '>') {
+ $cid = substr($cid, 1, -1);
+ }
+
+ $cids["$attachnum"] = $cid;
+ }
+ }
+
+ return $cids;
+ }
+
+ /**
+ * Get more detailed information about attachments
+ *
+ * @param stdClass $decoded parsed headers & body as object
+ * @param Array $parts parsed parts
+ * @param bool $include_attachments
+ */
+ function parseOutput(&$decoded, &$parts, $include_attachments = true)
+ {
+ $ctype = strtolower($decoded->ctype_primary . '/' . $decoded->ctype_secondary);
+
+ // don't parse attached messages recursevely
+ if (!empty($decoded->parts) && $ctype != 'message/rfc822') {
+ for ($i = 0; $i < count($decoded->parts); $i++) {
+ $this->parseOutput($decoded->parts["$i"], $parts, $include_attachments);
+ }
+ } else/*if (!empty($decoded->disposition) && $decoded->disposition != 'inline' or 1)*/ {
+ switch ($ctype) {
+ case 'text/plain':
+ case 'text/html':
+ if (!empty($decoded->disposition) && ($decoded->disposition == 'attachment')) {
+ $parts['attachments'][] = Array (
+ 'data' => $include_attachments ? $decoded->body : '',
+ 'filename' => array_key_exists('filename', $decoded->d_parameters) ? $decoded->d_parameters['filename'] : '', // from content-disposition
+ 'filename2' => $decoded->ctype_parameters['name'], // from content-type
+ 'type' => $decoded->ctype_primary, // "text"
+ 'encoding' => $decoded->headers['content-transfer-encoding']
+ );
+ } else {
+ $body_type = $decoded->ctype_secondary == 'plain' ? 'text' : 'html';
+ $parts[$body_type][] = Array (
+ 'content-type' => $ctype,
+ 'charset' => array_key_exists('charset', $decoded->ctype_parameters) ? $decoded->ctype_parameters['charset'] : 'ISO-8859-1',
+ 'body' => $decoded->body
+ );
+ }
+ break;
+
+ case 'message/rfc822':
+ // another e-mail as attachment
+ $parts['attachments'][] = Array (
+ 'data' => $include_attachments ? $decoded->body : '',
+ 'filename' => array_key_exists('filename', $decoded->d_parameters) ? $decoded->d_parameters['filename'] : '',
+ 'filename2' => array_key_exists('name', $decoded->ctype_parameters) ? $decoded->ctype_parameters['name'] : $decoded->parts[0]->headers['subject'],
+ 'type' => $decoded->ctype_primary, // "message"
+ 'headers' => $decoded->headers // individual copy of headers with each attachment
+ );
+ break;
+
+ default:
+ if (!stristr($decoded->headers['content-type'], 'signature')) {
+ $parts['attachments'][] = Array (
+ 'data' => $include_attachments ? $decoded->body : '',
+ 'filename' => array_key_exists('filename', $decoded->d_parameters) ? $decoded->d_parameters['filename'] : '', // from content-disposition
+ 'filename2' => $decoded->ctype_parameters['name'], // from content-type
+ 'type' => $decoded->ctype_primary,
+ 'headers' => $decoded->headers // individual copy of headers with each attachment
+ );
+ }
+
+ }
+ }
+
+ $parts['headers'] = $decoded->headers; // headers of next parts overwrite previous part headers
+ }
+
+ }
\ No newline at end of file
Index: core/units/helpers/mime_decode_helper.php
===================================================================
--- core/units/helpers/mime_decode_helper.php (revision 0)
+++ core/units/helpers/mime_decode_helper.php (revision 0)
@@ -0,0 +1,482 @@
+<?php
+
+ /**
+ * The MIME decoding class
+ *
+ */
+ class MimeDecodeHelper extends kHelper {
+
+ /**
+ * Contains headers part of email message
+ *
+ * @var string
+ */
+ var $_headerPart;
+
+ /**
+ * Contains body part of email message
+ *
+ * @var string
+ */
+ var $_bodyPart;
+
+ /**
+ * Last parsing error message (if any)
+ *
+ * @var string
+ */
+ var $_lastErrorMessage = '';
+
+ /**
+ * Decode message headers
+ *
+ * @var bool
+ */
+ var $_decodeHeaders = false;
+
+ /**
+ * Include email body in decoded result
+ *
+ * @var bool
+ */
+ var $_includeBodies = true;
+
+ /**
+ * Decode email body (only in case, when it will be included in result)
+ *
+ * @var bool
+ */
+ var $_decodeBodies = false;
+
+ /**
+ * Displays parsing error
+ *
+ * @param string $str
+ */
+ function raiseError($str)
+ {
+ trigger_error('Error during email parsing: ' . $str, E_USER_WARNING);
+ }
+
+ /**
+ * Initializes mime parsing using given email message
+ *
+ * @param string $message
+ */
+ function InitHelper($message = null)
+ {
+ if (!isset($message)) {
+ return ;
+ }
+
+ list ($header, $body) = $this->_splitBodyHeader($message);
+
+ $this->_headerPart = $header;
+ $this->_bodyPart = $body;
+ }
+
+ /**
+ * Decodes email message, that was previously set using InitHelper method
+ *
+ * @param bool $decode_headers
+ * @param bool $include_bodies
+ * @param bool $decode_bodies
+ * @return stdClass
+ */
+ function decode($decode_headers = false, $include_bodies = false, $decode_bodies = false)
+ {
+ $this->_decodeHeaders = $decode_headers;
+ $this->_includeBodies = $include_bodies;
+ $this->_decodeBodies = $decode_bodies;
+
+ $ret = $this->decodePart($this->_headerPart, $this->_bodyPart);
+
+ if ($ret === false) {
+ $this->raiseError($this->_lastErrorMessage);
+
+ return false;
+ }
+
+ return $ret;
+ }
+
+ function decodePart($headers, $body, $default_ctype = 'text/plain', $only_headers = false)
+ {
+ $return = new stdClass;
+
+ // process headers
+ $return->headers = Array ();
+ $headers = $this->_parseHeaders($headers, $this->_decodeHeaders);
+ $single_headers = Array ('subject', 'from', 'to', 'cc', 'reply-to', 'date');
+
+ foreach ($headers as $value) {
+ $header_name = strtolower($value['name']);
+ $header_value = $only_headers ? $this->_decodeHeader($value['value']) : $value['value'];
+
+ if (array_key_exists($header_name, $return->headers) && !is_array($return->headers[$header_name]) && !in_array($header_name, $single_headers)) {
+ // this is not a single header, so convert it to array, when 2nd value is found
+ $return->headers[$header_name] = Array ( $return->headers[$header_name] );
+ $return->headers[$header_name][] = $header_value;
+ }
+ elseif (array_key_exists($header_name, $return->headers) && !in_array($header_name, $single_headers)) {
+ $return->headers[$header_name][] = $header_value;
+ }
+ else {
+ $return->headers[$header_name] = $header_value;
+ }
+ }
+
+ if ($only_headers) {
+ return $return->headers;
+ }
+
+ foreach ($headers as $value) {
+ $header_name = strtolower($value['name']);
+ $header_value = $value['value'];
+
+ switch ($header_name) {
+ case 'content-type':
+ $content_type = $this->_parseHeaderValue($header_value);
+
+ if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
+ // "text/plain", "text/html", etc.
+ $return->ctype_primary = $regs[1];
+ $return->ctype_secondary = $regs[2];
+ }
+
+ if (array_key_exists('other', $content_type)) {
+ // "charset", etc.
+ foreach ($content_type['other'] as $p_name => $p_value) {
+ $return->ctype_parameters["$p_name"] = $p_value;
+ }
+ }
+ break;
+
+ case 'content-disposition';
+ $content_disposition = $this->_parseHeaderValue($header_value);
+ $return->disposition = $content_disposition['value'];
+
+ if (array_key_exists('other', $content_disposition)) {
+ // "filename", etc.
+ foreach ($content_disposition['other'] as $p_name => $p_value) {
+ $return->d_parameters["$p_name"] = $p_value;
+ }
+ }
+ break;
+
+ case 'content-transfer-encoding':
+ $content_transfer_encoding = $this->_parseHeaderValue($header_value);
+ break;
+ }
+ }
+
+ // process message body
+ if (isset($content_type)) {
+ switch ( strtolower($content_type['value']) ) {
+ case 'text/plain':
+ case 'text/html':
+ if ($this->_includeBodies) {
+ $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+ $return->body = $this->_decodeBodies ? $this->_decodeBody($body, $encoding) : $body;
+ }
+ break;
+
+ case 'multipart/parallel':
+ case 'multipart/report': // RFC1892
+ case 'multipart/signed': // PGP
+ case 'multipart/digest':
+ case 'multipart/alternative':
+ case 'multipart/appledouble':
+ case 'multipart/related':
+ case 'multipart/mixed':
+ if (!isset($content_type['other']['boundary'])) {
+ $this->_lastErrorMessage = 'No boundary found for ' . $content_type['value'] . ' part';
+ return false;
+ }
+
+ $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';
+
+ $parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
+
+ for ($i = 0; $i < count($parts); $i++) {
+ list ($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
+ $part = $this->decodePart($part_header, $part_body, $default_ctype);
+
+ if ($part === false) {
+ // part is broken
+ $this->raiseError($this->_lastErrorMessage);
+ }
+
+ $return->parts[] = $part;
+ }
+ break;
+
+ case 'message/rfc822':
+ case 'message/disposition-notification':
+ // create another instance, not to interfear with main parser
+ $mime_decode_helper =& $this->Application->makeClass('MimeDecodeHelper');
+ /* @var $mime_decode_helper MimeDecodeHelper */
+
+ $mime_decode_helper->InitHelper($body);
+
+ $return->parts[] = $mime_decode_helper->decode(true, $this->_includeBodies, $this->_decodeBodies);
+ unset($mime_decode_helper);
+ break;
+
+ default:
+ if ($this->_includeBodies) {
+ $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
+ $return->body = $this->_decodeBodies ? $this->_decodeBody($body, $encoding) : $body;
+ }
+ break;
+ }
+
+ } else {
+ $ctype = explode('/', $default_ctype);
+ $return->ctype_primary = $ctype[0];
+ $return->ctype_secondary = $ctype[1];
+
+ if ($this->_includeBodies) {
+ $return->body = $this->_decodeBodies ? $this->_decodeBody($body) : $body;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Divides message into header and body parts
+ *
+ * @param string $input
+ * @return Array
+ */
+ function _splitBodyHeader($input)
+ {
+ if (strpos($input, "\r\n\r\n") === false) {
+ return Array ($input, '');
+ } elseif (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
+ return Array ($match[1], $match[2]);
+ } else {
+ $this->_lastErrorMessage = 'Could not split header and body';
+
+ return false;
+ }
+ }
+
+ /**
+ * Parses headers string into array and optionally decode them
+ *
+ * @param string $input
+ * @param bool $decode
+ * @return Array
+ */
+ function _parseHeaders($input, $decode = false)
+ {
+ if (!$input) {
+ return Array ();
+ }
+
+ $ret = Array ();
+
+ // Unfold the input
+ $input = preg_replace("/\r\n/", "\n", $input);
+ $input = preg_replace("/\n(\t| )+/", ' ', $input);
+ $headers = explode("\n", trim($input));
+
+ foreach ($headers as $value) {
+ $pos = strpos($value, ':');
+ $hdr_name = substr($value, 0, $pos);
+ $hdr_value = substr($value, $pos + 1);
+
+ if ($hdr_value[0] == ' ') {
+ $hdr_value = substr($hdr_value, 1);
+ }
+
+ $ret[] = Array (
+ 'name' => $hdr_name,
+ 'value' => $decode ? $this->_decodeHeader($hdr_value) : $hdr_value
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Parses header value in following format (without quotes): "multipart/alternative; boundary=001636c9274051e332048498d8cc"
+ *
+ * @param string $input
+ * @return Array
+ */
+ function _parseHeaderValue($input)
+ {
+ $ret = Array ();
+ $pos = strpos($input, ';');
+
+ if ($pos === false) {
+ $ret['value'] = trim($input);
+
+ return $ret;
+ }
+
+ // get text until first ";"
+ $ret['value'] = trim(substr($input, 0, $pos));
+ $input = trim(substr($input, $pos + 1));
+
+ if (strlen($input) > 0) {
+ // This splits on a semi-colon, if there's no preceeding backslash
+ // Can't handle if it's in double quotes however. (Of course anyone
+ // sending that needs a good slap).
+ $parameters = preg_split('/\s*(?<!\\\\);\s*/i', $input);
+
+ for ($i = 0; $i < count($parameters); $i++) {
+ $pos = strpos($parameters[$i], '=');
+ $param_name = substr($parameters[$i], 0, $pos);
+ $param_value = substr($parameters[$i], $pos + 1);
+
+ if ($param_value[0] == '"') {
+ $param_value = substr($param_value, 1, -1);
+ }
+
+ $ret['other']["$param_name"] = $param_value;
+ $ret['other'][ strtolower($param_name) ] = $param_value;
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Splits input body using given boundary
+ *
+ * @param string $input
+ * @param string $boundary
+ * @return Array
+ */
+ function _boundarySplit($input, $boundary)
+ {
+ $tmp = explode('--' . $boundary, $input);
+
+ for ($i = 1; $i < count($tmp) - 1; $i++) {
+ $parts[] = $tmp[$i];
+ }
+
+ return $parts;
+ }
+
+ /**
+ * Decode message header value
+ *
+ * @param string $input
+ * @return string
+ */
+ function _decodeHeader($input)
+ {
+ // Remove white space between encoded-words (http://www.ietf.org/rfc/rfc2047.txt)
+ $regexp = '/(=\?[^?]+\?(Q|B)\?[^?]*\?=)(\s)+=\?/i';
+
+ while (preg_match($regexp, $input)) {
+ // process each word separately
+ $input = preg_replace($regexp, '\1=?', $input);
+ }
+
+ // For each encoded-word...
+ while (preg_match('/(=\?([^?]+)\?(Q|B)\?([^?]*)\?=)/i', $input, $matches)) {
+ $encoded = $matches[1];
+ $charset = $matches[2];
+ $encoding = $matches[3];
+ $text = $matches[4];
+
+ switch (strtoupper($encoding)) {
+ case 'B':
+ $text = base64_decode($text);
+ break;
+
+ case 'Q':
+ // $text = $this->_quotedPrintableDecode($text);
+ $text = str_replace('_', ' ', $text);
+ preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
+
+ foreach($matches[1] as $value) {
+ $text = str_replace('=' . $value, chr(hexdec($value)), $text);
+ }
+ break;
+ }
+
+ $input = $this->convertEncoding($charset, str_replace($encoded, $text, $input));
+ }
+
+ return $input;
+ }
+
+ /**
+ * Converts encoding to one, that site uses
+ *
+ * @param string $from_engoding
+ * @param string $text
+ * @return string
+ * @author Alex
+ */
+ function convertEncoding($from_engoding, $text)
+ {
+ if (!function_exists('mb_convert_encoding')) {
+ // if mbstring extension not installed
+ return $text;
+ }
+
+ static $to_encoding = false;
+
+ if ($to_encoding === false) {
+ $language =& $this->Application->recallObject('lang.current');
+ /* @var $language LanguagesItem */
+ $to_encoding = $language->GetDBField('Charset');
+ }
+
+ return mb_convert_encoding($text, $to_encoding, $from_engoding);
+
+ }
+
+ /**
+ * Decodes message body
+ *
+ * @param string $input
+ * @param string $encoding
+ * @return string
+ */
+ function _decodeBody($input, $encoding = '7bit')
+ {
+ switch (strtolower($encoding)) {
+ case 'quoted-printable':
+ return $this->_quotedPrintableDecode($input);
+ break;
+
+ case 'base64':
+ return base64_decode($input);
+ break;
+ }
+
+ // for 7bit, 8bit, anything else
+ return $input;
+ }
+
+ /**
+ * Decodes "quoted-printable" encoding
+ *
+ * @param string $string
+ * @return string
+ */
+ function _quotedPrintableDecode($string)
+ {
+ // Remove soft line breaks
+ $string = preg_replace("/=\r?\n/", '', $string);
+
+ // Replace encoded characters
+ if (preg_match_all('/=[a-f0-9]{2}/i', $string, $matches)) {
+ $matches = array_unique($matches[0]);
+ foreach ($matches as $value) {
+ $string = str_replace($value, chr(hexdec(substr($value,1))), $string);
+ }
+ }
+
+ return $string;
+ }
+ }
\ No newline at end of file
Index: core/units/helpers/pop3_helper.php
===================================================================
--- core/units/helpers/pop3_helper.php (revision 0)
+++ core/units/helpers/pop3_helper.php (revision 0)
@@ -0,0 +1,339 @@
+<?php
+
+ /**
+ * POP3 connection class, that uses sockets
+ *
+ */
+ class POP3Helper extends kHelper {
+
+ /**
+ * Pointer to socket to POP3 server
+ *
+ * @var resource
+ */
+ var $fp = null;
+
+ /**
+ * Connection to POP3 server established
+ *
+ * @var bool
+ */
+ var $connected = false;
+
+ /**
+ * Connection timeout
+ *
+ * @var int
+ */
+ var $connectionTimeout = 60;
+
+ /**
+ * Server connection information
+ *
+ * @var Array
+ */
+ var $serverInfo = Array ();
+
+ /**
+ * Size of each message in mailbox
+ *
+ * @var Array
+ */
+ var $messageSizes = Array ();
+
+ /**
+ * Sets up the server information array
+ *
+ * @param Array $server_info
+ * @return POP3Helper
+ */
+ function POP3Helper($server_info, $connection_timeout = null)
+ {
+ parent::kHelper();
+
+ $this->serverInfo = $server_info;
+
+ if (isset($connection_timeout)) {
+ $this->connectionTimeout = $connection_timeout;
+ }
+ }
+
+ /**
+ * Check if we can connect and log into the mailbox
+ *
+ * @return string
+ */
+ function initMailbox($dry_run = false)
+ {
+ if ($this->connect() === false) {
+ return 'socket';
+ }
+ elseif ($this->auth() === false) {
+ $this->close();
+ return 'login';
+ }
+ elseif ($this->getMessageList() === false) {
+ $this->close();
+ return 'list';
+ }
+ elseif (empty($this->messageSizes)) {
+ $this->close();
+ return 'empty'; // Still 'good'
+ }
+ elseif ($dry_run) {
+ $this->close();
+ return 'success';
+ }
+
+ return true;
+ }
+
+ /**
+ * Logs failed logins to our server
+ *
+ * @param int $error error code
+ * @param Array $error_array params of error
+ */
+ function error($error, $error_array)
+ {
+ trigger_error('POP3 Error. Code: ' . $error . '; Params: ' . print_r($error_array, true), E_USER_WARNING);
+ }
+
+ /**
+ * Connect to the server
+ *
+ * @return bool
+ */
+ function connect()
+ {
+ // Apparently fsockopen() doesn't return false in these cases:
+ if (empty($this->serverInfo['server'])) {
+ return false;
+ }
+
+ if ($this->connected == true) {
+ return true;
+ }
+
+ $this->fp = @fsockopen($this->serverInfo['server'], intval($this->serverInfo['port']), $error_no, $error_str, $this->connectionTimeout);
+
+ if (!is_resource($this->fp)) {
+ $this->error(101, $this->serverInfo);
+ return false;
+ }
+
+ $this->connected = true;
+ $buffer = fgets($this->fp, 4096);
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->error(101, $this->serverInfo);
+ $this->close();
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ /**
+ * Close connection to the server
+ *
+ */
+ function close()
+ {
+ if ($this->connected == true) { // and is_resource($this->fp)) {
+ $this->connected = false;
+ @fputs($this->fp, "QUIT\r\n");
+ @fclose($this->fp);
+ }
+ }
+
+ /**
+ * Login to the server
+ *
+ * @param bool $dry_run
+ * @return bool
+ */
+ function auth($dry_run = false)
+ {
+ if (!is_resource($this->fp) && ($this->connect() === false)) {
+ return false;
+ }
+
+ fputs($this->fp, 'USER ' . $this->serverInfo['username'] . "\r\n");
+ $buffer = fgets($this->fp, 4096);
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->close();
+ return false;
+ }
+
+ fputs($this->fp, 'PASS ' . $this->serverInfo['password'] . "\r\n");
+ $buffer = fgets($this->fp, 4096);
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->error(102, $this->serverInfo);
+ $this->close();
+
+ return false;
+ }
+ else {
+ if ($dry_run) {
+ $this->close();
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Get the list of messages and their ID's
+ *
+ * @return bool
+ */
+ function getMessageList()
+ {
+ fputs($this->fp, "LIST\r\n");
+
+ if (substr(fgets($this->fp, 4096), 0, 3) != '+OK') {
+ $this->close();
+ return false;
+ }
+
+ // Store the message numbers and sizes
+ $buffer = fgets($this->fp, 4096);
+
+ while ($buffer != ".\r\n") {
+ $msginfo = explode(' ', $buffer);
+ $this->messageSizes[ trim($msginfo[0]) ] = trim($msginfo[1]);
+ $buffer = fgets($this->fp, 4096);
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the size of a message
+ *
+ * @param int $message_number
+ * @return int
+ */
+ function getSize($message_number)
+ {
+ return $this->messageSizes["$message_number"];
+ }
+
+ /**
+ * Gets email number $message_number from the server
+ *
+ * @param int $message_number
+ * @param string $source
+ * @return string
+ */
+ function getEmail($message_number, &$source)
+ {
+ return $this->getData("RETR $message_number\r\n", $source);
+ }
+
+ /**
+ * Gets the top $lines from the message
+ *
+ * @param int $message_number
+ * @param string $source
+ * @param int $lines
+ * @param string $stopat
+ * @param bool $onelineonly
+ * @return string
+ */
+ function getTop($message_number, &$source, $lines = 0, $stopat = '', $onelineonly = false)
+ {
+ return $this->getData("TOP $message_number $lines\r\n", $source, $stopat, $onelineonly);
+ }
+
+ /**
+ * Issues $command and returns the output
+ *
+ * @param string $command
+ * @param string $source
+ * @param string $stopat
+ * @param bool $onelineonly
+ * @return string
+ */
+ function getData($command, &$source, $stopat = '', $onelineonly = false)
+ {
+ fputs($this->fp, $command);
+
+ if (substr(fgets($this->fp, 4096), 0, 3) != '+OK') {
+ return false;
+ }
+
+ $source = '';
+ $buffer = fgets($this->fp, 4096);
+
+ while ($buffer != ".\r\n") {
+ if (!$onelineonly) {
+ $source .= $buffer;
+ }
+
+ if (!empty($stopat)) {
+ if (strtolower(substr(trim($buffer), 0, strlen($stopat))) == strtolower($stopat)) {
+ if ($onelineonly) {
+ $source = $buffer;
+ }
+ else {
+ $onelineonly = true;
+ }
+
+ $stopat = '';
+ }
+ }
+
+ $buffer = fgets($this->fp, 4096);
+ }
+
+ return true;
+ }
+
+ /**
+ * Sends the given command to the server and returns true or false on success
+ *
+ * @param string $command
+ * @return bool
+ */
+ function sendCommand($command)
+ {
+ fputs($this->fp, $command . "\r\n");
+ $buffer = trim(fgets($this->fp, 4096));
+
+ if (substr($buffer, 0, 3) != '+OK') {
+ $this->error(103, Array ('cmd' => $command, 'resp' => $buffer));
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ /**
+ * Delete message number $message_number from the server
+ *
+ * @param int $message_number
+ * @return bool
+ */
+ function deleteEmail($message_number)
+ {
+ return $this->sendCommand("DELE $message_number");
+ }
+
+ /**
+ * Create new instance of object
+ *
+ * @return kBase
+ */
+ function &makeClass($server_info, $connection_timeout = null)
+ {
+ $object = new POP3Helper($server_info, $connection_timeout);
+
+ return $object;
+ }
+ }
\ No newline at end of file
Index: core/units/submission_log/submission_log_config.php
===================================================================
--- core/units/submission_log/submission_log_config.php (revision 0)
+++ core/units/submission_log/submission_log_config.php (revision 0)
@@ -0,0 +1,116 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => 'submission-log',
+ 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
+ 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
+ 'EventHandlerClass' => Array ('class' => 'SubmissionLogEventHandler', 'file' => 'submission_log_eh.php', 'build_event' => 'OnBuild'),
+ 'TagProcessorClass' => Array ('class' => 'SubmissionLogTagProcessor', 'file' => 'submission_log_tp.php', 'build_event' => 'OnBuild'),
+
+ 'AutoLoad' => true,
+
+ 'QueryString' => Array (
+ 1 => 'id',
+ 2 => 'Page',
+ 3 => 'event',
+ 4 => 'form_id'
+ ),
+
+ 'IDField' => 'SubmissionLogId',
+
+ 'TableName' => TABLE_PREFIX . 'SubmissionLog',
+
+ 'StatusField' => Array ('ReplyStatus'),
+
+ 'ParentPrefix' => 'formsubs',
+ 'ForeignKey' => 'FormSubmissionId',
+ 'ParentTableKey' => 'FormSubmissionId',
+ 'AutoDelete' => true,
+ 'AutoClone' => true,
+
+ 'TitleField' => 'Subject',
+
+ 'ListSQLs' => Array (
+ '' => ' SELECT %1$s.* %2$s FROM %1$s',
+ ),
+
+ 'ListSortings' => Array (
+ '' => Array (
+ 'Sorting' => Array ('SubmissionLogId' => 'desc'),
+ )
+ ),
+
+ 'Fields' => Array (
+ 'SubmissionLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'FormSubmissionId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+
+ 'FromEmail' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'regexp' => '/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/',
+ 'not_null' => 1, 'required' => 1, 'default' => ''
+ ),
+
+ 'ToEmail' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'regexp' => '/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/',
+ 'not_null' => 1, 'required' => 1, 'default' => ''
+ ),
+
+ 'Cc' => Array ('type' => 'string', 'default' => NULL),
+ 'Bcc' => Array ('type' => 'string', 'default' => NULL),
+ 'Subject' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'required' => 1, 'default' => ''),
+ 'Message' => Array ('type' => 'string', 'required' => 1, 'using_fck' => 1, 'default' => NULL),
+
+ 'Attachment' => Array (
+ 'type' => 'string',
+ 'formatter' => 'kUploadFormatter', 'upload_dir' => SUBMISSION_LOG_ATTACHMENT_PATH,
+ 'file_types' => '*.*', 'files_description' => '!la_hint_AnyFiles!', 'multiple' => 100,
+ 'default' => NULL
+ ),
+
+ 'ReplyStatus' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0 // create as not replied
+ ),
+
+ 'SentStatus' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No', 2 => 'la_opt_Bounce'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0 // create as not sent
+ ),
+
+ 'SentOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
+ 'RepliedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
+ 'VerifyCode' => Array ('type' => 'string', 'max_len' => 32, 'not_null' => 1, 'default' => ''),
+ 'DraftId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'MessageId' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
+ 'BounceInfo' => Array ('type' => 'string', 'default' => NULL),
+ 'BounceDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
+ ),
+
+ 'VirtualFields' => Array (
+ 'ReplyTo' => Array ('type' => 'int', 'default' => null),
+ ),
+
+ 'Grids' => Array (
+ 'Default' => Array (
+ 'Icons' => Array (0 => 'icon16_not_replied.gif', 1 => 'icon16_replied.gif'),
+ 'Fields' => Array (
+ 'SubmissionLogId' => Array ('title' => 'la_col_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', ),
+ 'Subject' => Array ('title' => 'la_col_Subject', 'data_block' => 'grid_subject_td', 'filter_block' => 'grid_like_filter',),
+ 'Message' => Array ('title' => 'la_col_Message', 'filter_block' => 'grid_like_filter', 'first_chars' => 100),
+ 'ReplyStatus' => Array ('title' => 'la_col_ReplyStatus', 'filter_block' => 'grid_options_filter',),
+ 'SentStatus' => Array ('title' => 'la_col_SentStatus', 'filter_block' => 'grid_options_filter',),
+ 'FromEmail' => Array ('title' => 'la_col_FromEmail', 'filter_block' => 'grid_like_filter',),
+ 'ToEmail' => Array ('title' => 'la_col_ToEmail', 'filter_block' => 'grid_like_filter',),
+ 'SentOn' => Array ('title' => 'la_col_SentOn', 'filter_block' => 'grid_date_range_filter',),
+ 'RepliedOn' => Array ('title' => 'la_col_RepliedOn', 'filter_block' => 'grid_date_range_filter',),
+ 'Cc' => Array ('title' => 'la_col_Cc', 'filter_block' => 'grid_like_filter', 'hidden' => 1),
+ 'Bcc' => Array ('title' => 'la_col_Bcc', 'filter_block' => 'grid_like_filter', 'hidden' => 1),
+ 'BounceInfo' => Array ('title' => 'la_col_BounceInfo', 'filter_block' => 'grid_like_filter', 'hidden' => 1),
+ 'BounceDate' => Array ('title' => 'la_col_BounceDate', 'filter_block' => 'grid_date_range_filter', 'hidden' => 1),
+ ),
+ ),
+ ),
+ );
\ No newline at end of file
Index: core/units/submission_log/submission_log_eh.php
===================================================================
--- core/units/submission_log/submission_log_eh.php (revision 0)
+++ core/units/submission_log/submission_log_eh.php (revision 0)
@@ -0,0 +1,677 @@
+<?php
+
+ class SubmissionLogEventHandler extends kDBEventHandler {
+
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+ $permissions = Array (
+ 'OnResendReply' => Array ('subitem' => 'add|edit'),
+ 'OnSaveDraft' => Array ('subitem' => 'add|edit'),
+ 'OnUseDraft' => Array ('subitem' => 'add|edit'),
+ 'OnDeleteDraft' => Array ('subitem' => 'add|edit'),
+
+ 'OnProcessBounceMail' => Array ('subitem' => true),
+ );
+
+ $this->permMapping = array_merge($this->permMapping, $permissions);
+ }
+
+ /**
+ * Checks event permissions
+ *
+ * @param kEvent $event
+ * @return bool
+ */
+ function CheckPermission(&$event)
+ {
+ $section = $event->getSection();
+ $form_id = $this->Application->GetVar('form_id');
+
+ if ($form_id) {
+ // copy form_id to env to be passed info upload links
+ $this->Application->SetVar($event->getPrefixSpecial() . '_form_id', $form_id);
+ }
+ else {
+ $form_id = $this->Application->GetVar($event->getPrefixSpecial() . '_form_id');
+ }
+
+ $event->setEventParam('PermSection', $section . ':' . $form_id);
+
+ return parent::CheckPermission($event);
+ }
+
+ /**
+ * Prepares new kDBItem object
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnNew(&$event)
+ {
+ parent::OnNew($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $form_submission =& $this->Application->recallObject('formsubs');
+ /* @var $form_submission kDBItem */
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+
+ $from_email = $form->GetDBField('ReplyFromEmail');
+ $to_email = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_EMAIL);
+
+ if ($this->Application->GetVar('client_mode')) {
+ // debug code for sending email from client
+ $object->SetDBField('FromEmail', $to_email);
+ $object->SetDBField('ToEmail', $from_email);
+
+ }
+ else {
+ $object->SetDBField('FromEmail', $from_email);
+ $object->SetDBField('ToEmail', $to_email);
+ }
+
+ $object->SetDBField('Cc', $form->GetDBField('ReplyCc'));
+ $object->SetDBField('Bcc', $form->GetDBField('ReplyBcc'));
+
+ $ids = $this->StoreSelectedIDs($event);
+ if ($ids) {
+ $org_message =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
+ /* @var $org_message kDBItem */
+
+ $org_message->Load( array_shift($ids) );
+ // client could reply from different email, so compare to admin email!
+ if ($org_message->GetDBField('ToEmail') == $from_email) {
+ // can reply only to client email, not own :)
+
+ // transform subject
+ $message_subject = $org_message->GetDBField('Subject');
+
+ if ($message_subject) {
+ $object->SetDBField('Subject', $this->_transformSubject($message_subject, 'Re'));
+ }
+
+ // add signature
+ $message_body = $form->GetDBField('ReplyMessageSignature');
+
+ if ($org_message->GetDBField('Message')) {
+ // add replied marks
+ $message_body .= '> ' . preg_replace('/([\r]*\n)/', '\\1> ', $org_message->GetDBField('Message'));
+ }
+
+ $object->SetDBField('ToEmail', $org_message->GetDBField('FromEmail')); // user client's email from reply
+ $object->SetDBField('Message', $message_body);
+ $object->SetDBField('ReplyTo', $org_message->GetID());
+ }
+ }
+ else {
+ $sql = 'SELECT COUNT(*)
+ FROM ' . $object->TableName . '
+ WHERE FormSubmissionId = ' . $form_submission->GetID();
+ $replies_found = $this->Conn->GetOne($sql);
+
+ if (!$replies_found) {
+ // 1st message from admin -> quote subject & text from feedback
+ $message_subject = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_SUBJECT);
+
+ if ($message_subject) {
+ $object->SetDBField('Subject', $this->_transformSubject($message_subject, 'Re'));
+ }
+
+ // add signature
+ $message_body = $form->GetDBField('ReplyMessageSignature');
+
+ // add replied marks
+ $original_message_body = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_BODY);
+
+ if ($original_message_body) {
+ $message_body .= '> ' . preg_replace('/([\r]*\n)/', '\\1> ', $original_message_body);
+ }
+
+ $object->SetDBField('Message', $message_body);
+ }
+ }
+
+ $this->clearSelectedIDs($event);
+ }
+
+ /**
+ * Parses $search string in subject and reformats it
+ * Used for replying and forwarding
+ *
+ * @param string $subject
+ * @param string $search
+ * @return string
+ */
+ function _transformSubject($subject, $search = 'Re')
+ {
+ $regex = '/'.$search.'(\[([\d]+)\]){0,1}:/i';
+ preg_match_all($regex, $subject, $regs);
+
+ if ($regs[2]) {
+ $reply_count = 0; // reply count without numbers (equals to "re[1]")
+ $max_reply_number = 0; // maximal reply number
+ sort($regs[2], SORT_NUMERIC); // sort ascending (non-numeric replies first)
+ foreach ($regs[2] as $match) {
+ if (!$match) {
+ // found "re:"
+ $reply_count++;
+ }
+ elseif ($match > $max_reply) {
+ // found "re:[number]"
+ $max_reply_number = $match;
+ }
+ }
+
+ return $search.'['.($reply_count + $max_reply_number + 1).']: '.trim(preg_replace($regex, '', $subject));
+ }
+
+ return $search.': '.$subject;
+ }
+
+ /**
+ * Resends reply, that was not sent last time
+ *
+ * @param kEvent $event
+ */
+ function OnResendReply(&$event)
+ {
+ $ids = $this->StoreSelectedIDs($event);
+
+ if (!$ids) {
+ return ;
+ }
+
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $sql = 'SELECT f.ReplyFromEmail, sl.' . $object->IDField . '
+ FROM ' . $object->TableName . ' sl
+ JOIN ' . $this->Application->getUnitOption('formsubs', 'TableName') . ' fs ON fs.FormSubmissionId = sl.FormSubmissionId
+ JOIN ' . $this->Application->getUnitOption('form', 'TableName') . ' f ON f.FormId = fs.FormId
+ WHERE sl.' . $object->IDField . ' IN (' . implode(',', $ids) . ')';
+ $reply_emails = $this->Conn->GetCol($sql, $object->IDField);
+
+ foreach ($ids as $id) {
+ $object->Load($id);
+
+ // allow to send messages, that were successfully sended before :(
+ if (($object->GetDBField('ToEmail') != $reply_emails[$id]) && ($object->GetDBField('SentStatus') != SUBMISSION_LOG_SENT)) {
+ $object->SetOriginalField('SentStatus', 0); // reset sent status to update sent date automatically
+
+ $this->_sendEmail($object); // resend email here
+ }
+ }
+
+ $this->clearSelectedIDs($event);
+
+ if (!$this->Application->GetVar('from_list')) {
+ $event->SetRedirectParam('opener', 'u');
+ }
+ }
+
+ /**
+ * Updates last operation dates for log record
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+ parent::OnBeforeItemCreate($event);
+
+ $this->_validateRecipients($event);
+ $this->_updateStatusDates($event);
+ }
+
+ /**
+ * Updates last operation dates for log record
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+ parent::OnBeforeItemUpdate($event);
+
+ $this->_validateRecipients($event);
+ $this->_updateStatusDates($event);
+ }
+
+ /**
+ * Validates email recipients
+ *
+ * @param kEvent $event
+ */
+ function _validateRecipients(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $esender =& $this->Application->recallObject('EmailSender');
+ /* @var $esender kEmailSendingHelper */
+
+ $cc = $object->GetDBField('Cc');
+
+ if ($cc && ($esender->GetRecipients($cc) === false)) {
+ $object->SetError('Cc', 'invalid_format');
+ }
+
+ $bcc = $object->GetDBField('Bcc');
+
+ if ($bcc && ($esender->GetRecipients($bcc) === false)) {
+ $object->SetError('Bcc', 'invalid_format');
+ }
+ }
+
+ /**
+ * Generates verification code and sets it inside sent message
+ *
+ * @param kDBItem $object
+ * @return string
+ */
+ function _generateVerificationCode(&$object)
+ {
+ $code = Array (
+ $object->GetDBField('FromEmail'),
+ $object->GetDBField('ToEmail'),
+ $object->GetID(),
+ getmicrotime()
+ );
+
+ $object->SetDBField('VerifyCode', md5( implode('-', $code) ));
+ }
+
+ /**
+ * Sends email based on fields from given submission-log record
+ *
+ * @param kDBItem $object
+ */
+ function _sendEmail(&$object)
+ {
+ if ($this->Application->GetVar('client_mode')) {
+ return ;
+ }
+
+ if (!$object->GetDBField('VerifyCode')) {
+ $this->_generateVerificationCode($object);
+ }
+
+ $form_submission =& $this->_getFormSubmission($object);
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+
+ $send_params = Array (
+ 'from_name' => $form->GetDBField('ReplyFromName'),
+ 'from_email' => $object->GetDBField('FromEmail'),
+
+ 'to_email' => $object->GetDBField('ToEmail'),
+
+ 'subject' => $object->GetDBField('Subject'),
+ 'message' => $object->GetDBField('Message'),
+ );
+
+ $to_name = $form_submission_helper->getFieldByRole($form_submission, EMAIL_COMMUNICATION_ROLE_NAME);
+
+ if ($to_name) {
+ $send_params['to_name'] = $to_name;
+ }
+
+ $esender =& $this->Application->recallObject('EmailSender');
+ /* @var $esender kEmailSendingHelper */
+
+ $esender->SetReturnPath( $form->GetDBField('BounceEmail') );
+
+ if ($object->GetDBField('Cc')) {
+ $recipients = $esender->GetRecipients( $object->GetDBField('Cc') );
+
+ foreach ($recipients as $recipient_info) {
+ $esender->AddCc($recipient_info['Email'], $recipient_info['Name']);
+ }
+ }
+
+ if ($object->GetDBField('Bcc')) {
+ $recipients = $esender->GetRecipients( $object->GetDBField('Bcc') );
+
+ foreach ($recipients as $recipient_info) {
+ $esender->AddBcc($recipient_info['Email'], $recipient_info['Name']);
+ }
+ }
+
+ if ($object->GetDBField('Attachment')) {
+ $attachments = explode('|', $object->GetField('Attachment', 'file_paths'));
+
+ foreach ($attachments as $attachment) {
+ $esender->AddAttachment($attachment);
+ }
+ }
+
+ $this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.TO.USER', null, $send_params);
+
+ // mark as sent after sending is finished
+ $object->SetDBField('SentStatus', SUBMISSION_LOG_SENT);
+
+ // reset bounce status before (re-)sending
+ $object->SetDBField('BounceInfo', NULL);
+ $object->SetDBField('BounceDate_date', NULL);
+ $object->SetDBField('BounceDate_time', NULL);
+
+ if ($object->GetDBField('DraftId')) {
+ $temp_handler =& $this->Application->recallObject('draft_TempHandler', 'kTempTablesHandler');
+ /* @var $temp_handler kTempTablesHandler */
+
+ $temp_handler->DeleteItems('draft', '', Array ($object->GetDBField('DraftId')));
+ $object->SetDBField('DraftId', 0);
+ }
+
+ $object->Update();
+ }
+
+ /**
+ * Sends new email after log record was created
+ * Updates last update time for submission
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemCreate(&$event)
+ {
+ parent::OnAfterItemCreate($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $this->_sendEmail($object); // send email
+
+ $this->_updateSubmission($event);
+
+ $reply_to = $object->GetDBField('ReplyTo');
+ if (!$reply_to) {
+ $reply_to = $this->_getLastMessageId($event, !$this->Application->GetVar('client_mode'));
+ }
+
+ if ($reply_to) {
+ // this is reply to other message -> mark it as replied
+ $org_message =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
+ /* @var $org_message kDBItem */
+
+ $org_message->Load($reply_to);
+ $org_message->SetDBField('ReplyStatus', SUBMISSION_LOG_REPLIED);
+ $org_message->Update();
+ }
+
+ if ($this->Application->GetVar('client_mode')) {
+ // new reply from client received -> send notification about it
+ $this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.FROM.USER');
+ }
+ }
+
+ /**
+ * Returns last message id (client OR admin)
+ *
+ * @param kEvent $event
+ * @param bool $from_client
+ * @return int
+ */
+ function _getLastMessageId(&$event, $from_client = false)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $form_submission =& $this->_getFormSubmission($object);
+
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+ $reply_email = $form->GetDBField('ReplyFromEmail');
+
+ $sql = 'SELECT MAX(' . $object->IDField . ')
+ FROM ' . $object->TableName . '
+ WHERE (FormSubmissionId = ' . $form_submission->GetID() . ') AND (ToEmail' . ($from_client ? ' = ' : ' <> ') . $this->Conn->qstr($reply_email) . ')';
+ return $this->Conn->GetOne($sql);
+ }
+
+ /**
+ * Updates last update time for submission
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemUpdate(&$event)
+ {
+ parent::OnAfterItemUpdate($event);
+
+ $this->_updateSubmission($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ // send out email event to admin for bouncing
+ if ( $object->GetOriginalField('SentStatus') != $object->GetDBField('SentStatus')
+ && $object->GetDBField('SentStatus') == SUBMISSION_LOG_BOUNCE ) {
+
+ $this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED');
+ }
+ }
+
+ /**
+ * Sets last sent/reply dates based on field changes in log record
+ *
+ * @param kEvent $event
+ */
+ function _updateStatusDates(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $now = adodb_mktime();
+
+ $sent_status = $object->GetDBField('SentStatus');
+ if (($sent_status == SUBMISSION_LOG_SENT) && ($sent_status != $object->GetOriginalField('SentStatus'))) {
+ // sent status was set
+ $object->SetDBField('SentOn_date', $now);
+ $object->SetDBField('SentOn_time', $now);
+ }
+
+ $reply_status = $object->GetDBField('ReplyStatus');
+ if (($reply_status == SUBMISSION_LOG_REPLIED) && ($reply_status != $object->GetOriginalField('ReplyStatus'))) {
+ // sent status was set
+ $object->SetDBField('RepliedOn_date', $now);
+ $object->SetDBField('RepliedOn_time', $now);
+ }
+ }
+
+ /**
+ * Returns form submission by given event of submission log
+ *
+ * @param kDBItem $object
+ * @return kDBItem
+ */
+ function &_getFormSubmission(&$object)
+ {
+ $submission_id = $object->GetDBField('FormSubmissionId');
+
+ $form_submission =& $this->Application->recallObject('formsubs.-item', null, Array ('skip_autoload' => true));
+ /* @var $form_submission kDBItem */
+
+ if ($form_submission->isLoaded() && ($form_submission->GetID() == $submission_id)) {
+ // already loaded AND has needed id
+ return $form_submission;
+ }
+
+ $form_submission->Load($submission_id);
+
+ return $form_submission;
+ }
+
+ /**
+ * Sets last updated field for form submission
+ *
+ * @param kEvent $event
+ */
+ function _updateSubmission(&$event)
+ {
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $form_submission =& $this->_getFormSubmission($object);
+
+ // 1. set last updated
+ $last_updated = max ($object->GetDBField('SentOn'), $object->GetDBField('RepliedOn'));
+
+ if ($form_submission->GetDBField('LastUpdatedOn') < $last_updated) {
+ // don't set smaller last update, that currenly set
+ $form_submission->SetDBField('LastUpdatedOn_date', $last_updated);
+ $form_submission->SetDBField('LastUpdatedOn_time', $last_updated);
+ }
+
+ // 2. update submission status
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
+
+ $form =& $form_submission_helper->getForm($form_submission);
+ $client_responce = $form->GetDBField('ReplyFromEmail') == $object->GetDBField('ToEmail');
+ $replied = $object->GetDBField('ReplyStatus') == SUBMISSION_LOG_REPLIED;
+
+ if (!$client_responce && !$replied) {
+ // admin sends new email to client
+ $form_submission->SetDBField('LogStatus', SUBMISSION_REPLIED);
+ }
+ elseif ($client_responce) {
+ // client email becomes replied OR receiving new unreplied email from client
+ $form_submission->SetDBField('LogStatus', $replied ? SUBMISSION_REPLIED : SUBMISSION_NEW_EMAIL);
+ }
+
+ if ($object->GetDBField('SentStatus') == SUBMISSION_LOG_BOUNCE) {
+ // propagate bounce status from reply
+ $form_submission->SetDBField('LogStatus', SUBMISSION_BOUNCE);
+ }
+
+ $form_submission->Update();
+ }
+
+ /**
+ * Saves current unsent message as draft
+ *
+ * @param kEvent $event
+ */
+ function OnSaveDraft(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ foreach ($items_info as $id => $field_values) {
+ $object->setID($id);
+ $object->SetFieldsFromHash($field_values);
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+
+ $draft->SetDBField('Message', $object->GetDBField('Message'));
+
+ if ($draft->isLoaded()) {
+ $draft->Update();
+ }
+ else {
+ $draft->SetDBFieldsFromHash($load_keys);
+ $draft->Create();
+ }
+ }
+ }
+
+ $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
+ $event->SetRedirectParam('opener', 'u');
+ }
+
+ /**
+ * Uses found draft instead of submission reply body
+ *
+ * @param kEvent $event
+ */
+ function OnUseDraft(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ foreach ($items_info as $id => $field_values) {
+ $object->setID($id);
+ $object->SetFieldsFromHash($field_values);
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+ if ($draft->isLoaded()) {
+ $object->SetDBField('Message', $draft->GetDBField('Message'));
+ $object->SetDBField('DraftId', $draft->GetID());
+ }
+ }
+ }
+
+ $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
+ $event->redirect = false;
+ }
+
+ /**
+ * Deletes draft, that matches given user and form submission
+ *
+ * @param kEvent $event
+ */
+ function OnDeleteDraft(&$event)
+ {
+ $object =& $event->getObject( Array('skip_autoload' => true) );
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if ($items_info) {
+ foreach ($items_info as $id => $field_values) {
+ $object->setID($id);
+ $object->SetFieldsFromHash($field_values);
+ $object->SetDBField('DraftId', 0);
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+ if ($draft->isLoaded()) {
+ $temp_handler =& $this->Application->recallObject('draft_TempHandler', 'kTempTablesHandler');
+ /* @var $temp_handler kTempTablesHandler */
+
+ $temp_handler->DeleteItems('draft', '', Array ($draft->GetID()));
+ }
+ }
+ }
+
+ $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
+ $event->redirect = false;
+ }
+ }
\ No newline at end of file
Index: core/units/submission_log/submission_log_tp.php
===================================================================
--- core/units/submission_log/submission_log_tp.php (revision 0)
+++ core/units/submission_log/submission_log_tp.php (revision 0)
@@ -0,0 +1,99 @@
+<?php
+
+ class SubmissionLogTagProcessor extends kDBTagProcessor {
+
+ /**
+ * Checks, that current log record is mail from client to admin and it's not replied
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function IsNewUserReply($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $user_reply = $this->IsUserReply($params);
+
+ return $user_reply && ($object->GetDBField('ReplyStatus') != SUBMISSION_LOG_REPLIED);
+ }
+
+ /**
+ * Checks, that current log record is mail from client to admin
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function IsUserReply($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $reply_email = $this->Application->ConfigValue('SubmissionReplyFromEmail');
+
+ return $object->GetDBField('ToEmail') == $reply_email;
+ }
+
+ /**
+ * Checks if there is draft for given article
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function HasDraft($params)
+ {
+ if (!$this->IsNewItem($params)) {
+ // use drafts only for unsent (new) messages
+ return false;
+ }
+
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
+ /* @var $draft kDBItem */
+
+ $load_keys = Array (
+ 'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
+ 'CreatedById' => $this->Application->RecallVar('user_id'),
+ );
+
+ // get existing draft for given submission and user
+ $draft->Load($load_keys);
+
+ return $draft->isLoaded();
+ }
+
+ /**
+ * Lists all files, uploadeded to given field
+ *
+ * @param Array $params
+ * @return string
+ */
+ function IterateFiles($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ $field = $this->SelectParam($params, 'name,field');
+ $value = $object->GetDBField($field);
+
+ if (!$value) {
+ return '';
+ }
+
+ $ret = '';
+ $files = explode('|', $value);
+ $block_params = $this->prepareTagParams($params);
+ $block_params['name'] = $params['render_as'];
+
+ foreach ($files as $file) {
+ $object->SetDBField($field, $file);
+ $ret .= $this->Application->ParseBlock($block_params);
+ }
+
+ $object->SetDBField($field, $value);
+
+ return $ret;
+ }
+ }
\ No newline at end of file
473-Improvements to Form Submissions-DEFAULT_theme_installdata.patch [^] (2,396 bytes) 2010-04-22 17:29
[Show Content]
Index: themes/default/_install/install_data.sql
===================================================================
--- themes/default/_install/install_data.sql (revision 13380)
+++ themes/default/_install/install_data.sql (working copy)
@@ -22,14 +22,14 @@
INSERT INTO PermCache VALUES(DEFAULT, 202, 1, '11');
INSERT INTO PermCache VALUES(DEFAULT, 203, 1, '11');
-INSERT INTO Forms VALUES(1, 'Contact Us', 'Form for contacts');
+INSERT INTO Forms VALUES(1, 'Contact Us', 'Form for contacts', 0, 0, 0, '', '', '', '', '', '', '110', '', '', '', '', '110', '', '');
-INSERT INTO FormFields VALUES(1, 1, 0, 'Name', 'lu_fld_Name', NULL, 'la_fld_Name', 'text', NULL, 5, 0, 1, 1, NULL, 0);
-INSERT INTO FormFields VALUES(2, 1, 0, 'Company', 'lu_fld_Company', NULL, 'la_fld_Company', 'text', NULL, 4, 0, 1, 1, NULL, 0);
-INSERT INTO FormFields VALUES(3, 1, 0, 'Email', 'lu_fld_Email', NULL, 'la_fld_Email', 'text', NULL, 3, 0, 1, 1, NULL, 1);
-INSERT INTO FormFields VALUES(4, 1, 0, 'Phone', 'lu_fld_Phone', NULL, 'la_fld_Phone', 'text', NULL, 2, 0, 0, 1, NULL, 0);
-INSERT INTO FormFields VALUES(5, 1, 0, 'Message', 'lu_fld_Message', NULL, 'la_fld_Message', 'textarea', NULL, 0, 0, 1, 0, NULL, 0);
-INSERT INTO FormFields VALUES(6, 1, 0, 'Subject', 'lu_fld_Subject', NULL, 'la_fld_Subject', 'select', '=+-- Please select --||0=+Sales questions||1=+General questions||2=+Billing questions||3=+Support questions', 1, 0, 1, 0, NULL, 0);
+INSERT INTO FormFields VALUES(1, 1, 0, 'Name', 'lu_fld_Name', NULL, 'la_fld_Name', 'text', NULL, 5, 0, 1, 1, NULL, 0, 1, 0);
+INSERT INTO FormFields VALUES(2, 1, 0, 'Company', 'lu_fld_Company', NULL, 'la_fld_Company', 'text', NULL, 4, 0, 1, 1, NULL, 0, 1, 0);
+INSERT INTO FormFields VALUES(3, 1, 0, 'Email', 'lu_fld_Email', NULL, 'la_fld_Email', 'text', NULL, 3, 0, 1, 1, NULL, 1, 1, 0);
+INSERT INTO FormFields VALUES(4, 1, 0, 'Phone', 'lu_fld_Phone', NULL, 'la_fld_Phone', 'text', NULL, 2, 0, 0, 1, NULL, 0, 1, 0);
+INSERT INTO FormFields VALUES(5, 1, 0, 'Message', 'lu_fld_Message', NULL, 'la_fld_Message', 'textarea', NULL, 0, 0, 1, 0, NULL, 0, 1, 0);
+INSERT INTO FormFields VALUES(6, 1, 0, 'Subject', 'lu_fld_Subject', NULL, 'la_fld_Subject', 'select', '=+-- Please select --||0=+Sales questions||1=+General questions||2=+Billing questions||3=+Support questions', 1, 0, 1, 0, NULL, 0, 1, 0);
ALTER TABLE FormSubmissions
ADD COLUMN fld_1 text,
form_field_edit_fix.patch [^] (472 bytes) 2010-05-15 04:47
[Show Content]
Index: admin_templates/forms/forms_edit_fields.tpl
===================================================================
--- admin_templates/forms/forms_edit_fields.tpl (revision 13557)
+++ admin_templates/forms/forms_edit_fields.tpl (working copy)
@@ -12,7 +12,7 @@
function edit()
{
- std_edit_temp_item('form', 'forms/form_field_edit');
+ std_edit_temp_item('formflds', 'forms/form_field_edit');
}
a_toolbar = new ToolBar();
|