// 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-2019 Antonio Caņas Vargas
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 .
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
#include // For PATH_MAX
#include // For NULL
#include // For asprintf
#include // For free
#include // For string functions
#include // For time
#include "swad_action.h"
#include "swad_box.h"
#include "swad_config.h"
#include "swad_course.h"
#include "swad_database.h"
#include "swad_form.h"
#include "swad_forum.h"
#include "swad_global.h"
#include "swad_group.h"
#include "swad_HTML.h"
#include "swad_ID.h"
#include "swad_message.h"
#include "swad_notification.h"
#include "swad_parameter.h"
#include "swad_photo.h"
#include "swad_profile.h"
#include "swad_user.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
#define Msg_MAX_BYTES_MESSAGES_QUERY (4 * 1024 - 1)
// 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
#define Msg_IMAGE_SAVED_MAX_HEIGHT 512
#define Msg_IMAGE_SAVED_QUALITY 75 // 1 to 100
static const Pag_WhatPaginate_t Msg_WhatPaginate[Msg_NUM_TYPES_OF_MSGS] =
{
Pag_MESSAGES_RECEIVED, // Msg_MESSAGES_RECEIVED
Pag_MESSAGES_SENT // Msg_MESSAGES_SENT
};
/*****************************************************************************/
/******************************** Private types ******************************/
/*****************************************************************************/
/*****************************************************************************/
/**************************** Internal prototypes ****************************/
/*****************************************************************************/
static void Msg_PutFormMsgUsrs (char Content[Cns_MAX_BYTES_LONG_TEXT + 1]);
static void Msg_ShowSentOrReceivedMessages (void);
static unsigned long Msg_GetNumUsrsBannedByMe (void);
static void Msg_PutLinkToViewBannedUsers(void);
static unsigned long Msg_GetSentOrReceivedMsgs (long UsrCod,
long FilterCrsCod,
const char *FilterFromToSubquery,
MYSQL_RES **mysql_res);
static char *Msg_WriteNumMsgs (unsigned NumUnreadMsgs);
static void Msg_PutIconsListMsgs (void);
static void Msg_PutHiddenParamsOneMsg (void);
static void Msg_ShowFormToShowOnlyUnreadMessages (void);
static void Msg_GetParamOnlyUnreadMsgs (void);
static void Msg_ShowASentOrReceivedMessage (long MsgNum,long MsgCod);
static void Msg_GetStatusOfSentMsg (long MsgCod,bool *Expanded);
static void Msg_GetStatusOfReceivedMsg (long MsgCod,bool *Open,bool *Replied,bool *Expanded);
static long Msg_GetParamMsgCod (void);
static void Msg_PutLinkToShowMorePotentialRecipients (void);
static void Msg_PutParamsShowMorePotentialRecipients (void);
static void Msg_PutParamsWriteMsg (void);
static void Msg_ShowOneUniqueRecipient (void);
static void Msg_WriteFormUsrsIDsOrNicksOtherRecipients (void);
static void Msg_WriteFormSubjectAndContentMsgToUsrs (char Content[Cns_MAX_BYTES_LONG_TEXT + 1]);
static void Msg_ShowNumMsgsDeleted (unsigned NumMsgs);
static void Msg_MakeFilterFromToSubquery (char FilterFromToSubquery[Msg_MAX_BYTES_MESSAGES_QUERY + 1]);
static void Msg_ExpandSentMsg (long MsgCod);
static void Msg_ExpandReceivedMsg (long MsgCod);
static void Msg_ContractSentMsg (long MsgCod);
static void Msg_ContractReceivedMsg (long MsgCod);
static long Msg_InsertNewMsg (const char *Subject,const char *Content,
struct Media *Media);
static unsigned long Msg_DelSomeRecOrSntMsgsUsr (Msg_TypeOfMessages_t TypeOfMessages,long UsrCod,
long FilterCrsCod,const char *FilterFromToSubquery);
static void Msg_InsertReceivedMsgIntoDB (long MsgCod,long UsrCod,bool NotifyByEmail);
static void Msg_SetReceivedMsgAsReplied (long MsgCod);
static void Msg_MoveReceivedMsgToDeleted (long MsgCod,long UsrCod);
static void Msg_MoveSentMsgToDeleted (long MsgCod);
static void Msg_MoveMsgContentToDeleted (long MsgCod);
static bool Msg_CheckIfSentMsgIsDeleted (long MsgCod);
static bool Msg_CheckIfReceivedMsgIsDeletedForAllItsRecipients (long MsgCod);
static unsigned Msg_GetNumUnreadMsgs (long FilterCrsCod,const char *FilterFromToSubquery);
static void Msg_GetMsgSntData (long MsgCod,long *CrsCod,long *UsrCod,
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],
struct Media *Media);
static void Msg_WriteSentOrReceivedMsgSubject (long MsgCod,const char *Subject,bool Open,bool Expanded);
static void Msg_WriteFormToReply (long MsgCod,long CrsCod,
bool ThisCrs,bool Replied,
const struct UsrData *UsrDat);
static void Msg_WriteMsgFrom (struct UsrData *UsrDat,bool Deleted);
static void Msg_WriteMsgTo (long MsgCod);
static void Msg_PutFormToBanSender (struct UsrData *UsrDat);
static void Msg_PutFormToUnbanSender (struct UsrData *UsrDat);
static void Msg_UnbanSender (void);
/*****************************************************************************/
/***************** Put a form to write a new message to users ****************/
/*****************************************************************************/
void Msg_FormMsgUsrs (void)
{
char Content[Cns_MAX_BYTES_LONG_TEXT + 1];
/***** Get possible hidden subject and content of the message *****/
Par_GetParToHTML ("HiddenSubject",Gbl.Msg.Subject,Cns_MAX_BYTES_SUBJECT);
Par_GetParAndChangeFormat ("HiddenContent",Content,Cns_MAX_BYTES_LONG_TEXT,
Str_TO_TEXT,false);
/***** Show a form to compose a message to users *****/
Msg_PutFormMsgUsrs (Content);
}
/*****************************************************************************/
/***************** Put a form to write a new message to users ****************/
/*****************************************************************************/
static void Msg_PutFormMsgUsrs (char Content[Cns_MAX_BYTES_LONG_TEXT + 1])
{
extern const char *Hlp_MESSAGES_Write;
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_Reply_message;
extern const char *Txt_New_message;
extern const char *Txt_MSG_To;
extern const char *Txt_Send_message;
unsigned NumUsrsInCrs = 0; // Initialized to avoid warning
bool ShowUsrsInCrs = false;
bool GetUsrsInCrs;
Gbl.Usrs.LstUsrs[Rol_STD].NumUsrs =
Gbl.Usrs.LstUsrs[Rol_NET].NumUsrs =
Gbl.Usrs.LstUsrs[Rol_TCH].NumUsrs = 0;
/***** Get parameter that indicates if the message is a reply to another message *****/
if ((Gbl.Msg.Reply.IsReply = Par_GetParToBool ("IsReply")))
/* Get original message code */
if ((Gbl.Msg.Reply.OriginalMsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/***** Get user's code of possible preselected recipient *****/
if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) // There is a preselected recipient
/* Get who to show as potential recipients:
- only the selected recipient
- any user (default) */
Gbl.Msg.ShowOnlyOneRecipient = Par_GetParToBool ("ShowOnlyOneRecipient");
else
Gbl.Msg.ShowOnlyOneRecipient = false;
GetUsrsInCrs = !Gbl.Msg.ShowOnlyOneRecipient && // Show list of potential recipients
(Gbl.Usrs.Me.IBelongToCurrentCrs || // If there is a course selected and I belong to it
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
if (GetUsrsInCrs)
{
/***** Get and update type of list,
number of columns in class photo
and preference about view photos *****/
Usr_GetAndUpdatePrefsAboutUsrList ();
/***** 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);
NumUsrsInCrs = Gbl.Usrs.LstUsrs[Rol_STD].NumUsrs + // Students
Gbl.Usrs.LstUsrs[Rol_NET].NumUsrs + // Non-editing teachers
Gbl.Usrs.LstUsrs[Rol_TCH].NumUsrs; // Teachers
}
/***** Begin box *****/
Box_BoxBegin (NULL,Gbl.Msg.Reply.IsReply ? Txt_Reply_message :
Txt_New_message,NULL,
Hlp_MESSAGES_Write,Box_NOT_CLOSABLE);
if (Gbl.Msg.ShowOnlyOneRecipient)
/***** Form to show several potential recipients *****/
Msg_PutLinkToShowMorePotentialRecipients ();
else
{
/***** Get list of users belonging to the current course *****/
if (GetUsrsInCrs)
{
/***** Form to select groups *****/
Grp_ShowFormToSelectSeveralGroups (Msg_PutParamsWriteMsg,
Grp_MY_GROUPS);
/***** Start section with user list *****/
HTM_SECTION_Begin (Usr_USER_LIST_SECTION_ID);
if (NumUsrsInCrs)
{
/***** Form to select type of list used for select several users *****/
Usr_ShowFormsToSelectUsrListType (Msg_PutParamsWriteMsg);
/***** Put link to register students *****/
Enr_CheckStdsAndPutButtonToRegisterStdsInCurrentCrs ();
/***** Check if it's a big list *****/
ShowUsrsInCrs = Usr_GetIfShowBigList (NumUsrsInCrs,Msg_PutParamsWriteMsg,
"CopyMessageToHiddenFields();");
if (ShowUsrsInCrs)
/***** Get lists of selected users *****/
Usr_GetListsSelectedUsrsCods ();
}
/***** End section with user list *****/
HTM_SECTION_End ();
}
/***** Get list of users' IDs or nicknames written explicitely *****/
Usr_GetListMsgRecipientsWrittenExplicitelyBySender (false);
}
/***** Begin form to select recipients and write the message *****/
Frm_StartForm (ActRcvMsgUsr);
if (Gbl.Msg.Reply.IsReply)
{
Par_PutHiddenParamChar ("IsReply",'Y');
Msg_PutHiddenParamMsgCod (Gbl.Msg.Reply.OriginalMsgCod);
}
if (Gbl.Usrs.Other.UsrDat.UsrCod > 0)
{
Usr_PutParamOtherUsrCodEncrypted ();
if (Gbl.Msg.ShowOnlyOneRecipient)
Par_PutHiddenParamChar ("ShowOnlyOneRecipient",'Y');
}
/***** Begin table *****/
HTM_TABLE_BeginCenterPadding (2);
/***** "To:" section (recipients) *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_MSG_To);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LT\"");
if (Gbl.Msg.ShowOnlyOneRecipient)
/***** Show only one user as recipient *****/
Msg_ShowOneUniqueRecipient ();
else
{
/***** Show potential recipients *****/
HTM_TABLE_BeginWide ();
if (ShowUsrsInCrs)
{
Usr_ListUsersToSelect (Rol_TCH); // All teachers in course
Usr_ListUsersToSelect (Rol_NET); // All non-editing teachers in course
Usr_ListUsersToSelect (Rol_STD); // All students in selected groups
}
Msg_WriteFormUsrsIDsOrNicksOtherRecipients (); // Other users (nicknames)
HTM_TABLE_End ();
}
HTM_TD_End ();
HTM_TR_End ();
/***** Subject and content sections *****/
Msg_WriteFormSubjectAndContentMsgToUsrs (Content);
/***** End table *****/
HTM_TABLE_End ();
/***** Help for text editor and send button *****/
Lay_HelpPlainEditor ();
/***** Attached image (optional) *****/
Med_PutMediaUploader (-1,"MSG_MED_INPUT");
/***** Send button *****/
Btn_PutCreateButton (Txt_Send_message);
/***** End form *****/
Frm_EndForm ();
/***** End box *****/
Box_BoxEnd ();
/***** Free memory used by the list of nicknames *****/
Usr_FreeListOtherRecipients ();
/***** Free memory used for by the lists of users *****/
if (GetUsrsInCrs)
{
Usr_FreeUsrsList (Rol_TCH);
Usr_FreeUsrsList (Rol_NET);
Usr_FreeUsrsList (Rol_STD);
}
/***** Free memory used by list of selected users' codes *****/
Usr_FreeListsSelectedUsrsCods ();
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
}
/*****************************************************************************/
/********** Put contextual link to show more potential recipients ************/
/*****************************************************************************/
static void Msg_PutLinkToShowMorePotentialRecipients (void)
{
extern const char *Txt_Show_more_recipients;
/***** Contextual menu *****/
Mnu_ContextMenuBegin ();
Lay_PutContextualLinkIconTextOnSubmit (ActReqMsgUsr,NULL,
Msg_PutParamsShowMorePotentialRecipients,
"users.svg",
Txt_Show_more_recipients,
"CopyMessageToHiddenFields();"); // Shor more potential recipients
Mnu_ContextMenuEnd ();
}
/*****************************************************************************/
/************ Put parameters to show more potential recipients ***************/
/*****************************************************************************/
static void Msg_PutParamsShowMorePotentialRecipients (void)
{
if (Gbl.Msg.Reply.IsReply)
{
Par_PutHiddenParamChar ("IsReply",'Y');
Msg_PutHiddenParamMsgCod (Gbl.Msg.Reply.OriginalMsgCod);
}
if (Gbl.Usrs.Other.UsrDat.UsrCod > 0)
Usr_PutParamOtherUsrCodEncrypted ();
/***** Hidden params to send subject and content *****/
Msg_PutHiddenParamsSubjectAndContent ();
}
/*****************************************************************************/
/***************** Put parameters when writing a message *********************/
/*****************************************************************************/
static void Msg_PutParamsWriteMsg (void)
{
Usr_PutHiddenParSelectedUsrsCods ();
Msg_PutHiddenParamOtherRecipients ();
Msg_PutHiddenParamsSubjectAndContent ();
if (Gbl.Msg.Reply.IsReply)
{
Par_PutHiddenParamChar ("IsReply",'Y');
Msg_PutHiddenParamMsgCod (Gbl.Msg.Reply.OriginalMsgCod);
}
if (Gbl.Usrs.Other.UsrDat.UsrCod > 0)
{
Usr_PutParamOtherUsrCodEncrypted ();
if (Gbl.Msg.ShowOnlyOneRecipient)
Par_PutHiddenParamChar ("ShowOnlyOneRecipient",'Y');
}
}
/*****************************************************************************/
/********** Put hidden parameters with message subject and content ***********/
/*****************************************************************************/
void Msg_PutHiddenParamsSubjectAndContent (void)
{
/***** Hidden params to send subject and content.
When the user edit the subject or the content,
they are copied here. *****/
Par_PutHiddenParamString (NULL,"HiddenSubject","");
Par_PutHiddenParamString (NULL,"HiddenContent","");
}
/*****************************************************************************/
/************ Put parameters to show more potential recipients ***************/
/*****************************************************************************/
static void Msg_ShowOneUniqueRecipient (void)
{
char PhotoURL[PATH_MAX + 1];
bool ShowPhoto;
/***** Show user's photo *****/
ShowPhoto = Pho_ShowingUsrPhotoIsAllowed (&Gbl.Usrs.Other.UsrDat,PhotoURL);
Pho_ShowUsrPhoto (&Gbl.Usrs.Other.UsrDat,ShowPhoto ? PhotoURL :
NULL,
"PHOTO21x28",Pho_ZOOM,false);
/****** Write user's IDs ******/
HTM_DIV_Begin ("class=\"MSG_TO_ONE_RCP %s\"",
Gbl.Usrs.Other.UsrDat.Accepted ? "DAT_SMALL_NOBR_N" :
"DAT_SMALL_NOBR");
ID_WriteUsrIDs (&Gbl.Usrs.Other.UsrDat,NULL);
HTM_DIV_End ();
/***** Write user's name *****/
HTM_DIV_Begin ("class=\"MSG_TO_ONE_RCP %s\"",
Gbl.Usrs.Other.UsrDat.Accepted ? "DAT_SMALL_NOBR_N" :
"DAT_SMALL_NOBR");
fprintf (Gbl.F.Out,"%s",Gbl.Usrs.Other.UsrDat.FullName);
HTM_DIV_End ();
/***** Hidden parameter with user's nickname *****/
Msg_PutHiddenParamAnotherRecipient (&Gbl.Usrs.Other.UsrDat);
}
/*****************************************************************************/
/************** Nicknames of recipients of a message to users ****************/
/*****************************************************************************/
static void Msg_WriteFormUsrsIDsOrNicksOtherRecipients (void)
{
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_NICKNAME_WITHOUT_ARROBA + 1];
unsigned ColSpan;
bool StdsAndTchsWritten = Gbl.Hierarchy.Level == Hie_CRS && // Course selected
(Gbl.Usrs.Me.IBelongToCurrentCrs || // I belong to it
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
/***** How many columns? *****/
if (StdsAndTchsWritten)
ColSpan = Usr_GetColumnsForSelectUsrs ();
else
ColSpan = 1;
/***** Title *****/
HTM_TR_Begin (NULL);
HTM_TH_Begin (1,ColSpan,"LM LIGHT_BLUE");
HTM_LABEL_Begin ("for=\"OtherRecipients\"");
fprintf (Gbl.F.Out,"%s:",StdsAndTchsWritten ? Txt_Other_recipients :
Txt_Recipients);
HTM_LABEL_End ();
HTM_TH_End ();
HTM_TR_End ();
/***** Textarea with users' @nicknames, emails or IDs *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("colspan=\"%u\" class=\"LM\"",ColSpan);
HTM_TEXTAREA_Begin ("id=\"OtherRecipients\" name=\"OtherRecipients\""
" class=\"MSG_RECIPIENTS\" rows=\"2\" placeholder=\"%s\"",
Txt_nicks_emails_or_IDs_separated_by_commas);
if (Gbl.Usrs.ListOtherRecipients[0])
fprintf (Gbl.F.Out,"%s",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
if (Nck_GetNicknameFromUsrCod (Gbl.Usrs.Other.UsrDat.UsrCod,Nickname))
fprintf (Gbl.F.Out,"@%s",Nickname);
HTM_TEXTAREA_End ();
HTM_TD_End ();
HTM_TR_End ();
}
/*****************************************************************************/
/****** Write form fields with subject and content of a message to users *****/
/*****************************************************************************/
static void Msg_WriteFormSubjectAndContentMsgToUsrs (char Content[Cns_MAX_BYTES_LONG_TEXT + 1])
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_MSG_Subject;
extern const char *Txt_MSG_Content;
extern const char *Txt_Original_message;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
long MsgCod;
bool SubjectAndContentComeFromForm = (Gbl.Msg.Subject[0] || Content[0]);
/***** Get possible code (of original message if it's a reply) *****/
MsgCod = Msg_GetParamMsgCod ();
/***** Message subject *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RT\"");
HTM_LABEL_Begin ("for=\"MsgSubject\" class=\"%s\"",
The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_MSG_Subject);
HTM_LABEL_End ();
HTM_TD_End ();
HTM_TD_Begin ("class=\"LM\"");
HTM_TEXTAREA_Begin ("id=\"MsgSubject\" name=\"Subject\""
" class=\"MSG_SUBJECT\" rows=\"2\"");
/* If message is a reply ==> get original message */
if (MsgCod > 0) // It's a reply
{
if (!SubjectAndContentComeFromForm)
{
/* Get subject and content of message from database */
NumRows = DB_QuerySELECT (&mysql_res,"can not get message content",
"SELECT Subject,Content FROM msg_content"
" WHERE MsgCod=%ld",MsgCod);
/* Result should have a unique row */
if (NumRows != 1)
Lay_ShowErrorAndExit ("Error when getting message.");
row = mysql_fetch_row (mysql_res);
/* Get subject */
Str_Copy (Gbl.Msg.Subject,row[0],
Cns_MAX_BYTES_SUBJECT);
/* Get content */
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)
fprintf (Gbl.F.Out,"Re: ");
fprintf (Gbl.F.Out,"%s",Gbl.Msg.Subject);
HTM_TEXTAREA_End ();
HTM_TD_End ();
HTM_TR_End ();
/***** Message content *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RT\"");
HTM_LABEL_Begin ("for=\"MsgContent\" class=\"%s\"",
The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_MSG_Content);
HTM_LABEL_End ();
HTM_TD_End ();
HTM_TD_Begin ("class=\"LM\"");
HTM_TEXTAREA_Begin ("id=\"MsgContent\" name=\"Content\""
" class=\"MSG_CONTENT\" rows=\"20\"");
/* Start 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 */
fprintf (Gbl.F.Out,"\n");
if (!SubjectAndContentComeFromForm)
fprintf (Gbl.F.Out,"\n\n----- %s -----\n",
Txt_Original_message);
Msg_WriteMsgContent (Content,Cns_MAX_BYTES_LONG_TEXT,false,true);
}
else // It's not a reply
{
/* End message subject */
fprintf (Gbl.F.Out,"%s",Gbl.Msg.Subject);
HTM_TEXTAREA_End ();
HTM_TD_End ();
HTM_TR_End ();
/***** Message content *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RT\"");
HTM_LABEL_Begin ("for=\"MsgContent\" class=\"%s\"",
The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_MSG_Content);
HTM_LABEL_End ();
HTM_TD_End ();
HTM_TD_Begin ("class=\"LM\"");
HTM_TEXTAREA_Begin ("id=\"MsgContent\" name=\"Content\""
" class=\"MSG_CONTENT\" rows=\"20\"");
/* Start 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 */
fprintf (Gbl.F.Out,"\n%s",Content);
}
HTM_TEXTAREA_End ();
HTM_TD_End ();
HTM_TR_End ();
}
/*****************************************************************************/
/********* Put hidden parameter for another recipient (one nickname) *********/
/*****************************************************************************/
void Msg_PutHiddenParamAnotherRecipient (const struct UsrData *UsrDat)
{
char NicknameWithArroba[Nck_MAX_BYTES_NICKNAME_FROM_FORM + 1];
snprintf (NicknameWithArroba,sizeof (NicknameWithArroba),
"@%s",
UsrDat->Nickname);
Par_PutHiddenParamString (NULL,"OtherRecipients",NicknameWithArroba);
}
/*****************************************************************************/
/********* Put hidden parameter for another recipient (one nickname) *********/
/*****************************************************************************/
void Msg_PutHiddenParamOtherRecipients (void)
{
if (Gbl.Usrs.ListOtherRecipients)
if (Gbl.Usrs.ListOtherRecipients[0])
Par_PutHiddenParamString (NULL,"OtherRecipients",Gbl.Usrs.ListOtherRecipients);
}
/*****************************************************************************/
/********************** 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;
extern const char *Txt_message_sent_to_X_notified_by_email;
extern const char *Txt_message_sent_to_X_not_notified_by_email;
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;
bool IsReply;
bool RecipientHasBannedMe;
bool Replied = false;
long OriginalMsgCod = -1L; // Initialized to avoid warning
const char *Ptr;
unsigned NumRecipients;
unsigned NumRecipientsToBeNotifiedByEMail = 0;
struct UsrData UsrDstData;
int NumErrors = 0;
long NewMsgCod = -1L; // Initiliazed to avoid warning
bool MsgAlreadyInserted = false;
bool CreateNotif;
bool NotifyByEmail;
char Content[Cns_MAX_BYTES_LONG_TEXT + 1];
struct Media Media;
bool Error = false;
/***** Get data from form *****/
/* Get subject */
Par_GetParToHTML ("Subject",Gbl.Msg.Subject,Cns_MAX_BYTES_SUBJECT);
/* Get body */
Par_GetParAndChangeFormat ("Content",Content,Cns_MAX_BYTES_LONG_TEXT,
Str_DONT_CHANGE,false);
/* Get parameter that indicates if the message is a reply to a previous message */
if ((IsReply = Par_GetParToBool ("IsReply")))
/* Get original message code */
if ((OriginalMsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/* Get user's code of possible preselected recipient */
Usr_GetParamOtherUsrCodEncryptedAndGetListIDs ();
/* Get lists of selected users */
Usr_GetListsSelectedUsrsCods ();
/* Get list of users' IDs or nicknames written explicitely */
Error = Usr_GetListMsgRecipientsWrittenExplicitelyBySender (true);
/***** Check number of recipients *****/
if ((NumRecipients = Usr_CountNumUsrsInListOfSelectedUsrs ()))
{
if (Gbl.Usrs.Me.Role.Logged == Rol_STD &&
NumRecipients > Cfg_MAX_RECIPIENTS)
{
/* Write warning message */
Ale_ShowAlert (Ale_WARNING,Txt_You_can_not_send_a_message_to_so_many_recipients_);
Error = true;
}
}
else // No recipients selected
{
/* Write warning message */
Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_recipients);
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,true);
Msg_PutFormMsgUsrs (Content);
return;
}
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDstData);
/***** Initialize image *****/
Med_MediaConstructor (&Media);
/***** Get attached image (action, file and title) *****/
Media.Width = Msg_IMAGE_SAVED_MAX_WIDTH;
Media.Height = Msg_IMAGE_SAVED_MAX_HEIGHT;
Media.Quality = Msg_IMAGE_SAVED_QUALITY;
Med_GetMediaFromForm (-1,&Media,NULL,NULL);
Ale_ShowAlerts (NULL);
/***** Loop over the list Gbl.Usrs.Selected.List[Rol_UNK], that holds the list of the
recipients, creating a received message for each recipient *****/
Str_ChangeFormat (Str_FROM_FORM,Str_TO_RIGOROUS_HTML,
Content,Cns_MAX_BYTES_LONG_TEXT,false);
Ptr = Gbl.Usrs.Selected.List[Rol_UNK];
NumRecipients = 0;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UsrDstData.EncryptedUsrCod,
Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64);
Usr_GetUsrCodFromEncryptedUsrCod (&UsrDstData);
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDstData,Usr_DONT_GET_PREFS)) // Get recipient's data from the database
{
/***** Check if recipient has banned me *****/
RecipientHasBannedMe = Msg_CheckIfUsrIsBanned (Gbl.Usrs.Me.UsrDat.UsrCod,UsrDstData.UsrCod);
if (RecipientHasBannedMe)
/***** Show an alert indicating that the message has not been sent successfully *****/
Ale_ShowAlert (Ale_WARNING,Txt_message_not_sent_to_X,
UsrDstData.FullName);
else
{
/***** Create message *****/
if (!MsgAlreadyInserted)
{
// The message is inserted only once in the table of messages sent
NewMsgCod = Msg_InsertNewMsg (Gbl.Msg.Subject,Content,&Media);
MsgAlreadyInserted = true;
}
/***** If this recipient is the original sender of a message been replied, set Replied to true *****/
Replied = (IsReply &&
UsrDstData.UsrCod == Gbl.Usrs.Other.UsrDat.UsrCod);
/***** This received message must be notified by email? *****/
CreateNotif = (UsrDstData.NtfEvents.CreateNotif & (1 << Ntf_EVENT_MESSAGE));
NotifyByEmail = CreateNotif &&
(UsrDstData.UsrCod != Gbl.Usrs.Me.UsrDat.UsrCod) &&
(UsrDstData.NtfEvents.SendEmail & (1 << Ntf_EVENT_MESSAGE));
/***** Create the received message for this recipient
and increment number of new messages received by this recipient *****/
Msg_InsertReceivedMsgIntoDB (NewMsgCod,UsrDstData.UsrCod,NotifyByEmail);
/***** Create notification for this recipient.
If this recipient wants to receive notifications by -mail,
activate the sending of a notification *****/
if (CreateNotif)
Ntf_StoreNotifyEventToOneUser (Ntf_EVENT_MESSAGE,&UsrDstData,NewMsgCod,
(Ntf_Status_t) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL :
0));
/***** Show an alert indicating that the message has been sent successfully *****/
Ale_ShowAlert (Ale_SUCCESS,NotifyByEmail ? Txt_message_sent_to_X_notified_by_email :
Txt_message_sent_to_X_not_notified_by_email,
UsrDstData.FullName);
/***** Increment number of recipients *****/
if (NotifyByEmail)
NumRecipientsToBeNotifiedByEMail++;
NumRecipients++;
}
}
else
{
Ale_ShowAlert (Ale_ERROR,Txt_Error_getting_data_from_a_recipient);
NumErrors++;
}
}
/***** Free image *****/
Med_MediaDestructor (&Media);
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDstData);
/***** Free memory *****/
/* Free memory used for list of users */
Usr_FreeListOtherRecipients ();
Usr_FreeListsSelectedUsrsCods ();
/***** Update received message setting Replied field to true *****/
if (Replied)
Msg_SetReceivedMsgAsReplied (OriginalMsgCod);
/***** Write final message *****/
if (NumRecipients)
{
if (NumRecipients == 1)
Ale_ShowAlert (Ale_SUCCESS,Txt_The_message_has_been_sent_to_1_recipient);
else
Ale_ShowAlert (Ale_SUCCESS,Txt_The_message_has_been_sent_to_X_recipients,
(unsigned) NumRecipients);
}
else
Ale_ShowAlert (Ale_WARNING,Txt_The_message_has_not_been_sent_to_any_recipient);
/***** Show alert about errors on sending message *****/
if (NumErrors > 1)
Ale_ShowAlert (Ale_ERROR,Txt_There_have_been_X_errors_in_sending_the_message,
(unsigned) NumErrors);
}
/*****************************************************************************/
/***************** 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;
/***** Get parameters *****/
Msg_GetParamMsgsCrsCod ();
Msg_GetParamFilterFromTo ();
Msg_GetParamFilterContent ();
Msg_GetParamOnlyUnreadMsgs ();
/***** Show question and button to remove messages received *****/
/* Start alert */
if (Gbl.Msg.FilterContent[0])
{
if (Gbl.Msg.ShowOnlyUnreadMsgs)
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_delete_the_unread_messages_received_from_USER_X_from_COURSE_Y_related_to_CONTENT_Z,
Gbl.Msg.FilterFromTo[0] ? Gbl.Msg.FilterFromTo :
Txt_any_user,
Gbl.Msg.FilterCrsShrtName,Gbl.Msg.FilterContent);
else
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_received_from_USER_X_from_COURSE_Y_related_to_CONTENT_Z,
Gbl.Msg.FilterFromTo[0] ? Gbl.Msg.FilterFromTo :
Txt_any_user,
Gbl.Msg.FilterCrsShrtName,Gbl.Msg.FilterContent);
}
else
{
if (Gbl.Msg.ShowOnlyUnreadMsgs)
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_delete_the_unread_messages_received_from_USER_X_from_COURSE_Y,
Gbl.Msg.FilterFromTo[0] ? Gbl.Msg.FilterFromTo :
Txt_any_user,
Gbl.Msg.FilterCrsShrtName);
else
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_received_from_USER_X_from_COURSE_Y,
Gbl.Msg.FilterFromTo[0] ? Gbl.Msg.FilterFromTo :
Txt_any_user,
Gbl.Msg.FilterCrsShrtName);
}
/* Show received messages again */
Gbl.Msg.TypeOfMessages = Msg_MESSAGES_RECEIVED;
Msg_ShowSentOrReceivedMessages ();
/* End alert */
Ale_ShowAlertAndButton2 (ActDelAllRcvMsg,NULL,NULL,
Msg_PutHiddenParamsMsgsFilters,
Btn_REMOVE_BUTTON,Txt_Delete_messages_received);
}
/*****************************************************************************/
/******************* 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;
/***** Get parameters *****/
Msg_GetParamMsgsCrsCod ();
Msg_GetParamFilterFromTo ();
Msg_GetParamFilterContent ();
/***** Show question and button to remove messages received *****/
/* Start alert */
if (Gbl.Msg.FilterContent[0])
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_sent_to_USER_X_from_COURSE_Y_related_to_CONTENT_Z,
Gbl.Msg.FilterFromTo[0] ? Gbl.Msg.FilterFromTo :
Txt_any_user,
Gbl.Msg.FilterCrsShrtName,Gbl.Msg.FilterContent);
else
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_delete_all_messages_sent_to_USER_X_from_COURSE_Y,
Gbl.Msg.FilterFromTo[0] ? Gbl.Msg.FilterFromTo :
Txt_any_user,
Gbl.Msg.FilterCrsShrtName);
/* Show sent messages again */
Gbl.Msg.TypeOfMessages = Msg_MESSAGES_SENT;
Msg_ShowSentOrReceivedMessages ();
/* End alert */
Ale_ShowAlertAndButton2 (ActDelAllSntMsg,NULL,NULL,
Msg_PutHiddenParamsMsgsFilters,
Btn_REMOVE_BUTTON,Txt_Delete_messages_sent);
}
/*****************************************************************************/
/*********************** Delete all received messages ************************/
/*****************************************************************************/
void Msg_DelAllRecMsgs (void)
{
char FilterFromToSubquery[Msg_MAX_BYTES_MESSAGES_QUERY + 1];
unsigned long NumMsgs;
/***** Get parameters *****/
Msg_GetParamMsgsCrsCod ();
Msg_GetParamFilterFromTo ();
Msg_GetParamFilterContent ();
Msg_GetParamOnlyUnreadMsgs ();
Msg_MakeFilterFromToSubquery (FilterFromToSubquery);
/***** Delete messages *****/
NumMsgs = Msg_DelSomeRecOrSntMsgsUsr (Msg_MESSAGES_RECEIVED,Gbl.Usrs.Me.UsrDat.UsrCod,Gbl.Msg.FilterCrsCod,FilterFromToSubquery);
Msg_ShowNumMsgsDeleted (NumMsgs);
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/************************* Delete all sent messages **************************/
/*****************************************************************************/
void Msg_DelAllSntMsgs (void)
{
char FilterFromToSubquery[Msg_MAX_BYTES_MESSAGES_QUERY + 1];
unsigned long NumMsgs;
/***** Get parameters *****/
Msg_GetParamMsgsCrsCod ();
Msg_GetParamFilterFromTo ();
Msg_GetParamFilterContent ();
Msg_MakeFilterFromToSubquery (FilterFromToSubquery);
/***** Delete messages *****/
NumMsgs = Msg_DelSomeRecOrSntMsgsUsr (Msg_MESSAGES_SENT,Gbl.Usrs.Me.UsrDat.UsrCod,Gbl.Msg.FilterCrsCod,FilterFromToSubquery);
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)
Ale_ShowAlert (Ale_SUCCESS,Txt_One_message_has_been_deleted);
else
Ale_ShowAlert (Ale_SUCCESS,Txt_X_messages_have_been_deleted,
NumMsgs);
}
/*****************************************************************************/
/**************** Get parameter with course origin of messages ***************/
/*****************************************************************************/
void Msg_GetParamMsgsCrsCod (void)
{
extern const char *Txt_any_course;
struct Course Crs;
if ((Gbl.Msg.FilterCrsCod = Par_GetParToLong ("FilterCrsCod")) > 0) // If origin course specified
{
/* Get data of course */
Crs.CrsCod = Gbl.Msg.FilterCrsCod;
Crs_GetDataOfCourseByCod (&Crs);
Str_Copy (Gbl.Msg.FilterCrsShrtName,Crs.ShrtName,
Hie_MAX_BYTES_SHRT_NAME);
}
else
Str_Copy (Gbl.Msg.FilterCrsShrtName,Txt_any_course,
Hie_MAX_BYTES_SHRT_NAME);
}
/*****************************************************************************/
/******************* Get parameter with "from"/"to" filter ********************/
/*****************************************************************************/
void Msg_GetParamFilterFromTo (void)
{
/***** Get "from"/"to" filter *****/
Par_GetParToText ("FilterFromTo",Gbl.Msg.FilterFromTo,
Usr_MAX_BYTES_FULL_NAME);
}
/*****************************************************************************/
/********************* Get parameter with content filter *********************/
/*****************************************************************************/
void Msg_GetParamFilterContent (void)
{
/***** Get content filter *****/
Par_GetParToText ("FilterContent",Gbl.Msg.FilterContent,
Msg_MAX_BYTES_FILTER_CONTENT);
}
/*****************************************************************************/
/************************* Make "from"/"to" subquery *************************/
/*****************************************************************************/
static void Msg_MakeFilterFromToSubquery (char FilterFromToSubquery[Msg_MAX_BYTES_MESSAGES_QUERY + 1])
{
const char *Ptr;
char SearchWord[Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1];
/***** Split "from"/"to" string into words *****/
if (Gbl.Msg.FilterFromTo[0])
{
Ptr = Gbl.Msg.FilterFromTo;
Str_Copy (FilterFromToSubquery,
" AND CONCAT(usr_data.FirstName,' ',usr_data.Surname1,' ',usr_data.Surname2) LIKE '",
Msg_MAX_BYTES_MESSAGES_QUERY);
while (*Ptr)
{
Str_GetNextStringUntilSpace (&Ptr,SearchWord,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
if (strlen (FilterFromToSubquery) + strlen (SearchWord) + 512 >
Msg_MAX_BYTES_MESSAGES_QUERY) // Prevent string overflow
break;
Str_Concat (FilterFromToSubquery,"%",
Msg_MAX_BYTES_MESSAGES_QUERY);
Str_Concat (FilterFromToSubquery,SearchWord,
Msg_MAX_BYTES_MESSAGES_QUERY);
}
Str_Concat (FilterFromToSubquery,"%'",
Msg_MAX_BYTES_MESSAGES_QUERY);
}
else
FilterFromToSubquery[0] = '\0';
}
/*****************************************************************************/
/****************************** Delete a sent message ************************/
/*****************************************************************************/
void Msg_DelSntMsg (void)
{
extern const char *Txt_Message_deleted;
long MsgCod;
/***** Get the code of the message to delete *****/
if ((MsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/***** Delete the message *****/
/* Delete the sent message */
Msg_MoveSentMsgToDeleted (MsgCod);
Ale_ShowAlert (Ale_SUCCESS,Txt_Message_deleted);
/* 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 *****/
if ((MsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/***** Delete the message *****/
/* Delete the received message */
Msg_MoveReceivedMsgToDeleted (MsgCod,Gbl.Usrs.Me.UsrDat.UsrCod);
Ale_ShowAlert (Ale_SUCCESS,Txt_Message_deleted);
/* Show the remaining messages */
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/**************************** Expand a sent message **************************/
/*****************************************************************************/
void Msg_ExpSntMsg (void)
{
/***** Get the code of the message to expand *****/
if ((Gbl.Msg.ExpandedMsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/***** Expand the message *****/
Msg_ExpandSentMsg (Gbl.Msg.ExpandedMsgCod);
/***** Show again the messages *****/
Msg_ShowSntMsgs ();
}
/*****************************************************************************/
/************************** Expand a received message ************************/
/*****************************************************************************/
void Msg_ExpRecMsg (void)
{
/***** Get the code of the message to expand *****/
if ((Gbl.Msg.ExpandedMsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/***** Expand the message *****/
Msg_ExpandReceivedMsg (Gbl.Msg.ExpandedMsgCod);
/***** Mark possible notification as seen *****/
Ntf_MarkNotifAsSeen (Ntf_EVENT_MESSAGE,
Gbl.Msg.ExpandedMsgCod,-1L,
Gbl.Usrs.Me.UsrDat.UsrCod);
/***** Show again the messages *****/
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/*************************** Contract a sent message *************************/
/*****************************************************************************/
void Msg_ConSntMsg (void)
{
long MsgCod;
/***** Get the code of the message to contract *****/
if ((MsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/***** Contract the message *****/
Msg_ContractSentMsg (MsgCod);
/***** Show again the messages *****/
Msg_ShowSntMsgs ();
}
/*****************************************************************************/
/************************* Contract a received message ***********************/
/*****************************************************************************/
void Msg_ConRecMsg (void)
{
long MsgCod;
/***** Get the code of the message to contract *****/
if ((MsgCod = Msg_GetParamMsgCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong code of message.");
/***** Contract the message *****/
Msg_ContractReceivedMsg (MsgCod);
/***** Show again the messages *****/
Msg_ShowRecMsgs ();
}
/*****************************************************************************/
/**************************** Expand a sent message **************************/
/*****************************************************************************/
static void Msg_ExpandSentMsg (long MsgCod)
{
/***** Expand message in sent message table *****/
DB_QueryUPDATE ("can not expand a sent message",
"UPDATE msg_snt SET Expanded='Y'"
" WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,Gbl.Usrs.Me.UsrDat.UsrCod);
/***** Contract all my other messages in sent message table *****/
DB_QueryUPDATE ("can not contract a sent message",
"UPDATE msg_snt SET Expanded='N'"
" WHERE UsrCod=%ld AND MsgCod<>%ld",
Gbl.Usrs.Me.UsrDat.UsrCod,MsgCod);
}
/*****************************************************************************/
/************************* Expand a received message *************************/
/*****************************************************************************/
static void Msg_ExpandReceivedMsg (long MsgCod)
{
/***** Expand message in received message table and mark it as read by me *****/
DB_QueryUPDATE ("can not expand a received message",
"UPDATE msg_rcv SET Open='Y',Expanded='Y'"
" WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,Gbl.Usrs.Me.UsrDat.UsrCod);
/***** Contract all my other messages in received message table *****/
DB_QueryUPDATE ("can not contract a received message",
"UPDATE msg_rcv SET Expanded='N'"
" WHERE UsrCod=%ld AND MsgCod<>%ld",
Gbl.Usrs.Me.UsrDat.UsrCod,MsgCod);
}
/*****************************************************************************/
/************************** Contract a sent message **************************/
/*****************************************************************************/
static void Msg_ContractSentMsg (long MsgCod)
{
/***** Contract message in sent message table *****/
DB_QueryUPDATE ("can not contract a sent message",
"UPDATE msg_snt SET Expanded='N'"
" WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,Gbl.Usrs.Me.UsrDat.UsrCod);
}
/*****************************************************************************/
/************************ Contract a received message ************************/
/*****************************************************************************/
static void Msg_ContractReceivedMsg (long MsgCod)
{
/***** Contract message in received message table *****/
DB_QueryUPDATE ("can not contract a received message",
"UPDATE msg_rcv SET Expanded='N'"
" WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,Gbl.Usrs.Me.UsrDat.UsrCod);
}
/*****************************************************************************/
/********************** Mark a received message as open **********************/
/*****************************************************************************/
void Msg_SetReceivedMsgAsOpen (long MsgCod,long UsrCod)
{
/***** Mark message as read by user *****/
DB_QueryUPDATE ("can not mark a received message as open",
"UPDATE msg_rcv SET Open='Y'"
" WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,UsrCod);
}
/*****************************************************************************/
/********************** Insert a message in the database *********************/
/*****************************************************************************/
// Return the code of the new inserted message
static long Msg_InsertNewMsg (const char *Subject,const char *Content,
struct Media *Media)
{
long MsgCod;
/***** Store media in filesystem and database *****/
Med_RemoveKeepOrStoreMedia (-1L,Media);
/***** Insert message subject and content in the database *****/
MsgCod =
DB_QueryINSERTandReturnCode ("can not create message",
"INSERT INTO msg_content"
" (Subject,Content,MedCod)"
" VALUES"
" ('%s','%s',%ld)",
Subject,Content,Media->MedCod);
/***** Insert message in sent messages *****/
DB_QueryINSERT ("can not create message",
"INSERT INTO msg_snt"
" (MsgCod,CrsCod,UsrCod,Expanded,CreatTime)"
" VALUES"
" (%ld,%ld,%ld,'N',NOW())",
MsgCod,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Usrs.Me.UsrDat.UsrCod);
/***** Increment number of messages sent by me *****/
Prf_IncrementNumMsgSntUsr (Gbl.Usrs.Me.UsrDat.UsrCod);
return MsgCod;
}
/*****************************************************************************/
/************** Delete some received or sent messages of a user **************/
/*****************************************************************************/
static unsigned long Msg_DelSomeRecOrSntMsgsUsr (Msg_TypeOfMessages_t TypeOfMessages,long UsrCod,
long FilterCrsCod,const char *FilterFromToSubquery)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long MsgNum;
unsigned long NumMsgs;
long MsgCod;
/***** Get some of the messages received or sent by this user from database *****/
NumMsgs = Msg_GetSentOrReceivedMsgs (UsrCod,
FilterCrsCod,
FilterFromToSubquery,
&mysql_res);
/***** Delete each message *****/
for (MsgNum = 0;
MsgNum < NumMsgs;
MsgNum++)
{
row = mysql_fetch_row (mysql_res);
if (sscanf (row[0],"%ld",&MsgCod) != 1)
Lay_ShowErrorAndExit ("Wrong code of message.");
switch (TypeOfMessages)
{
case Msg_MESSAGES_RECEIVED:
Msg_MoveReceivedMsgToDeleted (MsgCod,UsrCod);
break;
case Msg_MESSAGES_SENT:
Msg_MoveSentMsgToDeleted (MsgCod);
break;
default:
break;
}
}
/***** Free the MySQL result *****/
DB_FreeMySQLResult (&mysql_res);
return NumMsgs;
}
/*****************************************************************************/
/*************** Delete all received or sent messages of a user **************/
/*****************************************************************************/
void Msg_DelAllRecAndSntMsgsUsr (long UsrCod)
{
/***** Move messages from msg_rcv to msg_rcv_deleted *****/
/* Insert messages into msg_rcv_deleted */
DB_QueryINSERT ("can not remove received messages",
"INSERT IGNORE INTO msg_rcv_deleted"
" (MsgCod,UsrCod,Notified,Open,Replied)"
" SELECT MsgCod,UsrCod,Notified,Open,Replied FROM msg_rcv"
" WHERE UsrCod=%ld",
UsrCod);
/* Delete messages from msg_rcv *****/
DB_QueryDELETE ("can not remove received messages",
"DELETE FROM msg_rcv WHERE UsrCod=%ld",
UsrCod);
/***** Move message from msg_snt to msg_snt_deleted *****/
/* Insert message into msg_snt_deleted */
DB_QueryINSERT ("can not remove sent messages",
"INSERT IGNORE INTO msg_snt_deleted"
" (MsgCod,CrsCod,UsrCod,CreatTime)"
" SELECT MsgCod,CrsCod,UsrCod,CreatTime"
" FROM msg_snt WHERE UsrCod=%ld",
UsrCod);
/* Delete message from msg_snt *****/
DB_QueryDELETE ("can not remove sent messages",
"DELETE FROM msg_snt WHERE UsrCod=%ld",
UsrCod);
}
/*****************************************************************************/
/**** Insert a message y su destinatario in the table of messages received ***/
/*****************************************************************************/
static void Msg_InsertReceivedMsgIntoDB (long MsgCod,long UsrCod,bool NotifyByEmail)
{
/***** Insert message received in the database *****/
DB_QueryINSERT ("can not create received message",
"INSERT INTO msg_rcv"
" (MsgCod,UsrCod,Notified,Open,Replied,Expanded)"
" VALUES"
" (%ld,%ld,'%c','N','N','N')",
MsgCod,UsrCod,
NotifyByEmail ? 'Y' :
'N');
}
/*****************************************************************************/
/******** Update received message by setting Replied field to true ***********/
/*****************************************************************************/
static void Msg_SetReceivedMsgAsReplied (long MsgCod)
{
/***** Update received message by setting Replied field to true *****/
DB_QueryUPDATE ("can not update a received message",
"UPDATE msg_rcv SET Replied='Y'"
" WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,Gbl.Usrs.Me.UsrDat.UsrCod);
}
/*****************************************************************************/
/************ Delete a message from the received message table ***************/
/*****************************************************************************/
static void Msg_MoveReceivedMsgToDeleted (long MsgCod,long UsrCod)
{
/***** Move message from msg_rcv to msg_rcv_deleted *****/
/* Insert message into msg_rcv_deleted */
DB_QueryINSERT ("can not remove a received message",
"INSERT IGNORE INTO msg_rcv_deleted"
" (MsgCod,UsrCod,Notified,Open,Replied)"
" SELECT MsgCod,UsrCod,Notified,Open,Replied"
" FROM msg_rcv WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,UsrCod);
/* Delete message from msg_rcv *****/
DB_QueryDELETE ("can not remove a received message",
"DELETE FROM msg_rcv WHERE MsgCod=%ld AND UsrCod=%ld",
MsgCod,UsrCod);
/***** If message content is not longer necessary, move it to msg_content_deleted *****/
if (Msg_CheckIfSentMsgIsDeleted (MsgCod))
if (Msg_CheckIfReceivedMsgIsDeletedForAllItsRecipients (MsgCod))
Msg_MoveMsgContentToDeleted (MsgCod);
/***** Mark possible notifications as removed *****/
Ntf_MarkNotifToOneUsrAsRemoved (Ntf_EVENT_MESSAGE,MsgCod,UsrCod);
}
/*****************************************************************************/
/************** Delete a message from the sent message table *****************/
/*****************************************************************************/
static void Msg_MoveSentMsgToDeleted (long MsgCod)
{
/***** Move message from msg_snt to msg_snt_deleted *****/
/* Insert message into msg_snt_deleted */
DB_QueryINSERT ("can not remove a sent message",
"INSERT IGNORE INTO msg_snt_deleted"
" (MsgCod,CrsCod,UsrCod,CreatTime)"
" SELECT MsgCod,CrsCod,UsrCod,CreatTime"
" FROM msg_snt WHERE MsgCod=%ld",
MsgCod);
/* Delete message from msg_snt *****/
DB_QueryDELETE ("can not remove a sent message",
"DELETE FROM msg_snt WHERE MsgCod=%ld",
MsgCod);
/***** If message content is not longer necessary, move it to msg_content_deleted *****/
if (Msg_CheckIfReceivedMsgIsDeletedForAllItsRecipients (MsgCod))
Msg_MoveMsgContentToDeleted (MsgCod);
}
/*****************************************************************************/
/*************** Delete the subject and content of a message *****************/
/*****************************************************************************/
static void Msg_MoveMsgContentToDeleted (long MsgCod)
{
/***** Move message from msg_content to msg_content_deleted *****/
/* Insert message content into msg_content_deleted */
DB_QueryINSERT ("can not remove the content of a message",
"INSERT IGNORE INTO msg_content_deleted"
" (MsgCod,Subject,Content,MedCod)"
" SELECT MsgCod,Subject,Content,MedCod"
" FROM msg_content WHERE MsgCod=%ld",
MsgCod);
/* TODO: Messages in msg_content_deleted older than a certain time
should be deleted to ensure the protection of personal data */
/* Delete message from msg_content *****/
DB_QueryUPDATE ("can not remove the content of a message",
"DELETE FROM msg_content WHERE MsgCod=%ld",
MsgCod);
}
/*****************************************************************************/
/***** Delete the subject and content of all completely deleted messages *****/
/*****************************************************************************/
void Msg_MoveUnusedMsgsContentToDeleted (void)
{
/***** Move messages from msg_content to msg_content_deleted *****/
/* Insert message content into msg_content_deleted */
DB_QueryINSERT ("can not remove the content of some messages",
"INSERT IGNORE INTO msg_content_deleted"
" (MsgCod,Subject,Content)"
" SELECT MsgCod,Subject,Content FROM msg_content"
" WHERE MsgCod NOT IN (SELECT MsgCod FROM msg_snt)"
" AND MsgCod NOT IN (SELECT DISTINCT MsgCod FROM msg_rcv)");
/* Messages in msg_content_deleted older than a certain time
should be deleted to ensure the protection of personal data */
/* Delete message from msg_content *****/
DB_QueryUPDATE ("can not remove the content of some messages",
"DELETE FROM msg_content"
" WHERE MsgCod NOT IN (SELECT MsgCod FROM msg_snt)"
" AND MsgCod NOT IN (SELECT DISTINCT MsgCod FROM msg_rcv)");
}
/*****************************************************************************/
/******************** Check if a sent message is deleted *********************/
/*****************************************************************************/
static bool Msg_CheckIfSentMsgIsDeleted (long MsgCod)
{
/***** Get if the message code is in table of sent messages not deleted *****/
return (DB_QueryCOUNT ("can not check if a sent message is deleted",
"SELECT COUNT(*) FROM msg_snt"
" WHERE MsgCod=%ld",
MsgCod) == 0); // The message has been deleted
// by its author when it is not present
// in table of sent messages undeleted
}
/*****************************************************************************/
/***** Check if a received message has been deleted by all its recipients ****/
/*****************************************************************************/
static bool Msg_CheckIfReceivedMsgIsDeletedForAllItsRecipients (long MsgCod)
{
/***** Get if the message code is in table of received messages not deleted *****/
return (DB_QueryCOUNT ("can not check if a received message"
" is deleted by all recipients",
"SELECT COUNT(*) FROM msg_rcv"
" WHERE MsgCod=%ld",
MsgCod) == 0); // The message has been deleted
// by all its recipients when it is not present
// in table of received messages undeleted
}
/*****************************************************************************/
/******** Get number of received messages that haven't been read by me *******/
/*****************************************************************************/
static unsigned Msg_GetNumUnreadMsgs (long FilterCrsCod,const char *FilterFromToSubquery)
{
char SubQuery[Msg_MAX_BYTES_MESSAGES_QUERY + 1];
unsigned NumMsgs;
/***** Get number of unread messages from database *****/
if (FilterCrsCod >= 0) // If origin course selected
{
if (FilterFromToSubquery[0])
sprintf (SubQuery,"SELECT msg_rcv.MsgCod FROM msg_rcv,msg_snt,usr_data"
" WHERE msg_rcv.UsrCod=%ld AND msg_rcv.Open='N'"
" AND msg_rcv.MsgCod=msg_snt.MsgCod"
" AND msg_snt.CrsCod=%ld"
" AND msg_snt.UsrCod=usr_data.UsrCod%s",
Gbl.Usrs.Me.UsrDat.UsrCod,
FilterCrsCod,
FilterFromToSubquery);
else
sprintf (SubQuery,"SELECT msg_rcv.MsgCod FROM msg_rcv,msg_snt"
" WHERE msg_rcv.UsrCod=%ld AND msg_rcv.Open='N'"
" AND msg_rcv.MsgCod=msg_snt.MsgCod"
" AND msg_snt.CrsCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod,
FilterCrsCod);
}
else // If no origin course selected
{
if (FilterFromToSubquery[0])
sprintf (SubQuery,"SELECT msg_rcv.MsgCod FROM msg_rcv,msg_snt,usr_data"
" WHERE msg_rcv.UsrCod=%ld AND msg_rcv.Open='N'"
" AND msg_rcv.MsgCod=msg_snt.MsgCod"
" AND msg_snt.UsrCod=usr_data.UsrCod%s",
Gbl.Usrs.Me.UsrDat.UsrCod,
FilterFromToSubquery);
else
sprintf (SubQuery,"SELECT MsgCod FROM msg_rcv"
" WHERE UsrCod=%ld AND Open='N'",
Gbl.Usrs.Me.UsrDat.UsrCod);
}
if (Gbl.Msg.FilterContent[0])
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number of unread messages",
"SELECT COUNT(*) FROM msg_content"
" WHERE MsgCod IN (%s)"
" AND MATCH (Subject,Content) AGAINST ('%s')",
SubQuery,
Gbl.Msg.FilterContent);
else
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number of unread messages",
"SELECT COUNT(*) FROM (%s) AS T",
SubQuery);
return NumMsgs;
}
/*****************************************************************************/
/********************* Show messages sent to other users *********************/
/*****************************************************************************/
void Msg_ShowSntMsgs (void)
{
/***** Show the sent messages *****/
Gbl.Msg.TypeOfMessages = Msg_MESSAGES_SENT;
Msg_ShowSentOrReceivedMessages ();
}
/*****************************************************************************/
/******************* Show messages received from other users *****************/
/*****************************************************************************/
void Msg_ShowRecMsgs (void)
{
if (Msg_GetNumUsrsBannedByMe ())
{
/***** Contextual menu *****/
Mnu_ContextMenuBegin ();
Msg_PutLinkToViewBannedUsers (); // View banned users
Mnu_ContextMenuEnd ();
}
/***** Show the received messages *****/
Gbl.Msg.TypeOfMessages = Msg_MESSAGES_RECEIVED;
Msg_ShowSentOrReceivedMessages ();
}
/*****************************************************************************/
/************************ Show sent or received messages *********************/
/*****************************************************************************/
static void Msg_ShowSentOrReceivedMessages (void)
{
extern const char *Hlp_MESSAGES_Received;
extern const char *Hlp_MESSAGES_Received_filter;
extern const char *Hlp_MESSAGES_Sent;
extern const char *Hlp_MESSAGES_Sent_filter;
extern const char *The_ClassFormInBoxBold[The_NUM_THEMES];
extern const char *Txt_Filter;
extern const char *Txt_Update_messages;
char FilterFromToSubquery[Msg_MAX_BYTES_MESSAGES_QUERY + 1];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRow;
unsigned long NumRows;
unsigned long NumMsg = 0; // Initialized to avoid warning
unsigned NumUnreadMsgs = 0; // Initialized to avoid warning
struct Pagination Pagination;
long MsgCod;
static const Act_Action_t ActionSee[Msg_NUM_TYPES_OF_MSGS] =
{
ActSeeRcvMsg,
ActSeeSntMsg,
};
static const Pag_WhatPaginate_t WhatPaginate[Msg_NUM_TYPES_OF_MSGS] =
{
Pag_MESSAGES_RECEIVED,
Pag_MESSAGES_SENT,
};
const char *Help[Msg_NUM_TYPES_OF_MSGS] =
{
Hlp_MESSAGES_Received,
Hlp_MESSAGES_Sent,
};
const char *HelpFilter[Msg_NUM_TYPES_OF_MSGS] =
{
Hlp_MESSAGES_Received_filter,
Hlp_MESSAGES_Sent_filter,
};
/***** Get the page number *****/
Gbl.Msg.CurrentPage = Pag_GetParamPagNum (WhatPaginate[Gbl.Msg.TypeOfMessages]);
/***** Get other parameters *****/
Msg_GetParamMsgsCrsCod ();
Msg_GetParamFilterFromTo ();
Msg_GetParamFilterContent ();
Msg_MakeFilterFromToSubquery (FilterFromToSubquery);
Msg_GetDistinctCoursesInMyMessages ();
/***** Get number of unread messages *****/
switch (Gbl.Msg.TypeOfMessages)
{
case Msg_MESSAGES_RECEIVED:
Msg_GetParamOnlyUnreadMsgs ();
NumUnreadMsgs = Msg_GetNumUnreadMsgs (Gbl.Msg.FilterCrsCod,FilterFromToSubquery);
break;
case Msg_MESSAGES_SENT:
NumUnreadMsgs = 0;
break;
}
/***** Get messages from database *****/
NumRows = Msg_GetSentOrReceivedMsgs (Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Msg.FilterCrsCod,
FilterFromToSubquery,
&mysql_res);
Gbl.Msg.NumMsgs = (unsigned) NumRows;
/***** Begin box with messages *****/
Box_BoxBegin ("97%",Msg_WriteNumMsgs (NumUnreadMsgs),Msg_PutIconsListMsgs,
Help[Gbl.Msg.TypeOfMessages],Box_NOT_CLOSABLE);
/***** Filter messages *****/
/* Begin box with filter */
Box_BoxBegin (NULL,Txt_Filter,NULL,
HelpFilter[Gbl.Msg.TypeOfMessages],Box_CLOSABLE);
/* Form to see messages again */
Frm_StartForm (ActionSee[Gbl.Msg.TypeOfMessages]);
HTM_DIV_Begin ("class=\"CM\"");
Msg_ShowFormSelectCourseSentOrRecMsgs ();
if (Gbl.Msg.TypeOfMessages == Msg_MESSAGES_RECEIVED)
Msg_ShowFormToShowOnlyUnreadMessages ();
HTM_DIV_End ();
Msg_ShowFormToFilterMsgs ();
/***** Contextual menu *****/
Mnu_ContextMenuBegin ();
Frm_LinkFormSubmitAnimated (Txt_Update_messages,
The_ClassFormInBoxBold[Gbl.Prefs.Theme],
NULL);
Ico_PutCalculateIconWithText (Txt_Update_messages); // Animated icon to update messages
Frm_LinkFormEnd ();
Mnu_ContextMenuEnd ();
Frm_EndForm ();
/* End box */
Box_BoxEnd ();
if (Gbl.Msg.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 (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
row = mysql_fetch_row (mysql_res);
if (sscanf (row[0],"%ld",&MsgCod) != 1)
Lay_ShowErrorAndExit ("Wrong code of message when searching for a page.");
if (MsgCod == Gbl.Msg.ExpandedMsgCod) // Expanded message found
{
Gbl.Msg.CurrentPage = (unsigned) (NumRow / Pag_ITEMS_PER_PAGE) + 1;
break;
}
}
}
/***** Compute variables related to pagination *****/
Pagination.NumItems = Gbl.Msg.NumMsgs;
Pagination.CurrentPage = (int) Gbl.Msg.CurrentPage;
Pag_CalculatePagination (&Pagination);
Gbl.Msg.CurrentPage = (unsigned) Pagination.CurrentPage;
/***** Save my current page in order to show it next time I'll view my received/sent messages *****/
Pag_SaveLastPageMsgIntoSession (WhatPaginate[Gbl.Msg.TypeOfMessages],
Gbl.Msg.CurrentPage);
/***** Write links to pages *****/
if (Pagination.MoreThanOnePage)
Pag_WriteLinksToPagesCentered (WhatPaginate[Gbl.Msg.TypeOfMessages],
0,
&Pagination);
/***** Show received / sent messages in this page *****/
HTM_TABLE_BeginWidePadding (2);
mysql_data_seek (mysql_res,(my_ulonglong) (Pagination.FirstItemVisible - 1));
for (NumRow = Pagination.FirstItemVisible;
NumRow <= Pagination.LastItemVisible;
NumRow++)
{
row = mysql_fetch_row (mysql_res);
if (sscanf (row[0],"%ld",&MsgCod) != 1)
Lay_ShowErrorAndExit ("Wrong code of message when listing the messages in a page.");
NumMsg = NumRows - NumRow + 1;
Msg_ShowASentOrReceivedMessage (NumMsg,MsgCod);
}
HTM_TABLE_End ();
/***** Write again links to pages *****/
if (Pagination.MoreThanOnePage)
Pag_WriteLinksToPagesCentered (WhatPaginate[Gbl.Msg.TypeOfMessages],
0,
&Pagination);
}
/***** End box *****/
Box_BoxEnd ();
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/********************* Get number of user I have banned **********************/
/*****************************************************************************/
static unsigned long Msg_GetNumUsrsBannedByMe (void)
{
/***** Get number of users I have banned *****/
return DB_QueryCOUNT ("can not get number of users you have banned",
"SELECT COUNT(*) FROM msg_banned"
" WHERE ToUsrCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod);
}
/*****************************************************************************/
/****************** Put a link (form) to view banned users *******************/
/*****************************************************************************/
static void Msg_PutLinkToViewBannedUsers(void)
{
extern const char *Txt_Banned_users;
Lay_PutContextualLinkIconText (ActLstBanUsr,NULL,NULL,
"lock.svg",
Txt_Banned_users);
}
/*****************************************************************************/
/********* Generate a query to select messages received or sent **************/
/*****************************************************************************/
static unsigned long Msg_GetSentOrReceivedMsgs (long UsrCod,
long FilterCrsCod,
const char *FilterFromToSubquery,
MYSQL_RES **mysql_res)
{
char *SubQuery;
const char *StrUnreadMsg;
unsigned long NumMsgs;
if (FilterCrsCod > 0) // If origin course selected
switch (Gbl.Msg.TypeOfMessages)
{
case Msg_MESSAGES_RECEIVED:
StrUnreadMsg = (Gbl.Msg.ShowOnlyUnreadMsgs ? " AND msg_rcv.Open='N'" :
"");
if (FilterFromToSubquery[0])
{
if (asprintf (&SubQuery,"(SELECT msg_rcv.MsgCod"
" FROM msg_rcv,msg_snt,usr_data"
" WHERE msg_rcv.UsrCod=%ld%s"
" AND msg_rcv.MsgCod=msg_snt.MsgCod"
" AND msg_snt.CrsCod=%ld"
" AND msg_snt.UsrCod=usr_data.UsrCod%s)"
" UNION "
"(SELECT msg_rcv.MsgCod"
" FROM msg_rcv,msg_snt_deleted,usr_data"
" WHERE msg_rcv.UsrCod=%ld%s"
" AND msg_rcv.MsgCod=msg_snt_deleted.MsgCod"
" AND msg_snt_deleted.CrsCod=%ld"
" AND msg_snt_deleted.UsrCod=usr_data.UsrCod%s)",
UsrCod,StrUnreadMsg,FilterCrsCod,FilterFromToSubquery,
UsrCod,StrUnreadMsg,FilterCrsCod,FilterFromToSubquery) < 0)
Lay_NotEnoughMemoryExit ();
}
else
{
if (asprintf (&SubQuery,"(SELECT msg_rcv.MsgCod"
" FROM msg_rcv,msg_snt"
" WHERE msg_rcv.UsrCod=%ld%s"
" AND msg_rcv.MsgCod=msg_snt.MsgCod"
" AND msg_snt.CrsCod=%ld)"
" UNION "
"(SELECT msg_rcv.MsgCod"
" FROM msg_rcv,msg_snt_deleted"
" WHERE msg_rcv.UsrCod=%ld%s"
" AND msg_rcv.MsgCod=msg_snt_deleted.MsgCod"
" AND msg_snt_deleted.CrsCod=%ld)",
UsrCod,StrUnreadMsg,FilterCrsCod,
UsrCod,StrUnreadMsg,FilterCrsCod) < 0)
Lay_NotEnoughMemoryExit ();
}
break;
case Msg_MESSAGES_SENT:
if (FilterFromToSubquery[0])
{
if (asprintf (&SubQuery,"(SELECT DISTINCT msg_snt.MsgCod"
" FROM msg_snt,msg_rcv,usr_data"
" WHERE msg_snt.UsrCod=%ld"
" AND msg_snt.CrsCod=%ld"
" AND msg_snt.MsgCod=msg_rcv.MsgCod"
" AND msg_rcv.UsrCod=usr_data.UsrCod%s)"
" UNION "
"(SELECT DISTINCT msg_snt.MsgCod"
" FROM msg_snt,msg_rcv_deleted,usr_data"
" WHERE msg_snt.UsrCod=%ld"
" AND msg_snt.CrsCod=%ld"
" AND msg_snt.MsgCod=msg_rcv_deleted.MsgCod"
" AND msg_rcv_deleted.UsrCod=usr_data.UsrCod%s)",
UsrCod,FilterCrsCod,FilterFromToSubquery,
UsrCod,FilterCrsCod,FilterFromToSubquery) < 0)
Lay_NotEnoughMemoryExit ();
}
else
{
if (asprintf (&SubQuery,"SELECT MsgCod"
" FROM msg_snt"
" WHERE UsrCod=%ld AND CrsCod=%ld",
UsrCod,FilterCrsCod) < 0)
Lay_NotEnoughMemoryExit ();
}
break;
default: // Not aplicable here
break;
}
else // If no origin course selected
switch (Gbl.Msg.TypeOfMessages)
{
case Msg_MESSAGES_RECEIVED:
if (FilterFromToSubquery[0])
{
StrUnreadMsg = (Gbl.Msg.ShowOnlyUnreadMsgs ? " AND msg_rcv.Open='N'" :
"");
if (asprintf (&SubQuery,"(SELECT msg_rcv.MsgCod"
" FROM msg_rcv,msg_snt,usr_data"
" WHERE msg_rcv.UsrCod=%ld%s"
" AND msg_rcv.MsgCod=msg_snt.MsgCod"
" AND msg_snt.UsrCod=usr_data.UsrCod%s)"
" UNION "
"(SELECT msg_rcv.MsgCod"
" FROM msg_rcv,msg_snt_deleted,usr_data"
" WHERE msg_rcv.UsrCod=%ld%s"
" AND msg_rcv.MsgCod=msg_snt_deleted.MsgCod"
" AND msg_snt_deleted.UsrCod=usr_data.UsrCod%s)",
UsrCod,StrUnreadMsg,FilterFromToSubquery,
UsrCod,StrUnreadMsg,FilterFromToSubquery) < 0)
Lay_NotEnoughMemoryExit ();
}
else
{
StrUnreadMsg = (Gbl.Msg.ShowOnlyUnreadMsgs ? " AND Open='N'" :
"");
if (asprintf (&SubQuery,"SELECT MsgCod"
" FROM msg_rcv"
" WHERE UsrCod=%ld%s",
UsrCod,StrUnreadMsg) < 0)
Lay_NotEnoughMemoryExit ();
}
break;
case Msg_MESSAGES_SENT:
if (FilterFromToSubquery[0])
{
if (asprintf (&SubQuery,"(SELECT msg_snt.MsgCod"
" FROM msg_snt,msg_rcv,usr_data"
" WHERE msg_snt.UsrCod=%ld"
" AND msg_snt.MsgCod=msg_rcv.MsgCod"
" AND msg_rcv.UsrCod=usr_data.UsrCod%s)"
" UNION "
"(SELECT msg_snt.MsgCod"
" FROM msg_snt,msg_rcv_deleted,usr_data"
" WHERE msg_snt.UsrCod=%ld"
" AND msg_snt.MsgCod=msg_rcv_deleted.MsgCod"
" AND msg_rcv_deleted.UsrCod=usr_data.UsrCod%s)",
UsrCod,FilterFromToSubquery,
UsrCod,FilterFromToSubquery) < 0)
Lay_NotEnoughMemoryExit ();
}
else
{
if (asprintf (&SubQuery,"SELECT MsgCod"
" FROM msg_snt"
" WHERE UsrCod=%ld",
UsrCod) < 0)
Lay_NotEnoughMemoryExit ();
}
break;
default: // Not aplicable here
break;
}
if (Gbl.Msg.FilterContent[0])
/* Match against the content written in filter form */
NumMsgs = DB_QuerySELECT (mysql_res,"can not get messages",
"SELECT MsgCod"
" FROM msg_content"
" WHERE MsgCod IN (SELECT MsgCod FROM (%s) AS M)"
" AND MATCH (Subject,Content) AGAINST ('%s')"
" ORDER BY MsgCod DESC", // End the query ordering the result from most recent message to oldest
SubQuery,Gbl.Msg.FilterContent);
else
NumMsgs = DB_QuerySELECT (mysql_res,"can not get messages",
"%s"
" ORDER BY MsgCod DESC", // End the query ordering the result from most recent message to oldest
SubQuery);
/***** Free memory used for subquery *****/
free ((void *) SubQuery);
return NumMsgs;
}
/*****************************************************************************/
/**** Get the number of unique messages sent by any teacher from a course ****/
/*****************************************************************************/
unsigned Msg_GetNumMsgsSentByTchsCrs (long CrsCod)
{
/***** Get the number of unique messages sent by any teacher from this course *****/
return
(unsigned) DB_QueryCOUNT ("can not get the number of messages"
" sent by teachers",
"SELECT COUNT(*) FROM msg_snt,crs_usr"
" WHERE msg_snt.CrsCod=%ld"
" AND crs_usr.CrsCod=%ld AND crs_usr.Role=%u"
" AND msg_snt.UsrCod=crs_usr.UsrCod",
CrsCod,CrsCod,(unsigned) Rol_TCH);
}
/*****************************************************************************/
/************** Get the number of unique messages sent by a user *************/
/*****************************************************************************/
unsigned long Msg_GetNumMsgsSentByUsr (long UsrCod)
{
/***** Get the number of unique messages sent by any teacher from this course *****/
return DB_QueryCOUNT ("can not get the number of messages sent by a user",
"SELECT"
" (SELECT COUNT(*) FROM msg_snt"
" WHERE UsrCod=%ld)"
" +"
" (SELECT COUNT(*) FROM msg_snt_deleted"
" WHERE UsrCod=%ld)",
UsrCod,
UsrCod);
}
/*****************************************************************************/
/******** Get the number of unique messages sent from this location **********/
/******** (all the platform, current degree or current course) **********/
/*****************************************************************************/
unsigned Msg_GetNumMsgsSent (Hie_Level_t Scope,Msg_Status_t MsgStatus)
{
const char *Table = "msg_snt";
unsigned NumMsgs = 0; // Initialized to avoid warning
/***** Get the number of messages sent from this location
(all the platform, current degree or current course) from database *****/
switch (MsgStatus)
{
case Msg_STATUS_ALL:
case Msg_STATUS_NOTIFIED:
Table = "msg_snt";
break;
case Msg_STATUS_DELETED:
Table = "msg_snt_deleted";
break;
}
switch (Scope)
{
case Hie_SYS:
NumMsgs = (unsigned) DB_GetNumRowsTable (Table);
break;
case Hie_CTY:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number of sent messages",
"SELECT COUNT(*)"
" FROM institutions,centres,degrees,courses,%s"
" WHERE institutions.CtyCod=%ld"
" AND institutions.InsCod=centres.InsCod"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=%s.CrsCod",
Table,
Gbl.Hierarchy.Cty.CtyCod,
Table);
break;
case Hie_INS:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number of sent messages",
"SELECT COUNT(*)"
" FROM centres,degrees,courses,%s"
" WHERE centres.InsCod=%ld"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=%s.CrsCod",
Table,
Gbl.Hierarchy.Ins.InsCod,
Table);
break;
case Hie_CTR:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number of sent messages",
"SELECT COUNT(*)"
" FROM degrees,courses,%s"
" WHERE degrees.CtrCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=%s.CrsCod",
Table,
Gbl.Hierarchy.Ctr.CtrCod,
Table);
break;
case Hie_DEG:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number of sent messages",
"SELECT COUNT(*)"
" FROM courses,%s"
" WHERE courses.DegCod=%ld"
" AND courses.CrsCod=%s.CrsCod",
Table,
Gbl.Hierarchy.Deg.DegCod,
Table);
break;
case Hie_CRS:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number of sent messages",
"SELECT COUNT(*)"
" FROM %s"
" WHERE CrsCod=%ld",
Table,
Gbl.Hierarchy.Crs.CrsCod);
break;
default:
Lay_WrongScopeExit ();
break;
}
return NumMsgs;
}
/*****************************************************************************/
/****** Get the number of unique messages received from this location ********/
/****** (all the platform, current degree or current course) ********/
/*****************************************************************************/
unsigned Msg_GetNumMsgsReceived (Hie_Level_t Scope,Msg_Status_t MsgStatus)
{
char *Table;
unsigned NumMsgs = 0; // Initialized to avoid warning
/***** Get the number of unique messages sent from this location
(all the platform, current degree or current course) from database *****/
switch (MsgStatus)
{
case Msg_STATUS_ALL:
case Msg_STATUS_DELETED:
Table = (MsgStatus == Msg_STATUS_ALL) ? "msg_rcv" :
"msg_rcv_deleted";
switch (Scope)
{
case Hie_SYS:
NumMsgs = (unsigned) DB_GetNumRowsTable (Table);
break;
case Hie_CTY:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT COUNT(*)"
" FROM institutions,centres,degrees,courses,%s,msg_snt"
" WHERE institutions.CtyCod=%ld"
" AND institutions.InsCod=centres.InsCod"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=%s.MsgCod",
Table,
Gbl.Hierarchy.Cty.CtyCod,
Table);
break;
case Hie_INS:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT COUNT(*)"
" FROM centres,degrees,courses,%s,msg_snt"
" WHERE centres.InsCod=%ld"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=%s.MsgCod",
Table,
Gbl.Hierarchy.Ins.InsCod,
Table);
break;
case Hie_CTR:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT COUNT(*)"
" FROM degrees,courses,%s,msg_snt"
" WHERE degrees.CtrCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=%s.MsgCod",
Table,
Gbl.Hierarchy.Ctr.CtrCod,
Table);
break;
case Hie_DEG:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT COUNT(*)"
" FROM courses,%s,msg_snt"
" WHERE courses.DegCod=%ld"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=%s.MsgCod",
Table,
Gbl.Hierarchy.Deg.DegCod,
Table);
break;
case Hie_CRS:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT COUNT(*)"
" FROM msg_snt,%s"
" WHERE msg_snt.CrsCod=%ld"
" AND msg_snt.MsgCod=%s.MsgCod",
Table,
Gbl.Hierarchy.Crs.CrsCod,
Table);
break;
default:
Lay_WrongScopeExit ();
break;
}
break;
case Msg_STATUS_NOTIFIED:
switch (Scope)
{
case Hie_SYS:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT "
"(SELECT COUNT(*)"
" FROM msg_rcv"
" WHERE Notified='Y')"
" + "
"(SELECT COUNT(*)"
" FROM msg_rcv_deleted"
" WHERE Notified='Y')");
break;
case Hie_CTY:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT "
"(SELECT COUNT(*)"
" FROM institutions,centres,degrees,courses,msg_snt,msg_rcv"
" WHERE institutions.CtyCod=%ld"
" AND institutions.InsCod=centres.InsCod"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv.MsgCod"
" AND msg_rcv.Notified='Y')"
" + "
"(SELECT COUNT(*)"
" FROM institutions,centres,degrees,courses,msg_snt,msg_rcv_deleted"
" WHERE institutions.CtyCod=%ld"
" AND institutions.InsCod=centres.InsCod"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv_deleted.MsgCod"
" AND msg_rcv_deleted.Notified='Y')",
Gbl.Hierarchy.Cty.CtyCod,
Gbl.Hierarchy.Cty.CtyCod);
break;
case Hie_INS:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT "
"(SELECT COUNT(*)"
" FROM centres,degrees,courses,msg_snt,msg_rcv"
" WHERE centres.InsCod=%ld"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv.MsgCod"
" AND msg_rcv.Notified='Y')"
" + "
"(SELECT COUNT(*)"
" FROM centres,degrees,courses,msg_snt,msg_rcv_deleted"
" WHERE centres.InsCod=%ld"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv_deleted.MsgCod"
" AND msg_rcv_deleted.Notified='Y')",
Gbl.Hierarchy.Ins.InsCod,
Gbl.Hierarchy.Ins.InsCod);
break;
case Hie_CTR:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT "
"(SELECT COUNT(*)"
" FROM degrees,courses,msg_snt,msg_rcv"
" WHERE degrees.CtrCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv.MsgCod"
" AND msg_rcv.Notified='Y')"
" + "
"(SELECT COUNT(*)"
" FROM degrees,courses,msg_snt,msg_rcv_deleted"
" WHERE degrees.CtrCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv_deleted.MsgCod"
" AND msg_rcv_deleted.Notified='Y')",
Gbl.Hierarchy.Ctr.CtrCod,
Gbl.Hierarchy.Ctr.CtrCod);
break;
case Hie_DEG:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT "
"(SELECT COUNT(*)"
" FROM courses,msg_snt,msg_rcv"
" WHERE courses.DegCod=%ld"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv.MsgCod"
" AND msg_rcv.Notified='Y')"
" + "
"(SELECT COUNT(*)"
" FROM courses,msg_snt,msg_rcv_deleted"
" WHERE courses.DegCod=%ld"
" AND courses.CrsCod=msg_snt.CrsCod"
" AND msg_snt.MsgCod=msg_rcv_deleted.MsgCod"
" AND msg_rcv_deleted.Notified='Y')",
Gbl.Hierarchy.Deg.DegCod,
Gbl.Hierarchy.Deg.DegCod);
break;
case Hie_CRS:
NumMsgs =
(unsigned) DB_QueryCOUNT ("can not get number"
" of received messages",
"SELECT "
"(SELECT COUNT(*)"
" FROM msg_snt,msg_rcv"
" WHERE msg_snt.CrsCod=%ld"
" AND msg_snt.MsgCod=msg_rcv.MsgCod"
" AND msg_rcv.Notified='Y')"
" + "
"(SELECT COUNT(*)"
" FROM msg_snt,msg_rcv_deleted"
" WHERE msg_snt.CrsCod=%ld"
" AND msg_snt.MsgCod=msg_rcv_deleted.MsgCod"
" AND msg_rcv_deleted.Notified='Y')",
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod);
break;
default:
Lay_WrongScopeExit ();
break;
}
break;
}
return NumMsgs;
}
/*****************************************************************************/
/********* Write number of messages and number of unread messages ************/
/*****************************************************************************/
// Fill Gbl.Title
static char *Msg_WriteNumMsgs (unsigned NumUnreadMsgs)
{
extern const char *Txt_message_received;
extern const char *Txt_message_sent;
extern const char *Txt_messages_received;
extern const char *Txt_messages_sent;
extern const char *Txt_unread_MESSAGE;
extern const char *Txt_unread_MESSAGES;
switch (Gbl.Msg.TypeOfMessages)
{
case Msg_MESSAGES_RECEIVED:
if (Gbl.Msg.NumMsgs == 1)
{
if (NumUnreadMsgs)
snprintf (Gbl.Title,sizeof (Gbl.Title),
"1 %s, 1 %s",
Txt_message_received,Txt_unread_MESSAGE);
else
snprintf (Gbl.Title,sizeof (Gbl.Title),
"1 %s",
Txt_message_received);
}
else
{
if (NumUnreadMsgs == 0)
snprintf (Gbl.Title,sizeof (Gbl.Title),
"%u %s",
Gbl.Msg.NumMsgs,Txt_messages_received);
else if (NumUnreadMsgs == 1)
snprintf (Gbl.Title,sizeof (Gbl.Title),
"%u %s, 1 %s",
Gbl.Msg.NumMsgs,Txt_messages_received,
Txt_unread_MESSAGE);
else
snprintf (Gbl.Title,sizeof (Gbl.Title),
"%u %s, %u %s",
Gbl.Msg.NumMsgs,Txt_messages_received,
NumUnreadMsgs,Txt_unread_MESSAGES);
}
break;
case Msg_MESSAGES_SENT:
if (Gbl.Msg.NumMsgs == 1)
snprintf (Gbl.Title,sizeof (Gbl.Title),
"1 %s",
Txt_message_sent);
else
snprintf (Gbl.Title,sizeof (Gbl.Title),
"%u %s",
Gbl.Msg.NumMsgs,Txt_messages_sent);
break;
}
return Gbl.Title;
}
/*****************************************************************************/
/***************** Put contextual icons in list of messages ******************/
/*****************************************************************************/
static void Msg_PutIconsListMsgs (void)
{
static const Act_Action_t ActionReqDelAllMsg[Msg_NUM_TYPES_OF_MSGS] =
{
ActReqDelAllRcvMsg,
ActReqDelAllSntMsg,
};
/***** Put icon to remove messages *****/
Ico_PutContextualIconToRemove (ActionReqDelAllMsg[Gbl.Msg.TypeOfMessages],
Msg_PutHiddenParamsMsgsFilters);
/***** Put icon to show a figure *****/
Gbl.Figures.FigureType = Fig_MESSAGES;
Fig_PutIconToShowFigure ();
}
/*****************************************************************************/
/******* Put hidden parameters to expand, contract or delete a message *******/
/*****************************************************************************/
static void Msg_PutHiddenParamsOneMsg (void)
{
Pag_PutHiddenParamPagNum (Msg_WhatPaginate[Gbl.Msg.TypeOfMessages],
Gbl.Msg.CurrentPage);
Msg_PutHiddenParamMsgCod (Gbl.Msg.MsgCod);
Msg_PutHiddenParamsMsgsFilters ();
}
/*****************************************************************************/
/****************** Put hidden parameters with filters ***********************/
/*****************************************************************************/
void Msg_PutHiddenParamsMsgsFilters (void)
{
if (Gbl.Msg.FilterCrsCod >= 0)
Par_PutHiddenParamLong (NULL,"FilterCrsCod",Gbl.Msg.FilterCrsCod);
if (Gbl.Msg.FilterFromTo[0])
Par_PutHiddenParamString (NULL,"FilterFromTo",Gbl.Msg.FilterFromTo);
if (Gbl.Msg.FilterContent[0])
Par_PutHiddenParamString (NULL,"FilterContent",Gbl.Msg.FilterContent);
if (Gbl.Msg.ShowOnlyUnreadMsgs)
Par_PutHiddenParamChar ("OnlyUnreadMsgs",'Y');
}
/*****************************************************************************/
/********************* Get dictinct courses in my messages *******************/
/*****************************************************************************/
void Msg_GetDistinctCoursesInMyMessages (void)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRow;
unsigned long NumRows = 0; // Initialized to avoid warning
struct Course Crs;
/***** Get distinct courses in my messages from database *****/
switch (Gbl.Msg.TypeOfMessages)
{
case Msg_MESSAGES_RECEIVED:
NumRows = DB_QuerySELECT (&mysql_res,"can not get distinct courses"
" in your messages",""
"SELECT DISTINCT courses.CrsCod,courses.ShortName"
" FROM msg_rcv,msg_snt,courses"
" WHERE msg_rcv.UsrCod=%ld"
" AND msg_rcv.MsgCod=msg_snt.MsgCod"
" AND msg_snt.CrsCod=courses.CrsCod"
" ORDER BY courses.ShortName",
Gbl.Usrs.Me.UsrDat.UsrCod);
break;
case Msg_MESSAGES_SENT:
NumRows = DB_QuerySELECT (&mysql_res,"can not get distinct courses"
" in your messages",
"SELECT DISTINCT courses.CrsCod,courses.ShortName"
" FROM msg_snt,courses"
" WHERE msg_snt.UsrCod=%ld"
" AND msg_snt.CrsCod=courses.CrsCod"
" ORDER BY courses.ShortName",
Gbl.Usrs.Me.UsrDat.UsrCod);
break;
default: // Not aplicable here
break;
}
/***** Get distinct courses in messages from database *****/
Gbl.Msg.NumCourses = 0;
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next course */
row = mysql_fetch_row (mysql_res);
Crs.CrsCod = Str_ConvertStrCodToLongCod (row[0]);
if (Crs.CrsCod >= 0 && Gbl.Msg.NumCourses < Crs_MAX_COURSES_PER_USR)
if (Crs_GetDataOfCourseByCod (&Crs))
{
Gbl.Msg.Courses[Gbl.Msg.NumCourses].CrsCod = Crs.CrsCod;
Str_Copy (Gbl.Msg.Courses[Gbl.Msg.NumCourses].ShrtName,Crs.ShrtName,
Hie_MAX_BYTES_SHRT_NAME);
Gbl.Msg.NumCourses++;
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/********* Show form to select course for sent or received messages **********/
/*****************************************************************************/
void Msg_ShowFormSelectCourseSentOrRecMsgs (void)
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_Messages_received_from_A_COURSE;
extern const char *Txt_Messages_sent_from_A_COURSE;
extern const char *Txt_any_course;
unsigned NumOriginCrs;
const char *TxtSelector[Msg_NUM_TYPES_OF_MSGS] =
{
Txt_Messages_received_from_A_COURSE,
Txt_Messages_sent_from_A_COURSE
};
/***** Course selection *****/
HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s ",TxtSelector[Gbl.Msg.TypeOfMessages]);
fprintf (Gbl.F.Out,"