swad-core/swad_message.c

2955 lines
104 KiB
C
Raw Normal View History

2014-12-01 23:55:08 +01:00
// swad_message.c: messages between users
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2024 Antonio Ca<EFBFBD>as Vargas
2014-12-01 23:55:08 +01:00
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
2018-10-29 14:17:32 +01:00
#define _GNU_SOURCE // For asprintf
2014-12-01 23:55:08 +01:00
#include <linux/limits.h> // For PATH_MAX
2019-12-29 12:39:00 +01:00
#include <stddef.h> // For NULL
2018-10-29 14:17:32 +01:00
#include <stdio.h> // For asprintf
2014-12-01 23:55:08 +01:00
#include <stdlib.h> // For free
#include <string.h> // For string functions
#include <time.h> // For time
#include "swad_action.h"
#include "swad_action_list.h"
#include "swad_autolink.h"
2017-06-10 21:38:10 +02:00
#include "swad_box.h"
2014-12-01 23:55:08 +01:00
#include "swad_config.h"
#include "swad_course.h"
#include "swad_database.h"
#include "swad_error.h"
2020-04-14 17:15:17 +02:00
#include "swad_figure.h"
2018-11-09 20:47:39 +01:00
#include "swad_form.h"
2014-12-01 23:55:08 +01:00
#include "swad_forum.h"
#include "swad_global.h"
#include "swad_group.h"
2021-02-11 22:57:09 +01:00
#include "swad_hierarchy.h"
#include "swad_hierarchy_type.h"
2019-10-23 19:05:05 +02:00
#include "swad_HTML.h"
2015-12-23 13:20:58 +01:00
#include "swad_ID.h"
#include "swad_media.h"
2014-12-01 23:55:08 +01:00
#include "swad_message.h"
#include "swad_message_database.h"
#include "swad_nickname_database.h"
2014-12-01 23:55:08 +01:00
#include "swad_notification.h"
#include "swad_notification_database.h"
2020-04-07 03:01:41 +02:00
#include "swad_pagination.h"
2014-12-01 23:55:08 +01:00
#include "swad_parameter.h"
#include "swad_parameter_code.h"
2014-12-01 23:55:08 +01:00
#include "swad_photo.h"
2015-03-14 17:39:04 +01:00
#include "swad_profile.h"
#include "swad_profile_database.h"
#include "swad_session_database.h"
#include "swad_setting.h"
2014-12-01 23:55:08 +01:00
#include "swad_user.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
2016-04-10 14:09:50 +02:00
// Forum images will be saved with:
// - maximum width of Msg_IMAGE_SAVED_MAX_HEIGHT
// - maximum height of Msg_IMAGE_SAVED_MAX_HEIGHT
// - maintaining the original aspect ratio (aspect ratio recommended: 3:2)
#define Msg_IMAGE_SAVED_MAX_WIDTH 768
2020-02-13 22:33:31 +01:00
#define Msg_IMAGE_SAVED_MAX_HEIGHT 768
#define Msg_IMAGE_SAVED_QUALITY 90 // 1 to 100
2016-04-10 14:09:50 +02:00
2017-04-13 20:09:22 +02:00
static const Pag_WhatPaginate_t Msg_WhatPaginate[Msg_NUM_TYPES_OF_MSGS] =
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = Pag_NONE,
[Msg_RECEIVED] = Pag_MESSAGES_RECEIVED,
[Msg_SENT ] = Pag_MESSAGES_SENT,
2017-04-13 20:09:22 +02:00
};
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-11-21 16:47:07 +01:00
/***************************** Private prototypes ****************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_ResetMessages (struct Msg_Messages *Messages);
2014-12-01 23:55:08 +01:00
static void Msg_PutFormMsgUsrs (Act_Action_t NextAction,
struct Msg_Messages *Messages,
2020-04-11 15:21:30 +02:00
char Content[Cns_MAX_BYTES_LONG_TEXT + 1]);
static void Msg_ShowSntOrRcvMessages (struct Msg_Messages *Messages);
2014-12-17 23:04:35 +01:00
static void Msg_PutLinkToViewBannedUsers(void);
2016-03-21 13:41:15 +01:00
2020-04-11 15:21:30 +02:00
static void Msg_SetNumMsgsStr (const struct Msg_Messages *Messages,
char **NumMsgsStr,unsigned NumUnreadMsgs);
2016-11-07 12:31:14 +01:00
2020-04-08 19:42:03 +02:00
static void Msg_PutIconsListMsgs (void *Messages);
static void Msg_PutParsOneMsg (void *Messages);
2016-03-21 13:41:15 +01:00
2020-04-11 15:21:30 +02:00
static void Msg_ShowFormSelectCourseSentOrRecMsgs (const struct Msg_Messages *Messages);
static void Msg_ShowFormToFilterMsgs (const struct Msg_Messages *Messages);
static void Msg_ShowFormToShowOnlyUnreadMessages (const struct Msg_Messages *Messages);
static bool Msg_GetParOnlyUnreadMsgs (void);
2020-04-11 15:21:30 +02:00
static void Msg_ShowASentOrReceivedMessage (struct Msg_Messages *Messages,
long MsgNum,long MsgCod);
static void Msg_PutLinkToShowMorePotentialRecipients (struct Msg_Messages *Messages);
static void Msg_PutParsShowMorePotentialRecipients (void *Messages);
static void Msg_PutParsWriteMsg (void *Messages);
static void Msg_PutParsSubjectAndContent (void);
2015-12-23 13:20:58 +01:00
static void Msg_ShowOneUniqueRecipient (void);
2015-12-22 13:22:35 +01:00
static void Msg_WriteFormUsrsIDsOrNicksOtherRecipients (void);
2020-04-11 15:21:30 +02:00
static void Msg_WriteFormSubjectAndContentMsgToUsrs (struct Msg_Messages *Messages,
char Content[Cns_MAX_BYTES_LONG_TEXT + 1]);
static void Msg_PutParAnotherRecipient (const struct Usr_Data *UsrDat);
static void Msg_PutParOtherRecipients (void);
2020-04-11 15:21:30 +02:00
2014-12-01 23:55:08 +01:00
static void Msg_ShowNumMsgsDeleted (unsigned NumMsgs);
static void Msg_GetParMsgsCrsCod (struct Msg_Messages *Messages);
static void Msg_GetParFilterFromTo (struct Msg_Messages *Messages);
static void Msg_GetParFilterContent (struct Msg_Messages *Messages);
2020-04-11 15:21:30 +02:00
2016-04-10 19:19:20 +02:00
static long Msg_InsertNewMsg (const char *Subject,const char *Content,
2021-02-11 00:58:53 +01:00
struct Med_Media *Media);
2015-03-11 00:36:12 +01:00
static unsigned long Msg_RemoveSomeRecOrSntMsgsUsr (const struct Msg_Messages *Messages,
long UsrCod,
const char *FilterFromToSubquery);
static void Msg_MoveRcvMsgToDeleted (long MsgCod,long UsrCod);
static void Msg_MoveSntMsgToDeleted (long MsgCod);
2014-12-01 23:55:08 +01:00
2015-10-24 20:12:03 +02:00
static void Msg_GetMsgSntData (long MsgCod,long *CrsCod,long *UsrCod,
2017-01-17 03:10:43 +01:00
time_t *CreatTimeUTC,
char Subject[Cns_MAX_BYTES_SUBJECT + 1],
bool *Deleted);
static void Msg_GetMsgContent (long MsgCod,
char Content[Cns_MAX_BYTES_LONG_TEXT + 1],
2021-02-11 00:58:53 +01:00
struct Med_Media *Media);
2014-12-01 23:55:08 +01:00
2020-04-11 15:21:30 +02:00
static void Msg_WriteSentOrReceivedMsgSubject (struct Msg_Messages *Messages,
long MsgCod,const char *Subject,
CloOpe_ClosedOrOpen_t ClosedOrOpen,
bool Expanded);
2020-04-11 15:21:30 +02:00
static bool Msg_WriteCrsOrgMsg (long CrsCod);
static void Msg_WriteFormToReply (long MsgCod,long CrsCod,bool FromThisCrs,
const struct Usr_Data *UsrDat);
2020-04-11 15:21:30 +02:00
static void Msg_WriteMsgFrom (struct Msg_Messages *Messages,
struct Usr_Data *UsrDat,bool Deleted);
2020-04-11 15:21:30 +02:00
static void Msg_WriteMsgTo (struct Msg_Messages *Messages,long MsgCod);
static void Msg_PutFormToBanSender (struct Msg_Messages *Messages,
struct Usr_Data *UsrDat);
2020-04-11 15:21:30 +02:00
static void Msg_PutFormToUnbanSender (struct Msg_Messages *Messages,
struct Usr_Data *UsrDat);
2014-12-01 23:55:08 +01:00
static void Msg_UnbanSender (void);
2020-04-11 15:21:30 +02:00
/*****************************************************************************/
/**************************** Reset messages context *************************/
/*****************************************************************************/
static void Msg_ResetMessages (struct Msg_Messages *Messages)
{
Messages->NumMsgs = 0;
Messages->Subject[0] = '\0';
Messages->FilterCrsCod = -1L;
Messages->FilterCrsShrtName[0] = '\0';
Messages->FilterFromTo[0] = '\0';
Messages->FilterContent[0] = '\0';
Messages->ShowOnlyUnreadMsgs = false;
Messages->ExpandedMsgCod = -1L;
Messages->Reply.IsReply = false;
Messages->Reply.OriginalMsgCod = -1L;
Messages->ShowOnlyOneRecipient = false;
Messages->CurrentPage = 0;
Messages->MsgCod = -1L;
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/***************** Put a form to write a new message to users ****************/
/*****************************************************************************/
void Msg_FormMsgUsrs (void)
{
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
2017-01-17 03:10:43 +01:00
char Content[Cns_MAX_BYTES_LONG_TEXT + 1];
2014-12-01 23:55:08 +01:00
2020-04-11 15:21:30 +02:00
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2016-07-01 14:40:01 +02:00
/***** Get possible hidden subject and content of the message *****/
Par_GetParHTML ("HiddenSubject",Messages.Subject,Cns_MAX_BYTES_SUBJECT);
2016-07-01 14:40:01 +02:00
Par_GetParAndChangeFormat ("HiddenContent",Content,Cns_MAX_BYTES_LONG_TEXT,
Str_TO_TEXT,Str_DONT_REMOVE_SPACES);
2016-07-01 01:21:34 +02:00
2017-03-15 11:10:16 +01:00
/***** Show a form to compose a message to users *****/
Msg_PutFormMsgUsrs (ActReqMsgUsr,&Messages,Content);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Put a form to write a new message to users ****************/
/*****************************************************************************/
static void Msg_PutFormMsgUsrs (Act_Action_t NextAction,
struct Msg_Messages *Messages,
2020-04-11 15:21:30 +02:00
char Content[Cns_MAX_BYTES_LONG_TEXT + 1])
2014-12-01 23:55:08 +01:00
{
2020-09-26 17:20:01 +02:00
extern const char *Hlp_COMMUNICATION_Messages_write;
extern const char *Txt_Message;
2014-12-01 23:55:08 +01:00
extern const char *Txt_MSG_To;
extern const char *Txt_Send_message;
2016-11-25 09:41:06 +01:00
unsigned NumUsrsInCrs = 0; // Initialized to avoid warning
2016-07-04 17:52:09 +02:00
bool ShowUsrsInCrs = false;
2016-11-25 03:21:02 +01:00
bool GetUsrsInCrs;
char *ClassInput;
2014-12-01 23:55:08 +01:00
2017-05-22 14:52:11 +02:00
Gbl.Usrs.LstUsrs[Rol_STD].NumUsrs =
Gbl.Usrs.LstUsrs[Rol_NET].NumUsrs =
Gbl.Usrs.LstUsrs[Rol_TCH].NumUsrs = 0;
2014-12-01 23:55:08 +01:00
/***** Get parameter that indicates if the message is a reply to another message *****/
if ((Messages->Reply.IsReply = Par_GetParBool ("IsReply")))
2014-12-01 23:55:08 +01:00
/* Get original message code */
Messages->Reply.OriginalMsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2015-12-22 13:22:35 +01:00
2014-12-01 23:55:08 +01:00
/***** Get user's code of possible preselected recipient *****/
if (Usr_GetParOtherUsrCodEncryptedAndGetUsrData ()) // There is a preselected recipient
2015-12-22 14:00:36 +01:00
/* Get who to show as potential recipients:
- only the selected recipient
- any user (default) */
Messages->ShowOnlyOneRecipient = Par_GetParBool ("ShowOnlyOneRecipient");
2016-07-04 17:40:34 +02:00
else
2020-04-11 15:21:30 +02:00
Messages->ShowOnlyOneRecipient = false;
2014-12-01 23:55:08 +01:00
2020-04-11 15:21:30 +02:00
GetUsrsInCrs = !Messages->ShowOnlyOneRecipient && // Show list of potential recipients
(Gbl.Usrs.Me.IBelongToCurrent[Hie_CRS] || // If there is a course selected and I belong to it
2017-06-04 18:18:54 +02:00
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
2016-11-25 03:21:02 +01:00
if (GetUsrsInCrs)
{
/***** Get and update type of list,
number of columns in class photo
and preference about view photos *****/
Set_GetAndUpdatePrefsAboutUsrList ();
2016-11-25 03:21:02 +01:00
/***** Get groups to show ******/
Grp_GetParCodsSeveralGrpsToShowUsrs ();
/***** Get and order lists of users from this course *****/
Usr_GetListUsrs (Hie_CRS,Rol_STD);
Usr_GetListUsrs (Hie_CRS,Rol_NET);
Usr_GetListUsrs (Hie_CRS,Rol_TCH);
2017-05-22 14:52:11 +02:00
NumUsrsInCrs = Gbl.Usrs.LstUsrs[Rol_STD].NumUsrs + // Students
Gbl.Usrs.LstUsrs[Rol_NET].NumUsrs + // Non-editing teachers
Gbl.Usrs.LstUsrs[Rol_TCH].NumUsrs; // Teachers
2016-11-25 03:21:02 +01:00
}
2019-10-26 02:19:42 +02:00
/***** Begin box *****/
Box_BoxBegin (Txt_Message,Msg_PutIconsListMsgs,Messages,
2020-09-26 17:20:01 +02:00
Hlp_COMMUNICATION_Messages_write,Box_NOT_CLOSABLE);
2015-10-02 01:04:28 +02:00
if (Messages->ShowOnlyOneRecipient)
/***** Form to show several potential recipients *****/
Msg_PutLinkToShowMorePotentialRecipients (Messages);
else
2016-07-04 17:40:34 +02:00
{
/***** Get list of users belonging to the current course *****/
if (GetUsrsInCrs)
{
/***** Form to select groups *****/
Grp_ShowFormToSelectSeveralGroups (NextAction,Msg_PutParsWriteMsg,Messages,
"CopyMessageToHiddenFields();");
2017-05-25 11:04:38 +02:00
/***** Begin section with user list *****/
HTM_SECTION_Begin (Usr_USER_LIST_SECTION_ID);
2016-07-04 17:40:34 +02:00
if (NumUsrsInCrs)
{
/***** Form to select type of list used for select several users *****/
Usr_ShowFormsToSelectUsrListType (NextAction,Msg_PutParsWriteMsg,Messages,
"CopyMessageToHiddenFields();");
2016-07-04 17:40:34 +02:00
/***** Put link to register students *****/
Enr_CheckStdsAndPutButtonToRegisterStdsInCurrentCrs ();
2017-05-29 21:34:43 +02:00
/***** Check if it's a big list *****/
ShowUsrsInCrs = Usr_GetIfShowBigList (NumUsrsInCrs,
NextAction,Msg_PutParsWriteMsg,Messages,
"CopyMessageToHiddenFields();");
2016-07-04 17:40:34 +02:00
if (ShowUsrsInCrs)
/***** Get lists of selected users *****/
Usr_GetListsSelectedEncryptedUsrsCods (&Gbl.Usrs.Selected);
}
2017-05-25 11:04:38 +02:00
/***** End section with user list *****/
HTM_SECTION_End ();
}
2016-07-04 17:40:34 +02:00
/***** Get list of users' IDs or nicknames written explicitely *****/
Usr_GetListMsgRecipientsWrittenExplicitelyBySender (false);
}
2015-12-23 11:05:32 +01:00
/***** Begin form to select recipients and write the message *****/
Frm_BeginForm (ActRcvMsgUsr);
if (Messages->Reply.IsReply)
{
Par_PutParChar ("IsReply",'Y');
ParCod_PutPar (ParCod_Msg,Messages->Reply.OriginalMsgCod);
}
if (Gbl.Usrs.Other.UsrDat.UsrCod > 0)
{
Usr_PutParOtherUsrCodEncrypted (Gbl.Usrs.Other.UsrDat.EnUsrCod);
if (Messages->ShowOnlyOneRecipient)
Par_PutParChar ("ShowOnlyOneRecipient",'Y');
}
2014-12-01 23:55:08 +01:00
/***** Begin table *****/
HTM_TABLE_BeginCenterPadding (2);
2015-12-22 14:00:36 +01:00
/***** "To:" section (recipients) *****/
HTM_TR_Begin (NULL);
/* Label */
Frm_LabelColumn ("Frm_C1 RT","",Txt_MSG_To);
/* Data */
HTM_TD_Begin ("class=\"Frm_C2 LT\"");
if (Messages->ShowOnlyOneRecipient)
/***** Show only one user as recipient *****/
Msg_ShowOneUniqueRecipient ();
else
{
/***** Show potential recipients *****/
HTM_TABLE_Begin ("TBL_SCROLL_C2");
if (ShowUsrsInCrs)
Usr_ListUsersToSelect (&Gbl.Usrs.Selected);
Msg_WriteFormUsrsIDsOrNicksOtherRecipients (); // Other users (nicknames)
HTM_TABLE_End ();
}
HTM_TD_End ();
HTM_TR_End ();
2016-07-04 17:52:09 +02:00
/***** Subject and content sections *****/
Msg_WriteFormSubjectAndContentMsgToUsrs (Messages,Content);
2014-12-01 23:55:08 +01:00
/***** End table *****/
HTM_TABLE_End ();
2015-04-11 13:28:43 +02:00
/***** Help for text editor and send button *****/
Lay_HelpPlainEditor ();
2016-04-09 18:36:39 +02:00
/***** Attached image (optional) *****/
if (asprintf (&ClassInput,"MSG_MED_INPUT INPUT_%s",The_GetSuffix ()) < 0)
Err_NotEnoughMemoryExit ();
Med_PutMediaUploader (-1,ClassInput);
free (ClassInput);
2016-04-10 14:09:50 +02:00
/***** Send button *****/
Btn_PutCreateButton (Txt_Send_message);
2015-04-11 13:28:43 +02:00
/***** End form *****/
Frm_EndForm ();
2015-10-02 01:04:28 +02:00
2017-06-12 14:16:33 +02:00
/***** End box *****/
2019-10-25 22:48:34 +02:00
Box_BoxEnd ();
2014-12-01 23:55:08 +01:00
/***** Free memory used by the list of nicknames *****/
Usr_FreeListOtherRecipients ();
/***** Free memory used for by the lists of users *****/
2016-07-04 18:17:53 +02:00
if (GetUsrsInCrs)
{
2017-05-18 19:13:41 +02:00
Usr_FreeUsrsList (Rol_TCH);
2017-05-22 14:52:11 +02:00
Usr_FreeUsrsList (Rol_NET);
2017-05-18 19:13:41 +02:00
Usr_FreeUsrsList (Rol_STD);
2016-07-04 18:17:53 +02:00
}
2014-12-01 23:55:08 +01:00
2016-07-04 14:03:04 +02:00
/***** Free memory used by list of selected users' codes *****/
2019-11-15 03:34:48 +01:00
Usr_FreeListsSelectedEncryptedUsrsCods (&Gbl.Usrs.Selected);
2014-12-01 23:55:08 +01:00
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
}
2015-12-23 13:20:58 +01:00
/*****************************************************************************/
/********** Put contextual link to show more potential recipients ************/
/*****************************************************************************/
static void Msg_PutLinkToShowMorePotentialRecipients (struct Msg_Messages *Messages)
2015-12-23 13:20:58 +01:00
{
extern const char *Txt_Show_more_recipients;
2019-10-24 09:46:20 +02:00
/***** Contextual menu *****/
Mnu_ContextMenuBegin ();
Lay_PutContextualLinkIconText (ActReqMsgUsr,NULL,
Msg_PutParsShowMorePotentialRecipients,Messages,
"users.svg",Ico_BLACK,
Txt_Show_more_recipients,
"CopyMessageToHiddenFields();");
2019-10-24 09:46:20 +02:00
Mnu_ContextMenuEnd ();
2015-12-23 13:20:58 +01:00
}
2015-12-23 11:05:32 +01:00
/*****************************************************************************/
/************ Put parameters to show more potential recipients ***************/
/*****************************************************************************/
static void Msg_PutParsShowMorePotentialRecipients (void *Messages)
2015-12-23 11:05:32 +01:00
{
if (Messages)
2015-12-23 11:05:32 +01:00
{
if (((struct Msg_Messages *) Messages)->Reply.IsReply)
{
Par_PutParChar ("IsReply",'Y');
ParCod_PutPar (ParCod_Msg,((struct Msg_Messages *) Messages)->Reply.OriginalMsgCod);
}
if (Gbl.Usrs.Other.UsrDat.UsrCod > 0)
Usr_PutParOtherUsrCodEncrypted (Gbl.Usrs.Other.UsrDat.EnUsrCod);
2016-06-30 21:05:06 +02:00
/***** Hidden params to send subject and content *****/
Msg_PutParsSubjectAndContent ();
}
2016-07-01 14:40:01 +02:00
}
2019-04-11 09:55:35 +02:00
/*****************************************************************************/
/***************** Put parameters when writing a message *********************/
/*****************************************************************************/
static void Msg_PutParsWriteMsg (void *Messages)
2019-04-11 09:55:35 +02:00
{
2020-04-08 19:42:03 +02:00
if (Messages)
2019-04-11 09:55:35 +02:00
{
Usr_PutParSelectedUsrsCods (&Gbl.Usrs.Selected);
Msg_PutParOtherRecipients ();
Msg_PutParsSubjectAndContent ();
2020-04-08 19:42:03 +02:00
if (((struct Msg_Messages *) Messages)->Reply.IsReply)
2020-03-26 02:54:30 +01:00
{
Par_PutParChar ("IsReply",'Y');
ParCod_PutPar (ParCod_Msg,((struct Msg_Messages *) Messages)->Reply.OriginalMsgCod);
2020-03-26 02:54:30 +01:00
}
if (Gbl.Usrs.Other.UsrDat.UsrCod > 0)
{
Usr_PutParOtherUsrCodEncrypted (Gbl.Usrs.Other.UsrDat.EnUsrCod);
2020-04-08 19:42:03 +02:00
if (((struct Msg_Messages *) Messages)->ShowOnlyOneRecipient)
Par_PutParChar ("ShowOnlyOneRecipient",'Y');
2020-03-26 02:54:30 +01:00
}
2019-04-11 09:55:35 +02:00
}
}
2016-07-01 14:40:01 +02:00
/*****************************************************************************/
/********** Put hidden parameters with message subject and content ***********/
/*****************************************************************************/
static void Msg_PutParsSubjectAndContent (void)
2016-07-01 14:40:01 +02:00
{
2016-07-01 01:21:34 +02:00
/***** Hidden params to send subject and content.
When the user edit the subject or the content,
they are copied here. *****/
Par_PutParString (NULL,"HiddenSubject","");
Par_PutParString (NULL,"HiddenContent","");
2015-12-23 11:05:32 +01:00
}
2015-12-23 13:20:58 +01:00
/*****************************************************************************/
/************ Put parameters to show more potential recipients ***************/
/*****************************************************************************/
static void Msg_ShowOneUniqueRecipient (void)
{
static const char *ClassPhoto[PhoSha_NUM_SHAPES] =
{
[PhoSha_SHAPE_CIRCLE ] = "PHOTOC21x28",
[PhoSha_SHAPE_ELLIPSE ] = "PHOTOE21x28",
[PhoSha_SHAPE_OVAL ] = "PHOTOO21x28",
[PhoSha_SHAPE_RECTANGLE] = "PHOTOR21x28",
};
2015-12-23 13:20:58 +01:00
/***** Show user's photo *****/
Pho_ShowUsrPhotoIfAllowed (&Gbl.Usrs.Other.UsrDat,
ClassPhoto[Gbl.Prefs.PhotoShape],Pho_ZOOM);
2015-12-23 13:20:58 +01:00
/****** Write user's IDs ******/
HTM_DIV_Begin ("class=\"MSG_TO_ONE_RCP %s_%s\"",
Gbl.Usrs.Other.UsrDat.Accepted ? "DAT_SMALL_NOBR_STRONG" :
"DAT_SMALL_NOBR",
The_GetSuffix ());
ID_WriteUsrIDs (&Gbl.Usrs.Other.UsrDat,NULL);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2015-12-23 13:20:58 +01:00
/***** Write user's name *****/
HTM_DIV_Begin ("class=\"MSG_TO_ONE_RCP %s_%s\"",
Gbl.Usrs.Other.UsrDat.Accepted ? "DAT_SMALL_NOBR_STRONG" :
"DAT_SMALL_NOBR",
The_GetSuffix ());
HTM_Txt (Gbl.Usrs.Other.UsrDat.FullName);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2015-12-24 00:31:45 +01:00
/***** Hidden parameter with user's nickname *****/
Msg_PutParAnotherRecipient (&Gbl.Usrs.Other.UsrDat);
2015-12-23 13:20:58 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************** Nicknames of recipients of a message to users ****************/
/*****************************************************************************/
2015-12-22 13:22:35 +01:00
static void Msg_WriteFormUsrsIDsOrNicksOtherRecipients (void)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_Other_recipients;
extern const char *Txt_Recipients;
extern const char *Txt_nicks_emails_or_IDs_separated_by_commas;
char Nickname[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1];
2019-10-12 19:10:32 +02:00
unsigned ColSpan;
bool StdsAndTchsWritten = Gbl.Hierarchy.Level == Hie_CRS && // Course selected
(Gbl.Usrs.Me.IBelongToCurrent[Hie_CRS] || // I belong to it
2017-06-04 18:18:54 +02:00
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
2015-12-24 00:31:45 +01:00
2016-12-27 13:56:44 +01:00
/***** How many columns? *****/
if (StdsAndTchsWritten)
2019-10-12 19:10:32 +02:00
ColSpan = Usr_GetColumnsForSelectUsrs ();
2016-12-27 13:56:44 +01:00
else
2019-10-12 19:10:32 +02:00
ColSpan = 1;
2016-12-27 13:56:44 +01:00
/***** Title *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
HTM_TH_Span_Begin (HTM_HEAD_LEFT,1,ColSpan,"BG_HIGHLIGHT");
HTM_LABEL_Begin ("for=\"OtherRecipients\"");
HTM_TxtColon (StdsAndTchsWritten ? Txt_Other_recipients :
Txt_Recipients);
HTM_LABEL_End ();
HTM_TH_End ();
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
2016-11-16 23:19:52 +01:00
/***** Textarea with users' @nicknames, emails or IDs *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
HTM_TD_Begin ("colspan=\"%u\" class=\"LM\"",ColSpan);
HTM_TEXTAREA_Begin ("id=\"OtherRecipients\" name=\"OtherRecipients\""
" class=\"Frm_C2_INPUT INPUT_%s\" rows=\"2\""
" placeholder=\"%s\"",
The_GetSuffix (),
Txt_nicks_emails_or_IDs_separated_by_commas);
if (Gbl.Usrs.ListOtherRecipients[0])
HTM_Txt (Gbl.Usrs.ListOtherRecipients);
else if (Gbl.Usrs.Other.UsrDat.UsrCod > 0) // If there is a recipient
// and there's no list of explicit recipients,
// write @nickname of original sender
{
Nck_DB_GetNicknameFromUsrCod (Gbl.Usrs.Other.UsrDat.UsrCod,Nickname);
if (Nickname[0])
HTM_TxtF ("@%s",Nickname);
}
HTM_TEXTAREA_End ();
HTM_TD_End ();
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****** Write form fields with subject and content of a message to users *****/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_WriteFormSubjectAndContentMsgToUsrs (struct Msg_Messages *Messages,
char Content[Cns_MAX_BYTES_LONG_TEXT + 1])
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_MSG_Subject;
2017-04-19 14:27:52 +02:00
extern const char *Txt_MSG_Content;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Original_message;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2016-06-30 21:05:06 +02:00
long MsgCod;
2020-04-11 15:21:30 +02:00
bool SubjectAndContentComeFromForm = (Messages->Subject[0] || Content[0]);
2014-12-01 23:55:08 +01:00
2016-06-30 21:05:06 +02:00
/***** Get possible code (of original message if it's a reply) *****/
MsgCod = ParCod_GetPar (ParCod_Msg);
2016-06-30 21:05:06 +02:00
2016-12-24 14:05:59 +01:00
/***** Message subject *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
/* Label */
Frm_LabelColumn ("Frm_C1 RT","MsgSubject",Txt_MSG_Subject);
2019-10-07 17:36:41 +02:00
/* Data */
HTM_TD_Begin ("class=\"Frm_C2 LT\"");
HTM_TEXTAREA_Begin ("id=\"MsgSubject\" name=\"Subject\""
" class=\"Frm_C2_INPUT INPUT_%s\" rows=\"2\"",
The_GetSuffix ());
2014-12-01 23:55:08 +01:00
/* If message is a reply ==> get original message */
if (MsgCod > 0) // It's a reply
2016-07-01 01:21:34 +02:00
{
if (!SubjectAndContentComeFromForm)
{
/* Get subject and content of message from database */
if (Msg_DB_GetSubjectAndContent (&mysql_res,MsgCod) != 1)
Err_WrongMessageExit ();
row = mysql_fetch_row (mysql_res);
/* Get subject (row[0]) and content (row[1]) */
Str_Copy (Messages->Subject,row[0],sizeof (Messages->Subject) - 1);
Str_Copy (Content ,row[1],Cns_MAX_BYTES_LONG_TEXT);
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
}
/* Write subject */
if (!SubjectAndContentComeFromForm)
HTM_Txt ("Re: ");
HTM_Txt (Messages->Subject);
HTM_TEXTAREA_End ();
HTM_TD_End ();
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
/***** Message content *****/
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
/* Label */
Frm_LabelColumn ("Frm_C1 RT","MsgContent",Txt_MSG_Content);
2019-10-07 17:36:41 +02:00
/* Data */
HTM_TD_Begin ("class=\"Frm_C2 LT\"");
HTM_TEXTAREA_Begin ("id=\"MsgContent\" name=\"Content\""
" class=\"Frm_C2_INPUT INPUT_%s\""
" rows=\"20\"",
The_GetSuffix ());
2016-07-01 12:57:35 +02:00
/* Begin textarea with a '\n', that will be not visible in textarea.
When Content is "\nLorem ipsum" (a white line before "Lorem ipsum"),
if we don't put the initial '\n' ==> the form will be sent starting
by "Lorem", without the white line */
HTM_Txt ("\n");
2016-07-01 12:57:35 +02:00
if (!SubjectAndContentComeFromForm)
HTM_TxtF ("\n\n----- %s -----\n",Txt_Original_message);
2016-07-01 12:57:35 +02:00
Msg_WriteMsgContent (Content,false,true);
HTM_TEXTAREA_End ();
HTM_TD_End ();
}
else // It's not a reply
{
/* End message subject */
HTM_Txt (Messages->Subject);
2019-10-31 17:42:05 +01:00
HTM_TEXTAREA_End ();
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
/***** Message content *****/
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
/* Label */
Frm_LabelColumn ("Frm_C1 RT","MsgContent",Txt_MSG_Content);
2019-10-07 17:36:41 +02:00
/* Data */
HTM_TD_Begin ("class=\"Frm_C2 LT\"");
HTM_TEXTAREA_Begin ("id=\"MsgContent\" name=\"Content\""
" class=\"Frm_C2_INPUT INPUT_%s\""
" rows=\"20\"",
The_GetSuffix ());
2019-10-31 17:42:05 +01:00
/* Begin textarea with a '\n', that will be not visible in textarea.
When Content is "\nLorem ipsum" (a white line before "Lorem ipsum"),
if we don't put the initial '\n' ==> the form will be sent starting
by "Lorem", without the white line */
HTM_TxtF ("\n%s",Content);
HTM_TEXTAREA_End ();
HTM_TD_End ();
}
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
2015-03-03 19:21:59 +01:00
/*****************************************************************************/
/********* Put hidden parameter for another recipient (one nickname) *********/
/*****************************************************************************/
static void Msg_PutParAnotherRecipient (const struct Usr_Data *UsrDat)
2015-03-03 19:21:59 +01:00
{
char NickWithArr[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
2015-03-03 19:21:59 +01:00
snprintf (NickWithArr,sizeof (NickWithArr),"@%s",UsrDat->Nickname);
Par_PutParString (NULL,"OtherRecipients",NickWithArr);
2015-03-03 19:21:59 +01:00
}
/*****************************************************************************/
/********* Put hidden parameter for another recipient (one nickname) *********/
/*****************************************************************************/
static void Msg_PutParOtherRecipients (void)
2015-03-03 19:21:59 +01:00
{
if (Gbl.Usrs.ListOtherRecipients)
if (Gbl.Usrs.ListOtherRecipients[0])
Par_PutParString (NULL,"OtherRecipients",Gbl.Usrs.ListOtherRecipients);
2015-03-03 19:21:59 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/********************** Receive a new message from a user ********************/
/*****************************************************************************/
void Msg_RecMsgFromUsr (void)
{
extern const char *Txt_You_can_not_send_a_message_to_so_many_recipients_;
extern const char *Txt_You_must_select_one_ore_more_recipients;
extern const char *Txt_message_not_sent_to_X;
2016-11-16 23:19:52 +01:00
extern const char *Txt_message_sent_to_X_notified_by_email;
extern const char *Txt_message_sent_to_X_not_notified_by_email;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Error_getting_data_from_a_recipient;
extern const char *Txt_The_message_has_not_been_sent_to_any_recipient;
extern const char *Txt_The_message_has_been_sent_to_1_recipient;
extern const char *Txt_The_message_has_been_sent_to_X_recipients;
extern const char *Txt_There_have_been_X_errors_in_sending_the_message;
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
2014-12-01 23:55:08 +01:00
bool IsReply;
bool RecipientHasBannedMe;
bool Replied = false;
2015-12-22 13:22:35 +01:00
long OriginalMsgCod = -1L; // Initialized to avoid warning
2014-12-01 23:55:08 +01:00
const char *Ptr;
unsigned NumRecipients;
unsigned NumRecipientsToBeNotifiedByEMail = 0;
struct Usr_Data UsrDstData;
2014-12-01 23:55:08 +01:00
int NumErrors = 0;
2015-12-22 13:22:35 +01:00
long NewMsgCod = -1L; // Initiliazed to avoid warning
2014-12-01 23:55:08 +01:00
bool MsgAlreadyInserted = false;
bool CreateNotif;
bool NotifyByEmail;
2017-01-17 03:10:43 +01:00
char Content[Cns_MAX_BYTES_LONG_TEXT + 1];
2021-02-11 00:58:53 +01:00
struct Med_Media Media;
2014-12-01 23:55:08 +01:00
bool Error = false;
2020-04-11 15:21:30 +02:00
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-01 23:55:08 +01:00
/***** Get data from form *****/
2016-06-30 21:05:06 +02:00
/* Get subject */
Par_GetParHTML ("Subject",Messages.Subject,Cns_MAX_BYTES_SUBJECT);
2014-12-01 23:55:08 +01:00
2016-06-30 21:05:06 +02:00
/* Get body */
2014-12-01 23:55:08 +01:00
Par_GetParAndChangeFormat ("Content",Content,Cns_MAX_BYTES_LONG_TEXT,
Str_DONT_CHANGE,Str_DONT_REMOVE_SPACES);
2014-12-01 23:55:08 +01:00
/* Get parameter that indicates if the message is a reply to a previous message */
if ((IsReply = Par_GetParBool ("IsReply")))
2014-12-01 23:55:08 +01:00
/* Get original message code */
OriginalMsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2014-12-01 23:55:08 +01:00
/* Get user's code of possible preselected recipient */
Usr_GetParOtherUsrCodEncryptedAndGetListIDs ();
2014-12-01 23:55:08 +01:00
2015-09-30 23:10:15 +02:00
/* Get lists of selected users */
2019-11-15 03:34:48 +01:00
Usr_GetListsSelectedEncryptedUsrsCods (&Gbl.Usrs.Selected);
2014-12-01 23:55:08 +01:00
/* Get list of users' IDs or nicknames written explicitely */
Error = Usr_GetListMsgRecipientsWrittenExplicitelyBySender (true);
2015-12-24 00:31:45 +01:00
/***** Check number of recipients *****/
2019-11-15 03:34:48 +01:00
if ((NumRecipients = Usr_CountNumUsrsInListOfSelectedEncryptedUsrCods (&Gbl.Usrs.Selected)))
2014-12-01 23:55:08 +01:00
{
2017-06-04 18:18:54 +02:00
if (Gbl.Usrs.Me.Role.Logged == Rol_STD &&
2014-12-01 23:55:08 +01:00
NumRecipients > Cfg_MAX_RECIPIENTS)
{
/* Write warning message */
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_WARNING,Txt_You_can_not_send_a_message_to_so_many_recipients_);
2014-12-01 23:55:08 +01:00
Error = true;
}
}
else // No recipients selected
{
/* Write warning message */
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_recipients);
2014-12-01 23:55:08 +01:00
Error = true;
}
/***** If error in list of recipients, show again the form used to write a message *****/
if (Error)
{
/* Show the form again, with the subject and the message filled */
Str_ChangeFormat (Str_FROM_FORM,Str_TO_TEXT,
Content,Cns_MAX_BYTES_LONG_TEXT,Str_REMOVE_SPACES);
Msg_PutFormMsgUsrs (ActRcvMsgUsr,&Messages,Content);
2014-12-01 23:55:08 +01:00
return;
}
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDstData);
2016-04-10 14:09:50 +02:00
/***** Initialize image *****/
2019-03-02 21:49:11 +01:00
Med_MediaConstructor (&Media);
2016-04-10 14:09:50 +02:00
/***** Get attached image (action, file and title) *****/
2019-03-02 21:49:11 +01:00
Media.Width = Msg_IMAGE_SAVED_MAX_WIDTH;
Media.Height = Msg_IMAGE_SAVED_MAX_HEIGHT;
Media.Quality = Msg_IMAGE_SAVED_QUALITY;
2020-03-17 00:35:11 +01:00
Med_GetMediaFromForm (-1L,-1L,-1,&Media,NULL,NULL);
2019-03-17 14:47:58 +01:00
Ale_ShowAlerts (NULL);
2016-04-10 14:09:50 +02:00
2019-03-11 13:33:34 +01:00
/***** Loop over the list Gbl.Usrs.Selected.List[Rol_UNK], that holds the list of the
2014-12-01 23:55:08 +01:00
recipients, creating a received message for each recipient *****/
Str_ChangeFormat (Str_FROM_FORM,Str_TO_RIGOROUS_HTML,
Content,Cns_MAX_BYTES_LONG_TEXT,Str_DONT_REMOVE_SPACES);
2019-03-11 13:33:34 +01:00
Ptr = Gbl.Usrs.Selected.List[Rol_UNK];
2014-12-01 23:55:08 +01:00
NumRecipients = 0;
while (*Ptr)
{
Par_GetNextStrUntilSeparParMult (&Ptr,UsrDstData.EnUsrCod,
Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64);
2014-12-01 23:55:08 +01:00
Usr_GetUsrCodFromEncryptedUsrCod (&UsrDstData);
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDstData, // Get recipient's data from database
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CRS))
2014-12-01 23:55:08 +01:00
{
/***** Check if recipient has banned me *****/
RecipientHasBannedMe = Msg_DB_CheckIfUsrIsBanned (Gbl.Usrs.Me.UsrDat.UsrCod,UsrDstData.UsrCod);
2014-12-01 23:55:08 +01:00
if (RecipientHasBannedMe)
/***** Show an alert indicating that the message has not been sent successfully *****/
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_WARNING,Txt_message_not_sent_to_X,
UsrDstData.FullName);
2014-12-01 23:55:08 +01:00
else
{
/***** Create message *****/
if (!MsgAlreadyInserted)
{
// The message is inserted only once in the table of messages sent
2020-04-11 15:21:30 +02:00
NewMsgCod = Msg_InsertNewMsg (Messages.Subject,Content,&Media);
2014-12-01 23:55:08 +01:00
MsgAlreadyInserted = true;
}
/***** If this recipient is the original sender of a message been replied, set Replied to true *****/
2015-12-22 13:22:35 +01:00
Replied = (IsReply &&
UsrDstData.UsrCod == Gbl.Usrs.Other.UsrDat.UsrCod);
2014-12-01 23:55:08 +01:00
2016-11-16 23:19:52 +01:00
/***** This received message must be notified by email? *****/
2019-03-19 13:22:14 +01:00
CreateNotif = (UsrDstData.NtfEvents.CreateNotif & (1 << Ntf_EVENT_MESSAGE));
2014-12-01 23:55:08 +01:00
NotifyByEmail = CreateNotif &&
(UsrDstData.UsrCod != Gbl.Usrs.Me.UsrDat.UsrCod) &&
2019-03-19 13:22:14 +01:00
(UsrDstData.NtfEvents.SendEmail & (1 << Ntf_EVENT_MESSAGE));
2014-12-01 23:55:08 +01:00
/***** Create the received message for this recipient
2017-01-19 03:15:35 +01:00
and increment number of new messages received by this recipient *****/
Msg_DB_CreateRcvMsg (NewMsgCod,UsrDstData.UsrCod,NotifyByEmail);
2014-12-01 23:55:08 +01:00
/***** Create notification for this recipient.
2016-11-16 23:19:52 +01:00
If this recipient wants to receive notifications by -mail,
activate the sending of a notification *****/
2014-12-01 23:55:08 +01:00
if (CreateNotif)
Ntf_DB_StoreNotifyEventToUsr (Ntf_EVENT_MESSAGE,UsrDstData.UsrCod,NewMsgCod,
(Ntf_Status_t) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL :
0),
Gbl.Hierarchy.Node[Hie_INS].HieCod,
Gbl.Hierarchy.Node[Hie_CTR].HieCod,
Gbl.Hierarchy.Node[Hie_DEG].HieCod,
Gbl.Hierarchy.Node[Hie_CRS].HieCod);
2014-12-01 23:55:08 +01:00
/***** Show an alert indicating that the message has been sent successfully *****/
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,NotifyByEmail ? Txt_message_sent_to_X_notified_by_email :
Txt_message_sent_to_X_not_notified_by_email,
UsrDstData.FullName);
2014-12-01 23:55:08 +01:00
/***** Increment number of recipients *****/
if (NotifyByEmail)
NumRecipientsToBeNotifiedByEMail++;
NumRecipients++;
}
}
else
{
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_ERROR,Txt_Error_getting_data_from_a_recipient);
2014-12-01 23:55:08 +01:00
NumErrors++;
}
}
2016-04-10 14:09:50 +02:00
/***** Free image *****/
2019-03-02 21:49:11 +01:00
Med_MediaDestructor (&Media);
2016-04-10 14:09:50 +02:00
2014-12-01 23:55:08 +01:00
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDstData);
/***** Free memory *****/
/* Free memory used for list of users */
Usr_FreeListOtherRecipients ();
2019-11-15 03:34:48 +01:00
Usr_FreeListsSelectedEncryptedUsrsCods (&Gbl.Usrs.Selected);
2014-12-01 23:55:08 +01:00
/***** Update received message setting Replied field to true *****/
if (Replied)
Msg_DB_SetRcvMsgAsReplied (OriginalMsgCod);
2014-12-01 23:55:08 +01:00
/***** Write final message *****/
if (NumRecipients)
{
if (NumRecipients == 1)
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_The_message_has_been_sent_to_1_recipient);
2014-12-01 23:55:08 +01:00
else
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_The_message_has_been_sent_to_X_recipients,
(unsigned) NumRecipients);
2014-12-01 23:55:08 +01:00
}
else
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_WARNING,Txt_The_message_has_not_been_sent_to_any_recipient);
2014-12-01 23:55:08 +01:00
/***** Show alert about errors on sending message *****/
if (NumErrors > 1)
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_ERROR,Txt_There_have_been_X_errors_in_sending_the_message,
(unsigned) NumErrors);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Request deletion of all received messages *****************/
/*****************************************************************************/
void Msg_ReqDelAllRecMsgs (void)
{
extern const char *Txt_Do_you_really_want_to_delete_the_unread_messages_received_from_USER_X_from_COURSE_Y_related_to_CONTENT_Z;
extern const char *Txt_any_user;
extern const char *Txt_Do_you_really_want_to_delete_all_messages_received_from_USER_X_from_COURSE_Y_related_to_CONTENT_Z;
extern const char *Txt_Do_you_really_want_to_delete_the_unread_messages_received_from_USER_X_from_COURSE_Y;
extern const char *Txt_Do_you_really_want_to_delete_all_messages_received_from_USER_X_from_COURSE_Y;
extern const char *Txt_Delete_messages_received;
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-01 23:55:08 +01:00
/***** Get parameters *****/
Msg_GetParMsgsCrsCod (&Messages);
Msg_GetParFilterFromTo (&Messages);
Msg_GetParFilterContent (&Messages);
Messages.ShowOnlyUnreadMsgs = Msg_GetParOnlyUnreadMsgs ();
2014-12-01 23:55:08 +01:00
2017-04-28 01:02:44 +02:00
/***** Show question and button to remove messages received *****/
/* Begin alert */
2020-04-11 15:21:30 +02:00
if (Messages.FilterContent[0])
2014-12-01 23:55:08 +01:00
{
2020-04-11 15:21:30 +02:00
if (Messages.ShowOnlyUnreadMsgs)
Ale_ShowAlertAndButtonBegin (Ale_QUESTION,Txt_Do_you_really_want_to_delete_the_unread_messages_received_from_USER_X_from_COURSE_Y_related_to_CONTENT_Z,
2020-04-11 15:21:30 +02:00
Messages.FilterFromTo[0] ? Messages.FilterFromTo :
Txt_any_user,
Messages.FilterCrsShrtName,Messages.FilterContent);
2014-12-01 23:55:08 +01:00
else
Ale_ShowAlertAndButtonBegin (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_received_from_USER_X_from_COURSE_Y_related_to_CONTENT_Z,
2020-04-11 15:21:30 +02:00
Messages.FilterFromTo[0] ? Messages.FilterFromTo :
Txt_any_user,
Messages.FilterCrsShrtName,Messages.FilterContent);
2014-12-01 23:55:08 +01:00
}
else
{
2020-04-11 15:21:30 +02:00
if (Messages.ShowOnlyUnreadMsgs)
Ale_ShowAlertAndButtonBegin (Ale_QUESTION,Txt_Do_you_really_want_to_delete_the_unread_messages_received_from_USER_X_from_COURSE_Y,
2020-04-11 15:21:30 +02:00
Messages.FilterFromTo[0] ? Messages.FilterFromTo :
Txt_any_user,
Messages.FilterCrsShrtName);
2014-12-01 23:55:08 +01:00
else
Ale_ShowAlertAndButtonBegin (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_received_from_USER_X_from_COURSE_Y,
2020-04-11 15:21:30 +02:00
Messages.FilterFromTo[0] ? Messages.FilterFromTo :
Txt_any_user,
Messages.FilterCrsShrtName);
2014-12-01 23:55:08 +01:00
}
2017-04-28 01:02:44 +02:00
/* Show received messages again */
2020-09-26 17:20:01 +02:00
Messages.TypeOfMessages = Msg_RECEIVED;
Msg_ShowSntOrRcvMessages (&Messages);
2015-10-08 01:06:46 +02:00
2017-04-28 01:02:44 +02:00
/* End alert */
Ale_ShowAlertAndButtonEnd (ActDelAllRcvMsg,NULL,NULL,
Msg_PutParsMsgsFilters,&Messages,
2017-06-11 19:02:40 +02:00
Btn_REMOVE_BUTTON,Txt_Delete_messages_received);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Request deletion of all sent messages *******************/
/*****************************************************************************/
void Msg_ReqDelAllSntMsgs (void)
{
extern const char *Txt_Do_you_really_want_to_delete_all_messages_sent_to_USER_X_from_COURSE_Y_related_to_CONTENT_Z;
extern const char *Txt_any_user;
extern const char *Txt_Do_you_really_want_to_delete_all_messages_sent_to_USER_X_from_COURSE_Y;
extern const char *Txt_Delete_messages_sent;
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-01 23:55:08 +01:00
/***** Get parameters *****/
Msg_GetParMsgsCrsCod (&Messages);
Msg_GetParFilterFromTo (&Messages);
Msg_GetParFilterContent (&Messages);
2014-12-01 23:55:08 +01:00
2017-04-28 01:02:44 +02:00
/***** Show question and button to remove messages received *****/
/* Begin alert */
2020-04-11 15:21:30 +02:00
if (Messages.FilterContent[0])
Ale_ShowAlertAndButtonBegin (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_sent_to_USER_X_from_COURSE_Y_related_to_CONTENT_Z,
2020-04-11 15:21:30 +02:00
Messages.FilterFromTo[0] ? Messages.FilterFromTo :
Txt_any_user,
Messages.FilterCrsShrtName,Messages.FilterContent);
2014-12-01 23:55:08 +01:00
else
Ale_ShowAlertAndButtonBegin (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_sent_to_USER_X_from_COURSE_Y,
2020-04-11 15:21:30 +02:00
Messages.FilterFromTo[0] ? Messages.FilterFromTo :
Txt_any_user,
Messages.FilterCrsShrtName);
2015-10-08 01:06:46 +02:00
2017-04-28 01:02:44 +02:00
/* Show sent messages again */
2020-09-26 17:20:01 +02:00
Messages.TypeOfMessages = Msg_SENT;
Msg_ShowSntOrRcvMessages (&Messages);
2015-10-08 01:06:46 +02:00
2017-04-28 01:02:44 +02:00
/* End alert */
Ale_ShowAlertAndButtonEnd (ActDelAllSntMsg,NULL,NULL,
Msg_PutParsMsgsFilters,&Messages,
2017-06-11 19:02:40 +02:00
Btn_REMOVE_BUTTON,Txt_Delete_messages_sent);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Delete all received messages ************************/
/*****************************************************************************/
void Msg_DelAllRecMsgs (void)
{
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
char FilterFromToSubquery[Msg_DB_MAX_BYTES_MESSAGES_QUERY + 1];
2014-12-01 23:55:08 +01:00
unsigned long NumMsgs;
2020-04-11 15:21:30 +02:00
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-01 23:55:08 +01:00
/***** Get parameters *****/
Msg_GetParMsgsCrsCod (&Messages);
Msg_GetParFilterFromTo (&Messages);
Msg_GetParFilterContent (&Messages);
Messages.ShowOnlyUnreadMsgs = Msg_GetParOnlyUnreadMsgs ();
Msg_DB_MakeFilterFromToSubquery (&Messages,FilterFromToSubquery);
2014-12-01 23:55:08 +01:00
/***** Delete messages *****/
2020-11-25 01:50:13 +01:00
Messages.TypeOfMessages = Msg_RECEIVED;
NumMsgs = Msg_RemoveSomeRecOrSntMsgsUsr (&Messages,
Gbl.Usrs.Me.UsrDat.UsrCod,
FilterFromToSubquery);
2014-12-01 23:55:08 +01:00
Msg_ShowNumMsgsDeleted (NumMsgs);
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/************************* Delete all sent messages **************************/
/*****************************************************************************/
void Msg_DelAllSntMsgs (void)
{
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
char FilterFromToSubquery[Msg_DB_MAX_BYTES_MESSAGES_QUERY + 1];
2014-12-01 23:55:08 +01:00
unsigned long NumMsgs;
2020-04-11 15:21:30 +02:00
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-01 23:55:08 +01:00
/***** Get parameters *****/
Msg_GetParMsgsCrsCod (&Messages);
Msg_GetParFilterFromTo (&Messages);
Msg_GetParFilterContent (&Messages);
Msg_DB_MakeFilterFromToSubquery (&Messages,FilterFromToSubquery);
2014-12-01 23:55:08 +01:00
/***** Delete messages *****/
2020-11-25 01:50:13 +01:00
Messages.TypeOfMessages = Msg_SENT;
NumMsgs = Msg_RemoveSomeRecOrSntMsgsUsr (&Messages,
Gbl.Usrs.Me.UsrDat.UsrCod,
FilterFromToSubquery);
2014-12-01 23:55:08 +01:00
Msg_ShowNumMsgsDeleted (NumMsgs);
Msg_ShowSntMsgs ();
}
/*****************************************************************************/
/************* Write number of messages that have been deleted ***************/
/*****************************************************************************/
static void Msg_ShowNumMsgsDeleted (unsigned NumMsgs)
{
extern const char *Txt_One_message_has_been_deleted;
extern const char *Txt_X_messages_have_been_deleted;
if (NumMsgs == 1)
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_One_message_has_been_deleted);
2014-12-01 23:55:08 +01:00
else
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_X_messages_have_been_deleted,
NumMsgs);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************** Get parameter with course origin of messages ***************/
/*****************************************************************************/
static void Msg_GetParMsgsCrsCod (struct Msg_Messages *Messages)
2014-12-01 23:55:08 +01:00
{
extern bool (*Hie_GetDataByCod[Hie_NUM_LEVELS]) (struct Hie_Node *Node);
2014-12-01 23:55:08 +01:00
extern const char *Txt_any_course;
struct Hie_Node Crs;
2014-12-01 23:55:08 +01:00
if ((Messages->FilterCrsCod = ParCod_GetPar (ParCod_OthCrs)) > 0) // If origin course specified
2014-12-01 23:55:08 +01:00
{
/* Get data of course */
Crs.HieCod = Messages->FilterCrsCod;
Hie_GetDataByCod[Hie_CRS] (&Crs);
2014-12-01 23:55:08 +01:00
}
Str_Copy (Messages->FilterCrsShrtName,Messages->FilterCrsCod > 0 ? Crs.ShrtName :
Txt_any_course,
sizeof (Messages->FilterCrsShrtName) - 1);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Get parameter with "from"/"to" filter ********************/
/*****************************************************************************/
static void Msg_GetParFilterFromTo (struct Msg_Messages *Messages)
2014-12-01 23:55:08 +01:00
{
/***** Get "from"/"to" filter *****/
Par_GetParText ("FilterFromTo",Messages->FilterFromTo,
2017-03-07 19:55:29 +01:00
Usr_MAX_BYTES_FULL_NAME);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Get parameter with content filter *********************/
/*****************************************************************************/
static void Msg_GetParFilterContent (struct Msg_Messages *Messages)
2014-12-01 23:55:08 +01:00
{
/***** Get content filter *****/
Par_GetParText ("FilterContent",Messages->FilterContent,
2017-03-07 19:55:29 +01:00
Msg_MAX_BYTES_FILTER_CONTENT);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************************** Delete a sent message ************************/
/*****************************************************************************/
void Msg_DelSntMsg (void)
{
extern const char *Txt_Message_deleted;
long MsgCod;
/***** Get the code of the message to delete *****/
MsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2014-12-01 23:55:08 +01:00
/***** Delete the message *****/
/* Delete the sent message */
Msg_MoveSntMsgToDeleted (MsgCod);
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_Message_deleted);
2014-12-01 23:55:08 +01:00
/* Show the remaining messages */
Msg_ShowSntMsgs ();
}
/*****************************************************************************/
/************************* Delete a received message *************************/
/*****************************************************************************/
void Msg_DelRecMsg (void)
{
extern const char *Txt_Message_deleted;
long MsgCod;
/***** Get the code of the message to delete *****/
MsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2014-12-01 23:55:08 +01:00
/***** Delete the message *****/
/* Delete the received message */
Msg_MoveRcvMsgToDeleted (MsgCod,Gbl.Usrs.Me.UsrDat.UsrCod);
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_Message_deleted);
2014-12-01 23:55:08 +01:00
/* Show the remaining messages */
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/**************************** Expand a sent message **************************/
/*****************************************************************************/
void Msg_ExpSntMsg (void)
{
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-01 23:55:08 +01:00
/***** Get the code of the message to expand *****/
Messages.ExpandedMsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2014-12-01 23:55:08 +01:00
/***** Expand the message *****/
Msg_DB_ExpandSntMsg (Messages.ExpandedMsgCod);
2014-12-01 23:55:08 +01:00
/***** Show again the messages *****/
Msg_ShowSntMsgs ();
}
/*****************************************************************************/
/************************** Expand a received message ************************/
/*****************************************************************************/
void Msg_ExpRecMsg (void)
{
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-01 23:55:08 +01:00
/***** Get the code of the message to expand *****/
Messages.ExpandedMsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2014-12-01 23:55:08 +01:00
/***** Expand the message *****/
Msg_DB_ExpandRcvMsg (Messages.ExpandedMsgCod);
2014-12-01 23:55:08 +01:00
/***** Mark possible notification as seen *****/
Ntf_DB_MarkNotifAsSeenUsingCod (Ntf_EVENT_MESSAGE,Messages.ExpandedMsgCod);
2014-12-01 23:55:08 +01:00
/***** Show again the messages *****/
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/*************************** Contract a sent message *************************/
/*****************************************************************************/
void Msg_ConSntMsg (void)
{
long MsgCod;
/***** Get the code of the message to contract *****/
MsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2014-12-01 23:55:08 +01:00
/***** Contract the message *****/
Msg_DB_ContractSntMsg (MsgCod);
2014-12-01 23:55:08 +01:00
/***** Show again the messages *****/
Msg_ShowSntMsgs ();
}
/*****************************************************************************/
/************************* Contract a received message ***********************/
/*****************************************************************************/
void Msg_ConRecMsg (void)
{
long MsgCod;
/***** Get the code of the message to contract *****/
MsgCod = ParCod_GetAndCheckPar (ParCod_Msg);
2014-12-01 23:55:08 +01:00
/***** Contract the message *****/
Msg_DB_ContractRcvMsg (MsgCod);
2014-12-01 23:55:08 +01:00
/***** Show again the messages *****/
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/********************** Insert a message in the database *********************/
/*****************************************************************************/
// Return the code of the new inserted message
2016-04-10 19:19:20 +02:00
static long Msg_InsertNewMsg (const char *Subject,const char *Content,
2021-02-11 00:58:53 +01:00
struct Med_Media *Media)
2014-12-01 23:55:08 +01:00
{
long MsgCod;
2019-03-19 11:20:29 +01:00
/***** Store media in filesystem and database *****/
Med_RemoveKeepOrStoreMedia (-1L,Media);
2019-03-18 15:42:22 +01:00
2014-12-01 23:55:08 +01:00
/***** Insert message subject and content in the database *****/
MsgCod = Msg_DB_CreateNewMsg (Subject,Content,Media->MedCod);
2014-12-01 23:55:08 +01:00
/***** Insert message in sent messages *****/
Msg_DB_CreateSntMsg (MsgCod,Gbl.Hierarchy.Node[Hie_CRS].HieCod);
2016-04-10 19:19:20 +02:00
2015-03-11 00:36:12 +01:00
/***** Increment number of messages sent by me *****/
Prf_DB_IncrementNumMsgSntUsr (Gbl.Usrs.Me.UsrDat.UsrCod);
2015-03-11 00:36:12 +01:00
2014-12-01 23:55:08 +01:00
return MsgCod;
}
/*****************************************************************************/
/************** Delete some received or sent messages of a user **************/
/*****************************************************************************/
static unsigned long Msg_RemoveSomeRecOrSntMsgsUsr (const struct Msg_Messages *Messages,
long UsrCod,
const char *FilterFromToSubquery)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
unsigned NumMsgs;
unsigned NumMsg;
2014-12-01 23:55:08 +01:00
long MsgCod;
/***** Get some of the messages received or sent by this user from database *****/
NumMsgs = Msg_DB_GetSntOrRcvMsgs (&mysql_res,
Messages,UsrCod,FilterFromToSubquery);
2014-12-01 23:55:08 +01:00
/***** Delete each message *****/
for (NumMsg = 0;
NumMsg < NumMsgs;
NumMsg++)
2014-12-01 23:55:08 +01:00
{
if ((MsgCod = DB_GetNextCode (mysql_res)) <= 0)
Err_WrongMessageExit ();
2020-11-25 01:50:13 +01:00
switch (Messages->TypeOfMessages)
2014-12-01 23:55:08 +01:00
{
2020-09-26 17:20:01 +02:00
case Msg_RECEIVED:
Msg_MoveRcvMsgToDeleted (MsgCod,UsrCod);
2014-12-01 23:55:08 +01:00
break;
2020-09-26 17:20:01 +02:00
case Msg_SENT:
Msg_MoveSntMsgToDeleted (MsgCod);
2014-12-01 23:55:08 +01:00
break;
default:
break;
}
}
/***** Free the MySQL result *****/
DB_FreeMySQLResult (&mysql_res);
return NumMsgs;
}
/*****************************************************************************/
/************ Delete a message from the received message table ***************/
/*****************************************************************************/
static void Msg_MoveRcvMsgToDeleted (long MsgCod,long UsrCod)
2014-12-01 23:55:08 +01:00
{
/***** Move message from msg_rcv to msg_rcv_deleted *****/
/* Insert message into msg_rcv_deleted */
Msg_DB_CopyRcvMsgToDeleted (MsgCod,UsrCod);
2014-12-01 23:55:08 +01:00
/* Delete message from msg_rcv *****/
Msg_DB_RemoveRcvMsg (MsgCod,UsrCod);
2014-12-01 23:55:08 +01:00
/***** If message content is not longer necessary, move it to msg_content_deleted *****/
if (Msg_DB_CheckIfSntMsgIsDeleted (MsgCod))
if (Msg_DB_CheckIfRcvMsgIsDeletedForAllItsRecipients (MsgCod))
Msg_DB_MoveMsgContentToDeleted (MsgCod);
2014-12-01 23:55:08 +01:00
/***** Mark possible notifications as removed *****/
Ntf_DB_MarkNotifToOneUsrAsRemoved (Ntf_EVENT_MESSAGE,MsgCod,UsrCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************** Delete a message from the sent message table *****************/
/*****************************************************************************/
static void Msg_MoveSntMsgToDeleted (long MsgCod)
2014-12-01 23:55:08 +01:00
{
/***** Move message from msg_snt to msg_snt_deleted *****/
/* Insert message into msg_snt_deleted */
Msg_DB_CopySntMsgToDeleted (MsgCod);
2014-12-01 23:55:08 +01:00
/* Delete message from msg_snt *****/
Msg_DB_RemoveSntMsg (MsgCod);
2014-12-01 23:55:08 +01:00
/***** If message content is not longer necessary, move it to msg_content_deleted *****/
if (Msg_DB_CheckIfRcvMsgIsDeletedForAllItsRecipients (MsgCod))
Msg_DB_MoveMsgContentToDeleted (MsgCod);
2014-12-01 23:55:08 +01:00
}
2014-12-17 23:04:35 +01:00
/*****************************************************************************/
/********************* Show messages sent to other users *********************/
/*****************************************************************************/
void Msg_ShowSntMsgs (void)
{
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
2014-12-17 23:04:35 +01:00
/***** Show the sent messages *****/
2020-09-26 17:20:01 +02:00
Messages.TypeOfMessages = Msg_SENT;
Msg_ShowSntOrRcvMessages (&Messages);
2014-12-17 23:04:35 +01:00
}
/*****************************************************************************/
/******************* Show messages received from other users *****************/
/*****************************************************************************/
void Msg_ShowRecMsgs (void)
{
2020-04-11 15:21:30 +02:00
struct Msg_Messages Messages;
/***** Reset messages context *****/
Msg_ResetMessages (&Messages);
if (Msg_DB_GetNumUsrsBannedBy (Gbl.Usrs.Me.UsrDat.UsrCod))
2014-12-17 23:54:11 +01:00
{
2019-10-24 09:46:20 +02:00
/***** Contextual menu *****/
Mnu_ContextMenuBegin ();
Msg_PutLinkToViewBannedUsers (); // View banned users
2019-10-24 09:46:20 +02:00
Mnu_ContextMenuEnd ();
2014-12-17 23:54:11 +01:00
}
2014-12-17 23:04:35 +01:00
/***** Show the received messages *****/
2020-09-26 17:20:01 +02:00
Messages.TypeOfMessages = Msg_RECEIVED;
Msg_ShowSntOrRcvMessages (&Messages);
2014-12-17 23:04:35 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************************ Show sent or received messages *********************/
/*****************************************************************************/
static void Msg_ShowSntOrRcvMessages (struct Msg_Messages *Messages)
2014-12-01 23:55:08 +01:00
{
2020-09-26 17:20:01 +02:00
extern const char *Hlp_COMMUNICATION_Messages_received;
extern const char *Hlp_COMMUNICATION_Messages_received_filter;
extern const char *Hlp_COMMUNICATION_Messages_sent;
extern const char *Hlp_COMMUNICATION_Messages_sent_filter;
2016-11-23 22:43:27 +01:00
extern const char *Txt_Filter;
2015-04-03 01:45:57 +02:00
extern const char *Txt_Update_messages;
char FilterFromToSubquery[Msg_DB_MAX_BYTES_MESSAGES_QUERY + 1];
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumMsg;
2019-12-30 22:32:06 +01:00
char *NumMsgsStr;
2020-09-26 17:20:01 +02:00
unsigned NumUnreadMsgs;
struct Pag_Pagination Pagination;
2014-12-01 23:55:08 +01:00
long MsgCod;
static Act_Action_t ActionSee[Msg_NUM_TYPES_OF_MSGS] =
2016-11-23 13:55:27 +01:00
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = ActUnk,
[Msg_RECEIVED] = ActSeeRcvMsg,
[Msg_SENT ] = ActSeeSntMsg,
2016-11-23 13:55:27 +01:00
};
static Pag_WhatPaginate_t WhatPaginate[Msg_NUM_TYPES_OF_MSGS] =
2016-11-07 12:31:14 +01:00
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = Pag_NONE,
[Msg_RECEIVED] = Pag_MESSAGES_RECEIVED,
[Msg_SENT ] = Pag_MESSAGES_SENT,
2016-11-07 12:31:14 +01:00
};
2016-11-23 13:55:27 +01:00
const char *Help[Msg_NUM_TYPES_OF_MSGS] =
2016-11-07 12:31:14 +01:00
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = NULL,
[Msg_RECEIVED] = Hlp_COMMUNICATION_Messages_received,
[Msg_SENT ] = Hlp_COMMUNICATION_Messages_sent,
2016-11-07 12:31:14 +01:00
};
2016-11-24 00:57:25 +01:00
const char *HelpFilter[Msg_NUM_TYPES_OF_MSGS] =
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = NULL,
[Msg_RECEIVED] = Hlp_COMMUNICATION_Messages_received_filter,
[Msg_SENT ] = Hlp_COMMUNICATION_Messages_sent_filter,
2016-11-24 00:57:25 +01:00
};
2014-12-01 23:55:08 +01:00
/***** Get the page number *****/
Messages->CurrentPage = Pag_GetParPagNum (WhatPaginate[Messages->TypeOfMessages]);
2014-12-01 23:55:08 +01:00
/***** Get other parameters *****/
Msg_GetParMsgsCrsCod (Messages);
Msg_GetParFilterFromTo (Messages);
Msg_GetParFilterContent (Messages);
Msg_DB_MakeFilterFromToSubquery (Messages,FilterFromToSubquery);
2014-12-01 23:55:08 +01:00
2016-11-23 14:14:14 +01:00
/***** Get number of unread messages *****/
2020-04-11 15:21:30 +02:00
switch (Messages->TypeOfMessages)
2016-11-23 14:14:14 +01:00
{
2020-09-26 17:20:01 +02:00
case Msg_RECEIVED:
Messages->ShowOnlyUnreadMsgs = Msg_GetParOnlyUnreadMsgs ();
NumUnreadMsgs = Msg_DB_GetNumUnreadMsgs (Messages,
FilterFromToSubquery);
2016-11-23 14:14:14 +01:00
break;
2020-09-26 17:20:01 +02:00
case Msg_SENT:
default:
2016-11-23 14:14:14 +01:00
NumUnreadMsgs = 0;
break;
}
/***** Get messages from database *****/
Messages->NumMsgs = Msg_DB_GetSntOrRcvMsgs (&mysql_res,
Messages,Gbl.Usrs.Me.UsrDat.UsrCod,
FilterFromToSubquery);
2016-11-23 14:14:14 +01:00
2019-10-26 02:19:42 +02:00
/***** Begin box with messages *****/
2020-04-11 15:21:30 +02:00
Msg_SetNumMsgsStr (Messages,&NumMsgsStr,NumUnreadMsgs);
Box_BoxBegin (NumMsgsStr,Msg_PutIconsListMsgs,Messages,
2020-04-11 15:21:30 +02:00
Help[Messages->TypeOfMessages],Box_NOT_CLOSABLE);
2019-12-30 22:32:06 +01:00
free (NumMsgsStr);
2016-11-23 14:14:14 +01:00
/***** Filter messages *****/
/* Begin box with filter */
Box_BoxBegin (Txt_Filter,NULL,NULL,
HelpFilter[Messages->TypeOfMessages],Box_CLOSABLE);
2016-11-23 14:01:08 +01:00
/* Form to see messages again */
Frm_BeginForm (ActionSee[Messages->TypeOfMessages]);
2016-11-23 21:06:37 +01:00
HTM_DIV_Begin ("class=\"CM\"");
Msg_ShowFormSelectCourseSentOrRecMsgs (Messages);
if (Messages->TypeOfMessages == Msg_RECEIVED)
Msg_ShowFormToShowOnlyUnreadMessages (Messages);
HTM_DIV_End ();
2015-04-03 01:45:57 +02:00
Msg_ShowFormToFilterMsgs (Messages);
2015-04-03 01:45:57 +02:00
/***** Put button to refresh *****/
Lay_WriteLinkToUpdate (Txt_Update_messages,"CopyMessageToHiddenFields();");
2014-12-01 23:55:08 +01:00
Frm_EndForm ();
2016-11-23 14:01:08 +01:00
/* End box */
Box_BoxEnd ();
2016-11-07 12:31:14 +01:00
if (Messages->NumMsgs) // If there are messages...
{
if (Gbl.Action.Act == ActExpRcvMsg) // Expanding a message, perhaps it is the result of following a link
// from a notification of received message, so show the page where the message is inside
{
/***** Get the page where the expanded message is inside *****/
for (NumMsg = 0;
NumMsg < Messages->NumMsgs;
NumMsg++)
{
row = mysql_fetch_row (mysql_res);
if (sscanf (row[0],"%ld",&MsgCod) != 1)
Err_WrongMessageExit ();
2014-12-01 23:55:08 +01:00
if (MsgCod == Messages->ExpandedMsgCod) // Expanded message found
{
Messages->CurrentPage = NumMsg / Pag_ITEMS_PER_PAGE + 1;
break;
}
}
}
2014-12-01 23:55:08 +01:00
/***** Compute variables related to pagination *****/
Pagination.NumItems = Messages->NumMsgs;
Pagination.CurrentPage = (int) Messages->CurrentPage;
Pag_CalculatePagination (&Pagination);
Messages->CurrentPage = (unsigned) Pagination.CurrentPage;
2014-12-01 23:55:08 +01:00
/***** Save my current page in order to show it next time I'll view my received/sent messages *****/
Ses_DB_SaveLastPageMsgIntoSession (WhatPaginate[Messages->TypeOfMessages],
Messages->CurrentPage);
2014-12-01 23:55:08 +01:00
/***** Write links to pages *****/
Pag_WriteLinksToPagesCentered (WhatPaginate[Messages->TypeOfMessages],&Pagination,
Messages,-1L);
2014-12-01 23:55:08 +01:00
/***** Show received / sent messages in this page *****/
HTM_TABLE_BeginWidePadding (2);
2014-12-01 23:55:08 +01:00
mysql_data_seek (mysql_res,(my_ulonglong) (Pagination.FirstItemVisible - 1));
for (NumMsg = Pagination.FirstItemVisible;
NumMsg <= Pagination.LastItemVisible;
NumMsg++)
{
row = mysql_fetch_row (mysql_res);
2014-12-01 23:55:08 +01:00
if (sscanf (row[0],"%ld",&MsgCod) != 1)
Err_WrongMessageExit ();
Msg_ShowASentOrReceivedMessage (Messages,
Messages->NumMsgs - NumMsg + 1,
MsgCod);
}
2014-12-01 23:55:08 +01:00
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
/***** Write again links to pages *****/
Pag_WriteLinksToPagesCentered (WhatPaginate[Messages->TypeOfMessages],&Pagination,
Messages,-1L);
}
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End box *****/
2019-10-25 22:48:34 +02:00
Box_BoxEnd ();
2015-10-08 01:06:46 +02:00
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
2014-12-17 23:04:35 +01:00
/*****************************************************************************/
/****************** Put a link (form) to view banned users *******************/
/*****************************************************************************/
static void Msg_PutLinkToViewBannedUsers(void)
{
extern const char *Txt_Banned_users;
2020-03-26 02:54:30 +01:00
Lay_PutContextualLinkIconText (ActLstBanUsr,NULL,
NULL,NULL,
"lock.svg",Ico_RED,
Txt_Banned_users,NULL);
2014-12-17 23:04:35 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-12-30 22:32:06 +01:00
/***** Set string with number of messages and number of unread messages ******/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-12-30 22:32:06 +01:00
// The string must be deallocated after calling this function
2014-12-01 23:55:08 +01:00
2020-04-11 15:21:30 +02:00
static void Msg_SetNumMsgsStr (const struct Msg_Messages *Messages,
char **NumMsgsStr,unsigned NumUnreadMsgs)
2014-12-01 23:55:08 +01:00
{
2016-03-21 14:50:23 +01:00
extern const char *Txt_message_received;
extern const char *Txt_message_sent;
extern const char *Txt_messages_received;
extern const char *Txt_messages_sent;
2014-12-01 23:55:08 +01:00
extern const char *Txt_unread_MESSAGE;
extern const char *Txt_unread_MESSAGES;
2020-04-11 15:21:30 +02:00
switch (Messages->TypeOfMessages)
2016-03-21 14:50:23 +01:00
{
2020-09-26 17:20:01 +02:00
case Msg_RECEIVED:
2020-04-11 15:21:30 +02:00
if (Messages->NumMsgs == 1)
2016-11-07 12:31:14 +01:00
{
if (NumUnreadMsgs)
2019-12-30 22:32:06 +01:00
{
if (asprintf (NumMsgsStr,"1 %s, 1 %s",
Txt_message_received,Txt_unread_MESSAGE) < 0)
Err_NotEnoughMemoryExit ();
2019-12-30 22:32:06 +01:00
}
2016-11-07 12:31:14 +01:00
else
2019-12-30 22:32:06 +01:00
{
if (asprintf (NumMsgsStr,"1 %s",Txt_message_received) < 0)
Err_NotEnoughMemoryExit ();
2019-12-30 22:32:06 +01:00
}
2016-11-07 12:31:14 +01:00
}
2016-03-21 14:50:23 +01:00
else
2016-11-07 12:31:14 +01:00
{
if (NumUnreadMsgs == 0)
2019-12-30 22:32:06 +01:00
{
if (asprintf (NumMsgsStr,"%u %s",
2020-04-11 15:21:30 +02:00
Messages->NumMsgs,Txt_messages_received) < 0)
Err_NotEnoughMemoryExit ();
2019-12-30 22:32:06 +01:00
}
2016-11-07 12:31:14 +01:00
else if (NumUnreadMsgs == 1)
2019-12-30 22:32:06 +01:00
{
if (asprintf (NumMsgsStr,"%u %s, 1 %s",
2020-04-11 15:21:30 +02:00
Messages->NumMsgs,Txt_messages_received,
2019-12-30 22:32:06 +01:00
Txt_unread_MESSAGE) < 0)
Err_NotEnoughMemoryExit ();
2019-12-30 22:32:06 +01:00
}
2016-11-07 12:31:14 +01:00
else
2019-12-30 22:32:06 +01:00
{
if (asprintf (NumMsgsStr,"%u %s, %u %s",
2020-04-11 15:21:30 +02:00
Messages->NumMsgs,Txt_messages_received,
2019-12-30 22:32:06 +01:00
NumUnreadMsgs,Txt_unread_MESSAGES) < 0)
Err_NotEnoughMemoryExit ();
2019-12-30 22:32:06 +01:00
}
2016-11-07 12:31:14 +01:00
}
break;
2020-09-26 17:20:01 +02:00
case Msg_SENT:
2020-04-11 15:21:30 +02:00
if (Messages->NumMsgs == 1)
2019-12-30 22:32:06 +01:00
{
if (asprintf (NumMsgsStr,"1 %s",Txt_message_sent) < 0)
Err_NotEnoughMemoryExit ();
2019-12-30 22:32:06 +01:00
}
2016-03-21 14:50:23 +01:00
else
2019-12-30 22:32:06 +01:00
{
if (asprintf (NumMsgsStr,"%u %s",
2020-04-11 15:21:30 +02:00
Messages->NumMsgs,Txt_messages_sent) < 0)
Err_NotEnoughMemoryExit ();
2019-12-30 22:32:06 +01:00
}
2016-11-07 12:31:14 +01:00
break;
2020-09-26 17:20:01 +02:00
default:
break;
2016-03-21 14:50:23 +01:00
}
2016-11-07 12:31:14 +01:00
}
/*****************************************************************************/
/***************** Put contextual icons in list of messages ******************/
/*****************************************************************************/
2020-04-08 19:42:03 +02:00
static void Msg_PutIconsListMsgs (void *Messages)
2016-11-07 12:31:14 +01:00
{
static Act_Action_t ActionReqDelAllMsg[Msg_NUM_TYPES_OF_MSGS] =
2017-05-02 12:13:27 +02:00
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = ActUnk,
[Msg_RECEIVED] = ActReqDelAllRcvMsg,
[Msg_SENT ] = ActReqDelAllSntMsg,
2017-05-02 12:13:27 +02:00
};
2020-04-08 19:42:03 +02:00
if (Messages)
2020-03-26 02:54:30 +01:00
{
2020-09-25 12:43:21 +02:00
/***** Put icon to write a new message *****/
2020-09-26 17:20:01 +02:00
switch (((struct Msg_Messages *) Messages)->TypeOfMessages)
{
case Msg_RECEIVED:
case Msg_SENT:
Lay_PutContextualLinkOnlyIcon (ActReqMsgUsr,NULL,
Msg_PutParsMsgsFilters,Messages,
"marker.svg",Ico_BLACK);
2020-09-26 17:20:01 +02:00
break;
default:
break;
}
/***** Put icon to see received messages *****/
switch (((struct Msg_Messages *) Messages)->TypeOfMessages)
{
case Msg_WRITING:
case Msg_SENT:
Lay_PutContextualLinkOnlyIcon (ActSeeRcvMsg,NULL,
Msg_PutParsMsgsFilters,Messages,
"inbox.svg",Ico_BLACK);
2020-09-26 17:20:01 +02:00
break;
default:
break;
}
/***** Put icon to see sent messages *****/
switch (((struct Msg_Messages *) Messages)->TypeOfMessages)
{
case Msg_WRITING:
case Msg_RECEIVED:
Lay_PutContextualLinkOnlyIcon (ActSeeSntMsg,NULL,
Msg_PutParsMsgsFilters,Messages,
"share.svg",Ico_BLACK);
2020-09-26 17:20:01 +02:00
break;
default:
break;
}
2020-09-25 12:43:21 +02:00
2020-03-26 02:54:30 +01:00
/***** Put icon to remove messages *****/
2020-09-26 17:20:01 +02:00
switch (((struct Msg_Messages *) Messages)->TypeOfMessages)
{
case Msg_RECEIVED:
case Msg_SENT:
2020-10-13 22:34:31 +02:00
Ico_PutContextualIconToRemove (ActionReqDelAllMsg[((struct Msg_Messages *) Messages)->TypeOfMessages],NULL,
Msg_PutParsMsgsFilters,Messages);
2020-09-26 17:20:01 +02:00
break;
default:
break;
}
2014-12-01 23:55:08 +01:00
2020-03-26 02:54:30 +01:00
/***** Put icon to show a figure *****/
2020-04-06 23:18:02 +02:00
Fig_PutIconToShowFigure (Fig_MESSAGES);
2020-03-26 02:54:30 +01:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2017-05-02 12:13:27 +02:00
/******* Put hidden parameters to expand, contract or delete a message *******/
/*****************************************************************************/
static void Msg_PutParsOneMsg (void *Messages)
2017-05-02 12:13:27 +02:00
{
2020-04-08 19:42:03 +02:00
if (Messages)
2020-03-26 02:54:30 +01:00
{
Pag_PutParPagNum (Msg_WhatPaginate[((struct Msg_Messages *) Messages)->TypeOfMessages],
2020-04-08 19:42:03 +02:00
((struct Msg_Messages *) Messages)->CurrentPage);
ParCod_PutPar (ParCod_Msg,((struct Msg_Messages *) Messages)->MsgCod);
Msg_PutParsMsgsFilters (Messages);
2020-03-26 02:54:30 +01:00
}
2017-05-02 12:13:27 +02:00
}
/*****************************************************************************/
/****************** Put hidden parameters with filters ***********************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
void Msg_PutParsMsgsFilters (void *Messages)
2014-12-01 23:55:08 +01:00
{
2020-04-08 19:42:03 +02:00
if (Messages)
2020-03-26 02:54:30 +01:00
{
2020-04-08 19:42:03 +02:00
if (((struct Msg_Messages *) Messages)->FilterCrsCod >= 0)
ParCod_PutPar (ParCod_OthCrs,((struct Msg_Messages *) Messages)->FilterCrsCod);
2020-04-08 19:42:03 +02:00
if (((struct Msg_Messages *) Messages)->FilterFromTo[0])
Par_PutParString (NULL,"FilterFromTo",((struct Msg_Messages *) Messages)->FilterFromTo);
2020-04-08 19:42:03 +02:00
if (((struct Msg_Messages *) Messages)->FilterContent[0])
Par_PutParString (NULL,"FilterContent",((struct Msg_Messages *) Messages)->FilterContent);
2020-04-08 19:42:03 +02:00
if (((struct Msg_Messages *) Messages)->ShowOnlyUnreadMsgs)
Par_PutParChar ("OnlyUnreadMsgs",'Y');
2020-03-26 02:54:30 +01:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********* Show form to select course for sent or received messages **********/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
static void Msg_ShowFormSelectCourseSentOrRecMsgs (const struct Msg_Messages *Messages)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_Messages_received_from_A_COURSE;
extern const char *Txt_Messages_sent_from_A_COURSE;
extern const char *Txt_any_course;
static unsigned (*GetDistinctCrssInMyRcvMsgs[Msg_NUM_TYPES_OF_MSGS]) (MYSQL_RES **mysql_res) =
{
[Msg_WRITING ] = NULL,
[Msg_RECEIVED] = Msg_DB_GetDistinctCrssInMyRcvMsgs,
[Msg_SENT ] = Msg_DB_GetDistinctCrssInMySntMsgs,
};
static const char **TxtSelector[Msg_NUM_TYPES_OF_MSGS] =
{
[Msg_WRITING ] = NULL,
[Msg_RECEIVED] = &Txt_Messages_received_from_A_COURSE,
[Msg_SENT ] = &Txt_Messages_sent_from_A_COURSE,
};
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumCrss = 0; // Initialized to avoid warning
unsigned NumCrs;
long CrsCod;
2014-12-01 23:55:08 +01:00
/***** Get distinct courses in my messages *****/
if (GetDistinctCrssInMyRcvMsgs[Messages->TypeOfMessages])
NumCrss = GetDistinctCrssInMyRcvMsgs[Messages->TypeOfMessages] (&mysql_res);
2014-12-01 23:55:08 +01:00
/***** Course selection *****/
HTM_LABEL_Begin ("class=\"FORM_IN_%s\"",The_GetSuffix ());
HTM_TxtF ("%s&nbsp;",*TxtSelector[Messages->TypeOfMessages]);
HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE,NULL,
"name=\"FilterCrsCod\" class=\"INPUT_%s\"",
The_GetSuffix ());
/* Write a first option to select any course */
HTM_OPTION (HTM_Type_STRING,"",
Messages->FilterCrsCod < 0 ? HTM_OPTION_SELECTED :
HTM_OPTION_UNSELECTED,
HTM_OPTION_ENABLED,
"%s",Txt_any_course);
/* Write an option for each origin course */
for (NumCrs = 0;
NumCrs < NumCrss;
NumCrs++)
{
/* Get next course */
row = mysql_fetch_row (mysql_res);
if ((CrsCod = Str_ConvertStrCodToLongCod (row[0])) > 0)
HTM_OPTION (HTM_Type_LONG,&CrsCod,
CrsCod == Messages->FilterCrsCod ? HTM_OPTION_SELECTED :
HTM_OPTION_UNSELECTED,
HTM_OPTION_ENABLED,
"%s",row[1]); // Course short name
}
HTM_SELECT_End ();
2019-11-02 12:59:31 +01:00
HTM_LABEL_End ();
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***** Show form to filter "from" and "to" for received or sent messages *****/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_ShowFormToFilterMsgs (const struct Msg_Messages *Messages)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_MSG_From;
extern const char *Txt_MSG_To;
2017-04-19 14:27:52 +02:00
extern const char *Txt_MSG_Content;
static const char **TxtFromTo[Msg_NUM_TYPES_OF_MSGS] =
2016-11-07 12:31:14 +01:00
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = NULL,
[Msg_RECEIVED] = &Txt_MSG_From,
[Msg_SENT ] = &Txt_MSG_To
2016-11-07 12:31:14 +01:00
};
2014-12-01 23:55:08 +01:00
2019-10-20 22:00:28 +02:00
/***** Begin table *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginCenterPadding (2);
2014-12-01 23:55:08 +01:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
/***** Filter authors/recipients *****/
HTM_TD_Begin ("class=\"LM\"");
HTM_LABEL_Begin ("class=\"FORM_IN_%s\"",The_GetSuffix ());
HTM_TxtColonNBSP (*TxtFromTo[Messages->TypeOfMessages]);
HTM_INPUT_SEARCH ("FilterFromTo",Usr_MAX_CHARS_FIRSTNAME_OR_SURNAME * 3,
Messages->FilterFromTo,
"size=\"20\" class=\"INPUT_%s\"",
The_GetSuffix ());
HTM_LABEL_End ();
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Filter message content *****/
HTM_TD_Begin ("class=\"LM\"");
HTM_LABEL_Begin ("class=\"FORM_IN_%s\"",The_GetSuffix ());
HTM_TxtColonNBSP (Txt_MSG_Content);
HTM_INPUT_SEARCH ("FilterContent",Msg_MAX_CHARS_FILTER_CONTENT,
Messages->FilterContent,
"size=\"20\" class=\"INPUT_%s\"",
The_GetSuffix ());
HTM_LABEL_End ();
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
2016-03-20 13:47:46 +01:00
/***** End table *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**** Show form to select whether to show only unread (received) messages ****/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_ShowFormToShowOnlyUnreadMessages (const struct Msg_Messages *Messages)
2014-12-01 23:55:08 +01:00
{
2016-11-23 21:06:37 +01:00
extern const char *Txt_only_unread_messages;
2014-12-01 23:55:08 +01:00
/***** Put checkbox to select whether to show only unread (received) messages *****/
HTM_LABEL_Begin ("class=\"FORM_IN_%s\"",The_GetSuffix ());
HTM_INPUT_CHECKBOX ("OnlyUnreadMsgs",HTM_DONT_SUBMIT_ON_CHANGE,
"value=\"Y\"%s",
Messages->ShowOnlyUnreadMsgs ? " checked=\"checked\"" :
"");
HTM_Txt (Txt_only_unread_messages);
2019-11-02 12:59:31 +01:00
HTM_LABEL_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********** Get parameter to show only unread (received) messages ***********/
/*****************************************************************************/
static bool Msg_GetParOnlyUnreadMsgs (void)
2014-12-01 23:55:08 +01:00
{
/***** Get parameter to show only unread (received) messages *****/
return Par_GetParBool ("OnlyUnreadMsgs");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************************** Get data of a message *************************/
/*****************************************************************************/
2015-10-24 20:12:03 +02:00
static void Msg_GetMsgSntData (long MsgCod,long *CrsCod,long *UsrCod,
2017-01-17 03:10:43 +01:00
time_t *CreatTimeUTC,
char Subject[Cns_MAX_BYTES_SUBJECT + 1],
bool *Deleted)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Get data of message from table msg_snt *****/
/* Result should have a unique row */
if (Msg_DB_GetMsgSntData (&mysql_res,MsgCod,Deleted) != 1)
Err_WrongMessageExit ();
2014-12-01 23:55:08 +01:00
/* Get number of rows */
row = mysql_fetch_row (mysql_res);
/* Get location (row[0]) */
*CrsCod = Str_ConvertStrCodToLongCod (row[0]);
/* Get author code (row[1]) */
*UsrCod = Str_ConvertStrCodToLongCod (row[1]);
/* Get creation time (row[2]) */
2015-10-24 20:12:03 +02:00
*CreatTimeUTC = Dat_GetUNIXTimeFromStr (row[2]);
2014-12-01 23:55:08 +01:00
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
/***** Get subject of message from database *****/
Msg_DB_GetMsgSubject (MsgCod,Subject);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2016-04-10 19:19:20 +02:00
/*************** Get content and optional image of a message *****************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
static void Msg_GetMsgContent (long MsgCod,
char Content[Cns_MAX_BYTES_LONG_TEXT + 1],
2021-02-11 00:58:53 +01:00
struct Med_Media *Media)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Get content of message from database *****/
if (Msg_DB_GetMsgContent (&mysql_res,MsgCod) != 1)
Err_WrongMessageExit ();
2014-12-01 23:55:08 +01:00
/***** Get number of rows *****/
row = mysql_fetch_row (mysql_res);
2015-12-29 23:44:28 +01:00
/****** Get content (row[0]) *****/
Str_Copy (Content,row[0],Cns_MAX_BYTES_LONG_TEXT);
2014-12-01 23:55:08 +01:00
2019-03-18 15:42:22 +01:00
/***** Get media (row[1]) *****/
Media->MedCod = Str_ConvertStrCodToLongCod (row[1]);
Med_GetMediaDataByCod (Media);
2016-04-10 19:19:20 +02:00
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/******** Show a sent or a received message (from a user to another) *********/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_ShowASentOrReceivedMessage (struct Msg_Messages *Messages,
long MsgNum,long MsgCod)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_MSG_Replied;
extern const char *Txt_MSG_Not_replied;
extern const char *Txt_MSG_Unopened;
extern const char *Txt_MSG_Sent;
extern const char *Txt_MSG_From;
extern const char *Txt_MSG_To;
2017-04-19 14:27:52 +02:00
extern const char *Txt_MSG_Content;
static Act_Action_t ActionDelMsg[Msg_NUM_TYPES_OF_MSGS] =
2017-05-02 12:13:27 +02:00
{
2020-09-26 17:20:01 +02:00
[Msg_WRITING ] = ActUnk,
[Msg_RECEIVED] = ActDelRcvMsg,
[Msg_SENT ] = ActDelSntMsg,
2017-05-02 12:13:27 +02:00
};
static const char *Class[Msg_NUM_TYPES_OF_MSGS][CloOpe_NUM_CLOSED_OPEN] =
{
[Msg_RECEIVED][CloOpe_CLOSED] = "MSG_BG_NEW",
[Msg_RECEIVED][CloOpe_OPEN ] = "MSG_BG",
[Msg_SENT ][CloOpe_CLOSED] = "MSG_BG",
[Msg_SENT ][CloOpe_OPEN ] = "MSG_BG",
};
static struct
{
const char *Icon;
const char **Title;
} Icons[Msg_NUM_TYPES_OF_MSGS][CloOpe_NUM_CLOSED_OPEN][2] =
{
[Msg_RECEIVED][CloOpe_CLOSED][false] = {"envelope.svg" ,&Txt_MSG_Unopened },
[Msg_RECEIVED][CloOpe_CLOSED][true ] = {"envelope.svg" ,&Txt_MSG_Unopened },
[Msg_RECEIVED][CloOpe_OPEN ][false] = {"envelope-open-text.svg",&Txt_MSG_Not_replied},
[Msg_RECEIVED][CloOpe_OPEN ][true ] = {"reply.svg" ,&Txt_MSG_Replied },
[Msg_SENT ][CloOpe_CLOSED][false] = {"share.svg" ,&Txt_MSG_Sent },
[Msg_SENT ][CloOpe_CLOSED][true ] = {"share.svg" ,&Txt_MSG_Sent },
[Msg_SENT ][CloOpe_OPEN ][false] = {"share.svg" ,&Txt_MSG_Sent },
[Msg_SENT ][CloOpe_OPEN ][true ] = {"share.svg" ,&Txt_MSG_Sent },
};
static const char *ClassAuthor[CloOpe_NUM_CLOSED_OPEN] =
{
[CloOpe_CLOSED] = "MSG_AUT_NEW",
[CloOpe_OPEN ] = "MSG_AUT",
};
static const char *ClassDateTime[CloOpe_NUM_CLOSED_OPEN] =
{
[CloOpe_CLOSED] = "MSG_TIT_NEW",
[CloOpe_OPEN ] = "MSG_TIT",
};
static const char *ClassBg[CloOpe_NUM_CLOSED_OPEN] =
{
[CloOpe_CLOSED] = "MSG_BG_NEW",
[CloOpe_OPEN ] = "MSG_BG",
};
struct Usr_Data UsrDat;
2015-10-24 20:12:03 +02:00
bool FromThisCrs = false; // Initialized to avoid warning
time_t CreatTimeUTC; // Creation time of a message
2014-12-01 23:55:08 +01:00
long CrsCod;
2017-01-17 03:10:43 +01:00
char Subject[Cns_MAX_BYTES_SUBJECT + 1];
char Content[Cns_MAX_BYTES_LONG_TEXT + 1];
2021-02-11 00:58:53 +01:00
struct Med_Media Media;
2014-12-01 23:55:08 +01:00
bool Deleted;
CloOpe_ClosedOrOpen_t ClosedOrOpen = CloOpe_OPEN;
2015-10-24 20:12:03 +02:00
bool Replied = false; // Initialized to avoid warning
2014-12-01 23:55:08 +01:00
bool Expanded = false;
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDat);
/***** Get data of message *****/
2015-10-24 20:12:03 +02:00
Msg_GetMsgSntData (MsgCod,&CrsCod,&UsrDat.UsrCod,&CreatTimeUTC,Subject,&Deleted);
2020-04-11 15:21:30 +02:00
switch (Messages->TypeOfMessages)
2014-12-01 23:55:08 +01:00
{
2020-09-26 17:20:01 +02:00
case Msg_RECEIVED:
Msg_DB_GetStatusOfRcvMsg (MsgCod,&ClosedOrOpen,&Replied,&Expanded);
2014-12-01 23:55:08 +01:00
break;
2020-09-26 17:20:01 +02:00
case Msg_SENT:
Expanded = Msg_DB_GetStatusOfSntMsg (MsgCod);
2014-12-01 23:55:08 +01:00
break;
2020-09-26 17:20:01 +02:00
default:
Err_WrongMessageExit ();
2020-09-26 17:20:01 +02:00
break;
2014-12-01 23:55:08 +01:00
}
/***** Put an icon with message status *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-09 15:44:12 +02:00
/***** Icons *****/
HTM_TD_Begin ("class=\"CONTEXT_COL %s_%s\"",
Class[Messages->TypeOfMessages][ClosedOrOpen],
The_GetSuffix ());
/* Type of message icon (envelope, reply...) */
Ico_PutIcon (Icons[Messages->TypeOfMessages][ClosedOrOpen][Replied].Icon,
Ico_BLACK,
*Icons[Messages->TypeOfMessages][ClosedOrOpen][Replied].Title,
"ICO16x16");
HTM_BR ();
/* Form to delete message */
Messages->MsgCod = MsgCod; // Message to be deleted
Ico_PutContextualIconToRemove (ActionDelMsg[Messages->TypeOfMessages],NULL,
Msg_PutParsOneMsg,Messages);
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Number *****/
Msg_WriteMsgNumber (MsgNum,ClosedOrOpen == CloOpe_CLOSED);
2014-12-01 23:55:08 +01:00
/***** Author *****/
HTM_TD_Begin ("class=\"LT %s_%s %s_%s\"",
ClassAuthor[ClosedOrOpen],The_GetSuffix (),
ClassBg[ClosedOrOpen],The_GetSuffix ());
Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CRS);
Usr_WriteAuthor (&UsrDat,Cns_ENABLED);
HTM_TD_End ();
2017-05-02 01:05:23 +02:00
/***** Subject *****/
Msg_WriteSentOrReceivedMsgSubject (Messages,MsgCod,Subject,ClosedOrOpen,Expanded);
2014-12-01 23:55:08 +01:00
/***** Date-time *****/
Msg_WriteMsgDate (CreatTimeUTC,
ClassDateTime[ClosedOrOpen],
ClassBg[ClosedOrOpen]);
2015-10-24 20:12:03 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
if (Expanded)
{
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-09 15:44:12 +02:00
HTM_TD_Begin ("rowspan=\"3\" colspan=\"2\" class=\"LT\"");
HTM_TABLE_BeginPadding (2);
/***** Write course origin of message *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"LM\"");
FromThisCrs = Msg_WriteCrsOrgMsg (CrsCod);
HTM_TD_End ();
HTM_TR_End ();
/***** Form to reply message *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"LM\"");
if (Messages->TypeOfMessages == Msg_RECEIVED &&
Gbl.Usrs.Me.Role.Logged >= Rol_USR)
// Guests (users without courses) can read messages but not reply them
Msg_WriteFormToReply (MsgCod,CrsCod,FromThisCrs,&UsrDat);
HTM_TD_End ();
HTM_TR_End ();
HTM_TABLE_End ();
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Write "From:" *****/
HTM_TD_Begin ("class=\"RT MSG_TIT_%s\"",The_GetSuffix ());
HTM_TxtColonNBSP (Txt_MSG_From);
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
HTM_TD_Begin ("colspan=\"2\" class=\"LT\"");
Msg_WriteMsgFrom (Messages,&UsrDat,Deleted);
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
/***** Write "To:" *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
HTM_TD_Begin ("class=\"RT MSG_TIT_%s\"",The_GetSuffix ());
HTM_TxtColonNBSP (Txt_MSG_To);
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
HTM_TD_Begin ("colspan=\"2\" class=\"LT\"");
Msg_WriteMsgTo (Messages,MsgCod);
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
/***** Initialize media *****/
Med_MediaConstructor (&Media);
2016-04-10 19:19:20 +02:00
/***** Get message content and optional media *****/
Msg_GetMsgContent (MsgCod,Content,&Media);
2016-04-10 19:19:20 +02:00
/***** Write "Content:" *****/
HTM_TD_Begin ("class=\"RT MSG_TIT_%s\"",The_GetSuffix ());
HTM_TxtColonNBSP (Txt_MSG_Content);
HTM_TD_End ();
2016-04-10 19:19:20 +02:00
/***** Show content and media *****/
HTM_TD_Begin ("colspan=\"2\" class=\"LT MSG_TXT_%s\"",
The_GetSuffix ());
if (Content[0])
Msg_WriteMsgContent (Content,true,false);
Med_ShowMedia (&Media,"MSG_IMG_CONT","MSG_IMG");
HTM_TD_End ();
2019-10-09 17:38:50 +02:00
/***** Free media *****/
Med_MediaDestructor (&Media);
2016-04-10 19:19:20 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDat);
}
/*****************************************************************************/
2016-01-22 12:05:25 +01:00
/******************** Get subject and content of a message *******************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-03-08 14:12:33 +01:00
void Msg_GetNotifMessage (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1],
char **ContentStr,long MsgCod,Ntf_GetContent_t GetContent)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2017-01-15 22:58:26 +01:00
size_t Length;
2014-12-01 23:55:08 +01:00
SummaryStr[0] = '\0'; // Return nothing on error
/***** Get subject of message from database *****/
if (Msg_DB_GetSubjectAndContent (&mysql_res,MsgCod) == 1) // Result should have a unique row
2018-10-23 01:01:51 +02:00
{
/***** Get subject and content of the message *****/
row = mysql_fetch_row (mysql_res);
2014-12-01 23:55:08 +01:00
2018-10-23 01:01:51 +02:00
/***** Copy subject *****/
// TODO: Do only direct copy when Subject will be VARCHAR(255)
if (strlen (row[0]) > Ntf_MAX_BYTES_SUMMARY)
{
strncpy (SummaryStr,row[0],
Ntf_MAX_BYTES_SUMMARY);
SummaryStr[Ntf_MAX_BYTES_SUMMARY] = '\0';
}
else
Str_Copy (SummaryStr,row[0],Ntf_MAX_BYTES_SUMMARY);
2018-10-23 01:01:51 +02:00
/***** Copy subject *****/
if (GetContent == Ntf_GET_CONTENT)
2018-10-23 01:01:51 +02:00
{
Length = strlen (row[1]);
if ((*ContentStr = malloc (Length + 1)) == NULL)
Err_NotEnoughMemoryExit ();
Str_Copy (*ContentStr,row[1],Length);
2018-10-23 01:01:51 +02:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************** Write number of message **************************/
/*****************************************************************************/
void Msg_WriteMsgNumber (unsigned long MsgNum,bool NewMsg)
{
HTM_TD_Begin ("class=\"CT %s_%s %s_%s\" style=\"width:45px;\"",
NewMsg ? "MSG_TIT_NEW" :
"MSG_TIT",The_GetSuffix (),
NewMsg ? "MSG_BG_NEW" :
"MSG_BG" ,The_GetSuffix ());
HTM_TxtF ("%lu:",MsgNum);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************** Write subject of a received message ********************/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_WriteSentOrReceivedMsgSubject (struct Msg_Messages *Messages,
long MsgCod,const char *Subject,
CloOpe_ClosedOrOpen_t ClosedOrOpen,
bool Expanded)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_See_message;
extern const char *Txt_Hide_message;
2014-12-01 23:55:08 +01:00
extern const char *Txt_no_subject;
static const char *ClassSubject[CloOpe_NUM_CLOSED_OPEN] =
{
[CloOpe_CLOSED] = "MSG_TIT_NEW",
[CloOpe_OPEN ] = "MSG_TIT",
};
static const char *ClassBg[CloOpe_NUM_CLOSED_OPEN] =
{
[CloOpe_CLOSED] = "MSG_BG_NEW",
[CloOpe_OPEN ] = "MSG_BG",
};
static Act_Action_t Action[Msg_NUM_TYPES_OF_MSGS][2] =
{
[Msg_WRITING ][false] = ActUnk,
[Msg_WRITING ][true ] = ActUnk,
[Msg_RECEIVED][false] = ActExpRcvMsg,
[Msg_RECEIVED][true ] = ActConRcvMsg,
[Msg_SENT ][false] = ActExpSntMsg,
[Msg_SENT ][true ] = ActConSntMsg,
};
static const char **Title[2] =
{
[false] = &Txt_See_message,
[true ] = &Txt_Hide_message,
};
2014-12-01 23:55:08 +01:00
/***** Begin cell *****/
HTM_TD_Begin ("class=\"LT %s_%s %s_%s\"",
ClassSubject[ClosedOrOpen],The_GetSuffix (),
ClassBg[ClosedOrOpen],The_GetSuffix ());
2014-12-01 23:55:08 +01:00
/***** Begin form to expand/contract the message *****/
Frm_BeginForm (Action[Messages->TypeOfMessages][Expanded]);
Messages->MsgCod = MsgCod; // Message to be contracted/expanded
Msg_PutParsOneMsg (Messages);
HTM_BUTTON_Submit_Begin (*Title[Expanded],"class=\"LT BT_LINK\"");
/***** Write subject *****/
if (Subject[0])
HTM_Txt (Subject);
else
HTM_TxtF ("[%s]",Txt_no_subject);
2014-12-01 23:55:08 +01:00
/***** End form to expand the message *****/
HTM_BUTTON_End ();
Frm_EndForm ();
2014-12-01 23:55:08 +01:00
/***** End cell *****/
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Write course origin of a message **********************/
/*****************************************************************************/
// Returns true if the origin course is the current course
2020-04-11 15:21:30 +02:00
static bool Msg_WriteCrsOrgMsg (long CrsCod)
2014-12-01 23:55:08 +01:00
{
extern bool (*Hie_GetDataByCod[Hie_NUM_LEVELS]) (struct Hie_Node *Node);
2014-12-23 22:47:09 +01:00
extern const char *Txt_from_this_course;
2014-12-01 23:55:08 +01:00
extern const char *Txt_no_course_of_origin;
struct Hie_Node Crs;
2014-12-01 23:55:08 +01:00
bool FromThisCrs = true;
bool ThereIsOrgCrs = false;
if (CrsCod > 0)
{
/* Get new course code from old course code */
Crs.HieCod = CrsCod;
2014-12-01 23:55:08 +01:00
/* Get data of current degree */
if (Hie_GetDataByCod[Hie_CRS] (&Crs))
2014-12-01 23:55:08 +01:00
{
ThereIsOrgCrs = true;
if ((FromThisCrs = (CrsCod == Gbl.Hierarchy.Node[Hie_CRS].HieCod))) // Message sent from current course
2019-10-23 20:07:56 +02:00
{
HTM_DIV_Begin ("class=\"MSG_AUT_%s\"",The_GetSuffix ());
HTM_TxtF ("(%s)",Txt_from_this_course);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
}
2014-12-01 23:55:08 +01:00
else // Message sent from another course
{
/* Write course, including link */
Frm_BeginFormGoTo (ActSeeCrsInf);
ParCod_PutPar (ParCod_Crs,Crs.HieCod);
HTM_DIV_Begin ("class=\"MSG_AUT_%s\"",The_GetSuffix ());
HTM_Txt ("(");
HTM_BUTTON_Submit_Begin (Str_BuildGoToTitle (Crs.FullName),
"class=\"BT_LINK\"");
Str_FreeGoToTitle ();
HTM_Txt (Crs.ShrtName);
HTM_BUTTON_End ();
HTM_Txt (")");
HTM_DIV_End ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2014-12-01 23:55:08 +01:00
}
}
}
if (!ThereIsOrgCrs) // It's an old message without origin source specified, or is a message sent from none course
2019-10-23 20:07:56 +02:00
{
HTM_DIV_Begin ("class=\"MSG_AUT_%s\"",The_GetSuffix ());
HTM_TxtF ("(%s)",Txt_no_course_of_origin);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
}
2014-12-01 23:55:08 +01:00
return FromThisCrs;
}
/*****************************************************************************/
/************************* Write form to reply a message *********************/
/*****************************************************************************/
static void Msg_WriteFormToReply (long MsgCod,long CrsCod,bool FromThisCrs,
const struct Usr_Data *UsrDat)
2014-12-01 23:55:08 +01:00
{
/***** Begin form and parameters *****/
2014-12-01 23:55:08 +01:00
if (FromThisCrs)
Frm_BeginForm (ActReqMsgUsr);
2014-12-01 23:55:08 +01:00
else // Not the current course ==> go to another course
{
Frm_BeginFormGoTo (ActReqMsgUsr);
ParCod_PutPar (ParCod_Crs,CrsCod);
2014-12-01 23:55:08 +01:00
}
Grp_PutParAllGroups ();
Par_PutParChar ("IsReply",'Y');
ParCod_PutPar (ParCod_Msg,MsgCod);
Usr_PutParUsrCodEncrypted (UsrDat->EnUsrCod);
Par_PutParChar ("ShowOnlyOneRecipient",'Y');
2014-12-01 23:55:08 +01:00
/****** Link *****/
Ico_PutIconLink ("reply.svg",Ico_BLACK,ActReqMsgUsr);
/****** End form *****/
2019-01-11 02:55:01 +01:00
Frm_EndForm ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************** Write author of a message ************************/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_WriteMsgFrom (struct Msg_Messages *Messages,
struct Usr_Data *UsrDat,bool Deleted)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_MSG_Sent;
extern const char *Txt_MSG_Sent_and_deleted;
2015-03-12 14:45:40 +01:00
extern const char *Txt_ROLES_SINGUL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
static const char *ClassPhoto[PhoSha_NUM_SHAPES] =
{
[PhoSha_SHAPE_CIRCLE ] = "PHOTOC21x28",
[PhoSha_SHAPE_ELLIPSE ] = "PHOTOE21x28",
[PhoSha_SHAPE_OVAL ] = "PHOTOO21x28",
[PhoSha_SHAPE_RECTANGLE] = "PHOTOR21x28",
};
2014-12-01 23:55:08 +01:00
2019-10-23 19:05:05 +02:00
HTM_TABLE_Begin (NULL);
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
/***** Put an icon to show if user has read the message *****/
HTM_TD_Begin ("class=\"LM\" style=\"width:20px;\"");
if (Deleted)
Ico_PutIcon ("share.svg",Ico_RED ,Txt_MSG_Sent_and_deleted,"ICO16x16");
else
Ico_PutIcon ("share.svg",Ico_BLACK,Txt_MSG_Sent ,"ICO16x16");
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Put user's photo *****/
HTM_TD_Begin ("class=\"CM\" style=\"width:30px;\"");
Pho_ShowUsrPhotoIfAllowed (UsrDat,
ClassPhoto[Gbl.Prefs.PhotoShape],Pho_ZOOM);
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Write user's name *****/
HTM_TD_Begin ("class=\"LM MSG_AUT_%s\"",The_GetSuffix ());
if (UsrDat->UsrCod > 0)
{
HTM_Txt (UsrDat->FullName);
if (Act_GetSuperAction (Gbl.Action.Act) == ActSeeRcvMsg)
{
HTM_NBSP ();
if (Msg_DB_CheckIfUsrIsBanned (UsrDat->UsrCod,Gbl.Usrs.Me.UsrDat.UsrCod))
// Sender is banned
Msg_PutFormToUnbanSender (Messages,UsrDat);
else
// Sender is not banned
Msg_PutFormToBanSender (Messages,UsrDat);
}
}
else
HTM_TxtF ("[%s]",Txt_ROLES_SINGUL_abc[Rol_UNK][Usr_SEX_UNKNOWN]); // User not found, likely an old user who has been removed
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
HTM_TR_End ();
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************** Write list of recipients of a message ******************/
/*****************************************************************************/
#define Msg_MAX_RECIPIENTS_TO_SHOW 10 // If number of recipients <= Msg_MAX_RECIPIENTS_TO_SHOW, show all recipients
#define Msg_DEF_RECIPIENTS_TO_SHOW 5 // If number of recipients > Msg_MAX_RECIPIENTS_TO_SHOW, show only Msg_DEF_RECIPIENTS_TO_SHOW
2020-04-11 15:21:30 +02:00
static void Msg_WriteMsgTo (struct Msg_Messages *Messages,long MsgCod)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_MSG_Open_and_deleted;
extern const char *Txt_MSG_Open;
extern const char *Txt_MSG_Deleted_without_opening;
extern const char *Txt_MSG_Unopened;
extern const char *Txt_unknown_recipient;
extern const char *Txt_unknown_recipients;
extern const char *Txt_View_all_recipients;
extern const char *Txt_and_X_other_recipients;
extern const char *Txt_unknown_recipient;
extern const char *Txt_unknown_recipients;
static Act_Action_t ActionSee[Msg_NUM_TYPES_OF_MSGS] =
{
[Msg_WRITING ] = ActUnk,
[Msg_RECEIVED] = ActSeeRcvMsg,
[Msg_SENT ] = ActSeeSntMsg,
};
static const char *ClassPhoto[PhoSha_NUM_SHAPES] =
{
[PhoSha_SHAPE_CIRCLE ] = "PHOTOC21x28",
[PhoSha_SHAPE_ELLIPSE ] = "PHOTOE21x28",
[PhoSha_SHAPE_OVAL ] = "PHOTOO21x28",
[PhoSha_SHAPE_RECTANGLE] = "PHOTOR21x28",
};
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRcp;
struct
{
unsigned Total;
unsigned Known;
unsigned Unknown;
unsigned ToShow;
} NumRecipients;
struct Usr_Data UsrDat;
2014-12-01 23:55:08 +01:00
bool Deleted;
bool OpenByDst;
bool UsrValid;
bool ShowPhoto;
2015-07-22 11:56:26 +02:00
const char *Title;
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2014-12-01 23:55:08 +01:00
/***** Get number of recipients of a message from database *****/
NumRecipients.Total = Msg_DB_GetNumRecipients (MsgCod);
2014-12-01 23:55:08 +01:00
/***** Get recipients of a message from database *****/
NumRecipients.Known = Msg_DB_GetKnownRecipients (&mysql_res,MsgCod);
2014-12-01 23:55:08 +01:00
/***** Check number of recipients *****/
if (NumRecipients.Total)
2014-12-01 23:55:08 +01:00
{
2019-10-20 22:00:28 +02:00
/***** Begin table *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_Begin (NULL);
2014-12-01 23:55:08 +01:00
/***** How many recipients will be shown? *****/
if (NumRecipients.Known <= Msg_MAX_RECIPIENTS_TO_SHOW)
NumRecipients.ToShow = NumRecipients.Known;
else // A lot of recipients
/***** Get parameter that indicates if I want to see all recipients *****/
NumRecipients.ToShow = Par_GetParBool ("SeeAllRcpts") ? NumRecipients.Known :
Msg_DEF_RECIPIENTS_TO_SHOW;
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDat);
/***** Write known recipients *****/
for (NumRcp = 0;
NumRcp < NumRecipients.ToShow;
NumRcp++)
{
row = mysql_fetch_row (mysql_res);
/* Get user's code (row[0]) */
UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
/* Get if message has been deleted (row[1]) and read (row[2]) by recipient */
Deleted = (row[1][0] == 'Y');
OpenByDst = (row[2][0] == 'Y');
/* Get user's data */
UsrValid = Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CRS);
/* Put an icon to show if user has read the message */
Title = OpenByDst ? (Deleted ? Txt_MSG_Open_and_deleted :
Txt_MSG_Open) :
(Deleted ? Txt_MSG_Deleted_without_opening :
Txt_MSG_Unopened);
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"LM\" style=\"width:20px;\"");
if (OpenByDst)
Ico_PutIcon ("envelope-open-text.svg",Deleted ? Ico_RED :
Ico_BLACK,
Title,"ICO16x16");
else
Ico_PutIcon ("envelope.svg" ,Deleted ? Ico_RED :
Ico_BLACK,
Title,"ICO16x16");
HTM_TD_End ();
/* Put user's photo */
HTM_TD_Begin ("class=\"CT\" style=\"width:30px;\"");
ShowPhoto = (UsrValid ? Pho_ShowingUsrPhotoIsAllowed (&UsrDat,PhotoURL) :
false);
Pho_ShowUsrPhoto (&UsrDat,ShowPhoto ? PhotoURL :
NULL,
ClassPhoto[Gbl.Prefs.PhotoShape],Pho_ZOOM);
HTM_TD_End ();
/* Write user's name */
HTM_TD_Begin ("class=\"LM %s_%s\"",
OpenByDst ? "MSG_AUT" :
"MSG_AUT_NEW",
The_GetSuffix ());
if (UsrValid)
HTM_Txt (UsrDat.FullName);
else
HTM_TxtF ("[%s]",Txt_unknown_recipient); // User not found, likely a user who has been removed
HTM_TD_End ();
2019-10-09 15:44:12 +02:00
HTM_TR_End ();
}
2014-12-01 23:55:08 +01:00
/***** If any recipients are unknown *****/
if ((NumRecipients.Unknown = NumRecipients.Total - NumRecipients.Known))
{
/***** Begin form to show all users *****/
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
HTM_TD_Begin ("colspan=\"3\" class=\"LM MSG_AUT_%s\"",
The_GetSuffix ());
HTM_TxtF ("[%u %s]",
NumRecipients.Unknown,
(NumRecipients.Unknown == 1) ? Txt_unknown_recipient :
Txt_unknown_recipients);
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
HTM_TR_End ();
}
2014-12-01 23:55:08 +01:00
/***** If any known recipient is not listed *****/
if (NumRecipients.ToShow < NumRecipients.Known)
{
/***** Begin form to show all users *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("colspan=\"3\" class=\"LM MSG_AUT_%s\"",
The_GetSuffix ());
Frm_BeginForm (ActionSee[Messages->TypeOfMessages]);
Messages->MsgCod = MsgCod; // Message to be expanded with all recipients visible
Msg_PutParsOneMsg (Messages);
Par_PutParChar ("SeeAllRcpts",'Y');
HTM_BUTTON_Submit_Begin (Txt_View_all_recipients,
"class=\"LM BT_LINK\"");
HTM_TxtF (Txt_and_X_other_recipients,
NumRecipients.Known - NumRecipients.ToShow);
HTM_BUTTON_End ();
Frm_EndForm ();
HTM_TD_End ();
HTM_TR_End ();
}
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDat);
2014-12-01 23:55:08 +01:00
/***** End table *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/******************* Write the date of creation of a message *****************/
/*****************************************************************************/
2015-10-24 20:12:03 +02:00
// TimeUTC holds UTC date and time in UNIX format (seconds since 1970)
2014-12-01 23:55:08 +01:00
void Msg_WriteMsgDate (time_t TimeUTC,const char *ClassTxt,const char *ClassBg)
2014-12-01 23:55:08 +01:00
{
2015-10-24 20:12:03 +02:00
static unsigned UniqueId = 0;
2019-11-01 22:53:39 +01:00
char *Id;
2015-10-24 20:12:03 +02:00
UniqueId++;
2019-11-01 22:53:39 +01:00
if (asprintf (&Id,"msg_date_%u",UniqueId) < 0)
Err_NotEnoughMemoryExit ();
2015-10-24 20:12:03 +02:00
/***** Begin cell *****/
HTM_TD_Begin ("id=\"%s\" class=\"RT %s_%s %s_%s\" style=\"width:106px;\"",
Id,
ClassTxt,The_GetSuffix (),
ClassBg,The_GetSuffix ());
2014-12-01 23:55:08 +01:00
/***** Write date and time *****/
Dat_WriteLocalDateHMSFromUTC (Id,TimeUTC,
Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK,
true,true,false,0x6);
2015-10-24 20:12:03 +02:00
/***** End cell *****/
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-11-01 22:53:39 +01:00
2019-11-06 19:45:20 +01:00
free (Id);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2016-07-01 01:21:34 +02:00
/********************* Write the text (content) of a message *****************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
void Msg_WriteMsgContent (char Content[Cns_MAX_BYTES_LONG_TEXT + 1],
bool InsertLinks,bool ChangeBRToRet)
2014-12-01 23:55:08 +01:00
{
/***** Insert links in URLs *****/
if (InsertLinks)
ALn_InsertLinks (Content,Cns_MAX_BYTES_LONG_TEXT,60);
2014-12-01 23:55:08 +01:00
/***** Write message to file *****/
if (ChangeBRToRet)
Str_FilePrintStrChangingBRToRetAndNBSPToSpace (Fil_GetOutputFile (),Content);
2014-12-01 23:55:08 +01:00
else
2019-11-10 12:36:37 +01:00
HTM_Txt (Content);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Put a form to ban the sender of a message *****************/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_PutFormToBanSender (struct Msg_Messages *Messages,
struct Usr_Data *UsrDat)
2014-12-01 23:55:08 +01:00
{
Frm_BeginForm (ActBanUsrMsg);
Pag_PutParPagNum (Msg_WhatPaginate[Messages->TypeOfMessages],
Messages->CurrentPage);
Usr_PutParUsrCodEncrypted (UsrDat->EnUsrCod);
Msg_PutParsMsgsFilters (Messages);
Ico_PutIconLink ("unlock.svg",Ico_GREEN,ActBanUsrMsg);
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************** Put a form to unban the sender of a message ****************/
/*****************************************************************************/
2020-04-11 15:21:30 +02:00
static void Msg_PutFormToUnbanSender (struct Msg_Messages *Messages,
struct Usr_Data *UsrDat)
2014-12-01 23:55:08 +01:00
{
Frm_BeginForm (ActUnbUsrMsg);
Pag_PutParPagNum (Msg_WhatPaginate[Messages->TypeOfMessages],
Messages->CurrentPage);
Usr_PutParUsrCodEncrypted (UsrDat->EnUsrCod);
Msg_PutParsMsgsFilters (Messages);
Ico_PutIconLink ("lock.svg",Ico_RED,ActUnbUsrMsg);
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********* Ban a sender of a message when showing received messages **********/
/*****************************************************************************/
void Msg_BanSenderWhenShowingMsgs (void)
{
extern const char *Txt_From_this_time_you_will_not_receive_messages_from_X;
/***** Get user's code from form *****/
Usr_GetParOtherUsrCodEncryptedAndGetListIDs ();
2014-12-01 23:55:08 +01:00
/***** Get password, user type and user's data from database *****/
if (!Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CRS))
Err_WrongUserExit ();
2014-12-01 23:55:08 +01:00
/***** Insert pair (sender's code - my code) in table of banned senders if not inserted *****/
Msg_DB_CreateUsrsPairIntoBanned (Gbl.Usrs.Other.UsrDat.UsrCod, // From
Gbl.Usrs.Me.UsrDat.UsrCod); // To
2014-12-01 23:55:08 +01:00
/***** Show alert with the change made *****/
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_From_this_time_you_will_not_receive_messages_from_X,
Gbl.Usrs.Other.UsrDat.FullName);
2014-12-01 23:55:08 +01:00
/**** Show received messages again */
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/******** Unban a sender of a message when showing received messages *********/
/*****************************************************************************/
void Msg_UnbanSenderWhenShowingMsgs (void)
{
/**** Unban sender *****/
Msg_UnbanSender ();
/**** Show received messages again */
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/********** Unban a sender of a message when listing banned users ************/
/*****************************************************************************/
void Msg_UnbanSenderWhenListingUsrs (void)
{
/**** Unban sender *****/
Msg_UnbanSender ();
/**** List banned users again */
Msg_ListBannedUsrs ();
}
/*****************************************************************************/
/************************ Unban a sender of a message ************************/
/*****************************************************************************/
static void Msg_UnbanSender (void)
{
extern const char *Txt_From_this_time_you_can_receive_messages_from_X;
/***** Get user's code from form *****/
Usr_GetParOtherUsrCodEncryptedAndGetListIDs ();
2014-12-01 23:55:08 +01:00
/***** Get password, user type and user's data from database *****/
if (!Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CRS))
Err_WrongUserExit ();
2014-12-01 23:55:08 +01:00
/***** Remove pair (sender's code - my code) from table of banned senders *****/
Msg_DB_RemoveUsrsPairFromBanned (Gbl.Usrs.Other.UsrDat.UsrCod, // From
Gbl.Usrs.Me.UsrDat.UsrCod); // To
2014-12-01 23:55:08 +01:00
/***** Show alert with the change made *****/
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_From_this_time_you_can_receive_messages_from_X,
Gbl.Usrs.Other.UsrDat.FullName);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********** List banned users, who can not sent messages to me **************/
/*****************************************************************************/
void Msg_ListBannedUsrs (void)
{
extern const char *Txt_You_have_not_banned_any_sender;
extern const char *Txt_Banned_users;
static const char *ClassPhoto[PhoSha_NUM_SHAPES] =
{
[PhoSha_SHAPE_CIRCLE ] = "PHOTOC21x28",
[PhoSha_SHAPE_ELLIPSE ] = "PHOTOE21x28",
[PhoSha_SHAPE_OVAL ] = "PHOTOO21x28",
[PhoSha_SHAPE_RECTANGLE] = "PHOTOR21x28",
};
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
unsigned NumUsr;
unsigned NumUsrs;
struct Usr_Data UsrDat;
2014-12-01 23:55:08 +01:00
/***** Get users banned by me *****/
if ((NumUsrs = Msg_DB_GetUsrsBannedBy (&mysql_res,Gbl.Usrs.Me.UsrDat.UsrCod)))
2014-12-01 23:55:08 +01:00
{
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDat);
2019-10-26 02:19:42 +02:00
/***** Begin box and table *****/
Box_BoxTableBegin (Txt_Banned_users,NULL,NULL,NULL,Box_NOT_CLOSABLE,2);
2014-12-01 23:55:08 +01:00
/***** List users *****/
for (NumUsr = 1;
NumUsr <= NumUsrs;
NumUsr++)
{
/* Get user's code */
UsrDat.UsrCod = DB_GetNextCode (mysql_res);
2014-12-01 23:55:08 +01:00
/* Get user's data from database */
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CRS))
{
HTM_TR_Begin (NULL);
2019-10-09 15:44:12 +02:00
/* Put form to unban user */
HTM_TD_Begin ("class=\"BM\"");
Frm_BeginForm (ActUnbUsrLst);
Usr_PutParUsrCodEncrypted (UsrDat.EnUsrCod);
Ico_PutIconLink ("lock.svg",Ico_RED,ActUnbUsrLst);
Frm_EndForm ();
HTM_TD_End ();
/* Show photo */
HTM_TD_Begin ("class=\"LM\" style=\"width:30px;\"");
Pho_ShowUsrPhotoIfAllowed (&UsrDat,
ClassPhoto[Gbl.Prefs.PhotoShape],Pho_ZOOM);
HTM_TD_End ();
/* Write user's full name */
HTM_TD_Txt_Left (UsrDat.FullName);
2019-10-07 17:36:41 +02:00
HTM_TR_End ();
}
}
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End table and box *****/
2019-11-25 23:18:08 +01:00
Box_BoxTableEnd ();
2014-12-01 23:55:08 +01:00
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDat);
}
else // If not result ==> sent message is deleted
Ale_ShowAlert (Ale_INFO,Txt_You_have_not_banned_any_sender);
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/************************ Show figures about messages ************************/
/*****************************************************************************/
void Msg_GetAndShowMsgsStats (void)
{
extern const char *Hlp_ANALYTICS_Figures_messages;
extern const char *Txt_FIGURE_TYPES[Fig_NUM_FIGURES];
extern const char *Txt_Messages;
extern const char *Txt_MSGS_Not_deleted;
extern const char *Txt_MSGS_Deleted;
extern const char *Txt_Total;
extern const char *Txt_Number_of_BR_notifications;
extern const char *Txt_MSGS_Sent;
extern const char *Txt_MSGS_Received;
unsigned NumMsgsSentNotDeleted,NumMsgsSentDeleted;
unsigned NumMsgsReceivedNotDeleted,NumMsgsReceivedAndDeleted;
unsigned NumMsgsReceivedAndNotified;
/***** Get the number of unique messages sent from this location *****/
NumMsgsSentNotDeleted = Msg_DB_GetNumSntMsgs (Gbl.Scope.Current,Msg_STATUS_ALL );
NumMsgsSentDeleted = Msg_DB_GetNumSntMsgs (Gbl.Scope.Current,Msg_STATUS_DELETED );
NumMsgsReceivedNotDeleted = Msg_DB_GetNumRcvMsgs (Gbl.Scope.Current,Msg_STATUS_ALL );
NumMsgsReceivedAndDeleted = Msg_DB_GetNumRcvMsgs (Gbl.Scope.Current,Msg_STATUS_DELETED );
NumMsgsReceivedAndNotified = Msg_DB_GetNumRcvMsgs (Gbl.Scope.Current,Msg_STATUS_NOTIFIED);
/***** Begin box and table *****/
Box_BoxTableBegin (Txt_FIGURE_TYPES[Fig_MESSAGES],NULL,NULL,
Hlp_ANALYTICS_Figures_messages,Box_NOT_CLOSABLE,2);
/***** Write table heading *****/
HTM_TR_Begin (NULL);
HTM_TH (Txt_Messages ,HTM_HEAD_LEFT);
HTM_TH (Txt_MSGS_Not_deleted ,HTM_HEAD_RIGHT);
HTM_TH (Txt_MSGS_Deleted ,HTM_HEAD_RIGHT);
HTM_TH (Txt_Total ,HTM_HEAD_RIGHT);
HTM_TH (Txt_Number_of_BR_notifications,HTM_HEAD_RIGHT);
HTM_TR_End ();
/***** Write number of messages *****/
HTM_TR_Begin (NULL);
HTM_TD_Txt_Left (Txt_MSGS_Sent);
HTM_TD_Unsigned (NumMsgsSentNotDeleted);
HTM_TD_Unsigned (NumMsgsSentDeleted);
HTM_TD_Unsigned (NumMsgsSentNotDeleted + NumMsgsSentDeleted);
HTM_TD_Txt_Right ("-");
HTM_TR_End ();
HTM_TR_Begin (NULL);
HTM_TD_Txt_Left (Txt_MSGS_Received);
HTM_TD_Unsigned (NumMsgsReceivedNotDeleted);
HTM_TD_Unsigned (NumMsgsReceivedAndDeleted);
HTM_TD_Unsigned (NumMsgsReceivedNotDeleted + NumMsgsReceivedAndDeleted);
HTM_TD_Unsigned (NumMsgsReceivedAndNotified);
HTM_TR_End ();
/***** End table and box *****/
Box_BoxTableEnd ();
}