");
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
diff --git a/swad_changelog.h b/swad_changelog.h
index 6d6001aa..72805154 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -103,11 +103,12 @@
/****************************** Public constants *****************************/
/*****************************************************************************/
-#define Log_PLATFORM_VERSION "SWAD 14.113 (2015/04/12)"
+#define Log_PLATFORM_VERSION "SWAD 14.113.1 (2015/04/14)"
// Number of lines (includes comments but not blank lines) has been got with the following command:
// nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1
/*
+ Version 14.113.1: Apr 14, 2015 Fixed bug when compressing users' works, reported by José Martínez Aroza. (184484 lines)
Version 14.113: Apr 12, 2015 Refactoring code related to frames. (184462 lines)
Version 14.112.1: Apr 12, 2015 Refactoring code related to frames with ending buttons. (184583 lines)
Version 14.112: Apr 12, 2015 Optimization in frames with ending buttons.
diff --git a/swad_file_browser.c b/swad_file_browser.c
index b3924465..9944cc66 100644
--- a/swad_file_browser.c
+++ b/swad_file_browser.c
@@ -2914,24 +2914,29 @@ static void Brw_ShowFileBrowsersAsgWrkCrs (void)
struct UsrData UsrDat;
/***** Check the number of users whose works will be shown *****/
- if (Usr_CountNumUsrsInEncryptedList ()) // If some users are selected...
+ if (Usr_CountNumUsrsInEncryptedList ()) // If some users are selected...
{
if (Gbl.FileBrowser.ZIP.CreateZIP)
{
- /***** Create zip file with the assignments and works of the selected users *****/
- /* Create temporary directory for the compression of assignments and works */
+ /***** Create zip file
+ with the assignments and works
+ of the selected users *****/
+ /* Create temporary directory
+ for the compression of assignments and works */
ZIP_CreateTmpDirForCompression ();
/* Initialize structure with user's data */
Usr_UsrDataConstructor (&UsrDat);
- /* Create temporary directory for each selected user inside the directory used for compression */
+ /* Create temporary directory for each selected user
+ inside the directory used for compression */
Ptr = Gbl.Usrs.Select.All;
while (*Ptr)
{
- Par_GetNextStrUntilSeparParamMult (&Ptr,UsrDat.EncryptedUsrCod,Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
+ Par_GetNextStrUntilSeparParamMult (&Ptr,UsrDat.EncryptedUsrCod,
+ Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Usr_GetUsrCodFromEncryptedUsrCod (&UsrDat);
- if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) // Get user's data from database
+ if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) // Get user's data from database
if (Usr_CheckIfUsrBelongsToCrs (UsrDat.UsrCod,Gbl.CurrentCrs.Crs.CrsCod))
ZIP_CreateDirCompressionUsr (&UsrDat);
}
@@ -2943,7 +2948,8 @@ static void Brw_ShowFileBrowsersAsgWrkCrs (void)
ZIP_CreateZIPAsgWrk ();
}
else
- /***** Button to create a zip file with all the works of the selected users *****/
+ /***** Button to create a zip file
+ with all the works of the selected users *****/
ZIP_PutButtonToCreateZIPAsgWrk ();
/***** Write top before showing file browser *****/
@@ -2956,9 +2962,10 @@ static void Brw_ShowFileBrowsersAsgWrkCrs (void)
Ptr = Gbl.Usrs.Select.All;
while (*Ptr)
{
- Par_GetNextStrUntilSeparParamMult (&Ptr,Gbl.Usrs.Other.UsrDat.EncryptedUsrCod,Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
+ Par_GetNextStrUntilSeparParamMult (&Ptr,Gbl.Usrs.Other.UsrDat.EncryptedUsrCod,
+ Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Usr_GetUsrCodFromEncryptedUsrCod (&Gbl.Usrs.Other.UsrDat);
- if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat)) // Get of the database the data of the user
+ if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat)) // Get of the database the data of the user
if (Usr_CheckIfUsrBelongsToCrs (Gbl.Usrs.Other.UsrDat.UsrCod,Gbl.CurrentCrs.Crs.CrsCod))
{
/***** Show a row with the data of the owner of the works *****/
diff --git a/swad_mail.c b/swad_mail.c
index fc5e1a64..7c98d26f 100644
--- a/swad_mail.c
+++ b/swad_mail.c
@@ -878,9 +878,9 @@ bool Mai_CheckIfEmailIsValid (const char *Email)
bool ArrobaFound = false;
/***** An e-mail address must have a number of characters
- 5 <= Length <= Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA *****/
+ 5 <= Length <= Mai_MAX_BYTES_USR_EMAIL *****/
if (Length < 5 ||
- Length > Cns_MAX_BYTES_STRING)
+ Length > Usr_MAX_BYTES_USR_EMAIL)
return false;
/***** An e-mail address can have digits, letters, '.', '-' and '_';
@@ -1131,8 +1131,9 @@ void Mai_ShowFormChangeUsrEmail (void)
NumEmails ? Txt_New_email : // A new e-mail
Txt_Email); // The first e-mail
Act_FormStart (ActChgMai);
- fprintf (Gbl.F.Out,"",
- Cns_MAX_BYTES_STRING,
+ fprintf (Gbl.F.Out,"",
+ Usr_MAX_BYTES_USR_EMAIL,
Gbl.Usrs.Me.UsrDat.Email);
fprintf (Gbl.F.Out,""
"
");
@@ -1151,10 +1152,10 @@ void Mai_RemoveEmail (void)
{
extern const char *Txt_Email_X_removed;
extern const char *Txt_You_can_not_delete_your_current_email;
- char Email[Cns_MAX_BYTES_STRING+1];
+ char Email[Usr_MAX_BYTES_USR_EMAIL+1];
/***** Get new e-mail from form *****/
- Par_GetParToText ("Email",Email,Cns_MAX_BYTES_STRING);
+ Par_GetParToText ("Email",Email,Usr_MAX_BYTES_USR_EMAIL);
if (strcasecmp (Email,Gbl.Usrs.Me.UsrDat.Email)) // Only if not my current e-mail
{
@@ -1198,10 +1199,10 @@ void Mai_UpdateEmail (void)
extern const char *Txt_A_message_has_been_sent_to_email_address_X_to_confirm_that_address;
extern const char *Txt_The_email_address_X_had_been_registered_by_another_user;
extern const char *Txt_The_email_address_entered_X_is_not_valid;
- char NewEmail[Cns_MAX_BYTES_STRING+1];
+ char NewEmail[Usr_MAX_BYTES_USR_EMAIL+1];
/***** Get new e-mail from form *****/
- Par_GetParToText ("NewEmail",NewEmail,Cns_MAX_BYTES_STRING);
+ Par_GetParToText ("NewEmail",NewEmail,Usr_MAX_BYTES_USR_EMAIL);
if (Mai_CheckIfEmailIsValid (NewEmail)) // New e-mail is valid
{
@@ -1402,7 +1403,7 @@ void Mai_ConfirmEmail (void)
MYSQL_ROW row;
char MailKey[Mai_LENGTH_EMAIL_CONFIRM_KEY+1];
long UsrCod;
- char Email[Cns_MAX_BYTES_STRING+1];
+ char Email[Usr_MAX_BYTES_USR_EMAIL+1];
bool KeyIsCorrect = false;
bool Confirmed;
@@ -1473,7 +1474,6 @@ void Mai_ConfirmEmail (void)
Usr_WriteFormLogin ();
}
-
/*****************************************************************************/
/****************** Create temporary file for mail content *******************/
/*****************************************************************************/
diff --git a/swad_notification.c b/swad_notification.c
index 3e55913f..dbbc0c49 100644
--- a/swad_notification.c
+++ b/swad_notification.c
@@ -1340,7 +1340,7 @@ static void Ntf_SendPendingNotifByEMailToOneUsr (struct UsrData *ToUsrDat,unsign
extern const char *Txt_TAB_Messages_NO_HTML[Txt_NUM_LANGUAGES];
extern const char *Txt_Notifications_NO_HTML[Txt_NUM_LANGUAGES];
extern const char *Txt_If_you_no_longer_wish_to_receive_email_notifications_NO_HTML[Txt_NUM_LANGUAGES];
- char MailDomain[Cns_MAX_BYTES_STRING+1];
+ char MailDomain[Usr_MAX_BYTES_USR_EMAIL+1];
char Query[512];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
@@ -1360,7 +1360,7 @@ static void Ntf_SendPendingNotifByEMailToOneUsr (struct UsrData *ToUsrDat,unsign
/***** Return 0 notifications and 0 mails when error *****/
*NumNotif = *NumMails = 0;
- Str_GetMailBox (ToUsrDat->Email,MailDomain,Cns_MAX_BYTES_STRING);
+ Str_GetMailBox (ToUsrDat->Email,MailDomain,Usr_MAX_BYTES_USR_EMAIL);
if (Mai_CheckIfMailDomainIsAllowedForNotifications (MailDomain))
{
/***** Get pending notifications of this user from database ******/
diff --git a/swad_preference.c b/swad_preference.c
index 3f709fba..f94d6bff 100644
--- a/swad_preference.c
+++ b/swad_preference.c
@@ -65,7 +65,7 @@ void Pre_EditPrefs (void)
{
extern const char *Txt_Language;
extern const char *Txt_You_can_only_receive_email_notifications_if_;
- char MailDomain[Cns_MAX_BYTES_STRING+1];
+ char MailDomain[Usr_MAX_BYTES_USR_EMAIL+1];
/***** Language *****/
Lay_StartRoundFrame (NULL,Txt_Language);
@@ -101,7 +101,7 @@ void Pre_EditPrefs (void)
{
Ntf_PutFormChangeNotifSentByEMail ();
- Str_GetMailBox (Gbl.Usrs.Me.UsrDat.Email,MailDomain,Cns_MAX_BYTES_STRING);
+ Str_GetMailBox (Gbl.Usrs.Me.UsrDat.Email,MailDomain,Usr_MAX_BYTES_USR_EMAIL);
if (!Mai_CheckIfMailDomainIsAllowedForNotifications (MailDomain))
Lay_ShowAlert (Lay_WARNING,Txt_You_can_only_receive_email_notifications_if_);
}
diff --git a/swad_string.c b/swad_string.c
index 21617b8d..599e34f2 100644
--- a/swad_string.c
+++ b/swad_string.c
@@ -2468,38 +2468,30 @@ void Str_ConvertToValidFileName (char *Str)
*Ptr == '_' ||
*Ptr == '-')
continue;
- switch (*Ptr)
- {
- case ' ': *Ptr = '_'; break;
+ if (isspace ((int) *Ptr) ||
+ *Ptr == '\xA0')
+ *Ptr = '_';
+ else
+ switch (*Ptr)
+ {
+ case 'á': case 'à': case 'ä': case 'â': *Ptr = 'a'; break;
+ case 'é': case 'è': case 'ë': case 'ê': *Ptr = 'e'; break;
+ case 'í': case 'ì': case 'ï': case 'î': *Ptr = 'i'; break;
+ case 'ó': case 'ò': case 'ö': case 'ô': *Ptr = 'o'; break;
+ case 'ú': case 'ù': case 'ü': case 'û': *Ptr = 'u'; break;
+ case 'ñ': *Ptr = 'n'; break;
+ case 'ç': *Ptr = 'c'; break;
- case 'á': *Ptr = 'a'; break;
- case 'é': *Ptr = 'e'; break;
- case 'í': *Ptr = 'i'; break;
- case 'ó': *Ptr = 'o'; break;
- case 'ú': *Ptr = 'u'; break;
- case 'ñ': *Ptr = 'n'; break;
- case 'ä': *Ptr = 'a'; break;
- case 'ë': *Ptr = 'e'; break;
- case 'ï': *Ptr = 'i'; break;
- case 'ö': *Ptr = 'o'; break;
- case 'ü': *Ptr = 'u'; break;
- case 'ç': *Ptr = 'c'; break;
+ case 'Á': case 'À': case 'Ä': case 'Â': *Ptr = 'A'; break;
+ case 'É': case 'È': case 'Ë': case 'Ê': *Ptr = 'E'; break;
+ case 'Í': case 'Ì': case 'Ï': case 'Î': *Ptr = 'I'; break;
+ case 'Ó': case 'Ò': case 'Ö': case 'Ô': *Ptr = 'O'; break;
+ case 'Ú': case 'Ù': case 'Ü': case 'Û': *Ptr = 'U'; break;
+ case 'Ñ': *Ptr = 'N'; break;
+ case 'Ç': *Ptr = 'C'; break;
- case 'Á': *Ptr = 'A'; break;
- case 'É': *Ptr = 'E'; break;
- case 'Í': *Ptr = 'I'; break;
- case 'Ó': *Ptr = 'O'; break;
- case 'Ú': *Ptr = 'U'; break;
- case 'Ñ': *Ptr = 'N'; break;
- case 'Ä': *Ptr = 'A'; break;
- case 'Ë': *Ptr = 'E'; break;
- case 'Ï': *Ptr = 'I'; break;
- case 'Ö': *Ptr = 'O'; break;
- case 'Ü': *Ptr = 'U'; break;
- case 'Ç': *Ptr = 'C'; break;
-
- default: *Ptr = '-'; break;
- }
+ default: *Ptr = '-'; break;
+ }
}
}
diff --git a/swad_user.c b/swad_user.c
index 6930c01a..e4b5c235 100644
--- a/swad_user.c
+++ b/swad_user.c
@@ -2588,7 +2588,7 @@ static void Usr_WriteRowGstMainData (unsigned NumUsr,struct UsrData *UsrDat)
const char *BgColor;
char PhotoURL[PATH_MAX+1];
bool ShowPhoto;
- char MailLink[7+Cns_MAX_BYTES_STRING+1]; // mailto:mail_address
+ char MailLink[7+Usr_MAX_BYTES_USR_EMAIL+1]; // mailto:mail_address
struct Institution Ins;
/***** Start row *****/
@@ -2670,7 +2670,7 @@ void Usr_WriteRowStdMainData (unsigned NumUsr,struct UsrData *UsrDat,bool PutChe
char PhotoURL[PATH_MAX+1];
bool ShowPhoto;
bool UsrIsTheMsgSender = false;
- char MailLink[7+Cns_MAX_BYTES_STRING+1]; // mailto:mail_address
+ char MailLink[7+Usr_MAX_BYTES_USR_EMAIL+1]; // mailto:mail_address
struct Institution Ins;
bool ShowEmail = (Gbl.Usrs.Me.LoggedRole == Rol_TEACHER && UsrDat->Accepted) ||
Gbl.Usrs.Me.LoggedRole == Rol_DEG_ADM ||
@@ -2991,7 +2991,7 @@ static void Usr_WriteRowTchMainData (unsigned NumUsr,struct UsrData *UsrDat,bool
char PhotoURL[PATH_MAX+1];
bool ShowPhoto;
bool UsrIsTheMsgSender = false;
- char MailLink[7+Cns_MAX_BYTES_STRING+1]; // mailto:mail_address
+ char MailLink[7+Usr_MAX_BYTES_USR_EMAIL+1]; // mailto:mail_address
struct Institution Ins;
bool ShowEmail = UsrDat->Accepted ||
Gbl.Usrs.Me.LoggedRole == Rol_DEG_ADM ||
@@ -3164,7 +3164,7 @@ void Usr_WriteRowAdmData (unsigned NumUsr,struct UsrData *UsrDat)
const char *BgColor;
char PhotoURL[PATH_MAX+1];
bool ShowPhoto;
- char MailLink[7+Cns_MAX_BYTES_STRING+1]; // mailto:mail_address
+ char MailLink[7+Usr_MAX_BYTES_USR_EMAIL+1]; // mailto:mail_address
struct Institution Ins;
/***** Start row *****/
diff --git a/swad_user.h b/swad_user.h
index 7bec5d6d..ed594352 100644
--- a/swad_user.h
+++ b/swad_user.h
@@ -53,6 +53,7 @@
#define Usr_DEF_MONTHS_WITHOUT_ACCESS_TO_REMOVE_OLD_USRS 12
#define Usr_MAX_MONTHS_WITHOUT_ACCESS_TO_REMOVE_OLD_USRS 60
+#define Usr_MAX_BYTES_USR_EMAIL 127
#define Usr_MAX_LENGTH_USR_LOGIN 127 // @nick, e-mail or ID
#define Usr_MAX_BYTES_USR_LOGIN 127
@@ -124,7 +125,7 @@ struct UsrData
char FirstName [Usr_MAX_BYTES_NAME+1];
char FullName [(Usr_MAX_BYTES_NAME+1)*3];
Usr_Sex_t Sex;
- char Email [Cns_MAX_BYTES_STRING +1];
+ char Email [Usr_MAX_BYTES_USR_EMAIL+1];
bool EmailConfirmed;
char Photo [Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1]; // Name of public link to photo
Pri_Visibility_t PhotoVisibility; // Who can see user's photo
diff --git a/swad_web_service.c b/swad_web_service.c
index deaa1cbf..fd425c45 100644
--- a/swad_web_service.c
+++ b/swad_web_service.c
@@ -625,8 +625,8 @@ int swad__createAccount (struct soap *soap,
strncpy (Gbl.Usrs.Me.UsrDat.Nickname,userNickname,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA);
Gbl.Usrs.Me.UsrDat.Nickname[Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA] = '\0';
- strncpy (Gbl.Usrs.Me.UsrDat.Email,userEmail,Cns_MAX_BYTES_STRING);
- Gbl.Usrs.Me.UsrDat.Email[Cns_MAX_BYTES_STRING] = '\0';
+ strncpy (Gbl.Usrs.Me.UsrDat.Email,userEmail,Usr_MAX_BYTES_USR_EMAIL);
+ Gbl.Usrs.Me.UsrDat.Email[Usr_MAX_BYTES_USR_EMAIL] = '\0';
ID_ReallocateListIDs (&Gbl.Usrs.Me.UsrDat,1);
Gbl.Usrs.Me.UsrDat.IDs.List[0].Confirmed = false;
diff --git a/swad_zip.c b/swad_zip.c
index 3fb2db46..8873042b 100644
--- a/swad_zip.c
+++ b/swad_zip.c
@@ -26,6 +26,7 @@
/*****************************************************************************/
#include // For scandir, etc.
+#include // For errno
#include // For PATH_MAX
#include // For system...
#include // For strcpy...
@@ -245,9 +246,14 @@ void ZIP_CreateTmpDirForCompression (void)
void ZIP_CreateDirCompressionUsr (struct UsrData *UsrDat)
{
- char FullNameAndUsrID[(Usr_MAX_BYTES_NAME+1)*3+ID_MAX_LENGTH_USR_ID+1];
+ char FullNameAndUsrID[(Usr_MAX_BYTES_NAME+1)*3+
+ ID_MAX_LENGTH_USR_ID+1+
+ 10+1];
char PathFolderUsrInsideCrs[PATH_MAX+1];
- char LinkRelTmpUsr[PATH_MAX+1];
+ char LinkTmpUsr[PATH_MAX+1];
+ char Link[PATH_MAX+1];
+ unsigned NumTry;
+ bool Success;
/***** Create a link in the tree of compression
with a name that identifies the owner
@@ -263,20 +269,35 @@ void ZIP_CreateDirCompressionUsr (struct UsrData *UsrDat)
UsrDat->FirstName[0] ? "-" :
"");
Str_LimitLengthHTMLStr (FullNameAndUsrID,50);
- strcat (FullNameAndUsrID,UsrDat->IDs.List[0].ID); // TODO: What user's ID from the list?
- Str_ConvertToValidFileName (FullNameAndUsrID);
+ strcat (FullNameAndUsrID,UsrDat->IDs.List[0].ID); // First user's ID
sprintf (PathFolderUsrInsideCrs,"%s/usr/%02u/%ld",
Gbl.CurrentCrs.PathPriv,
(unsigned) (UsrDat->UsrCod % 100),
UsrDat->UsrCod);
- sprintf (LinkRelTmpUsr,"%s/%s/%s/%s",
+ sprintf (LinkTmpUsr,"%s/%s/%s/%s",
Cfg_PATH_SWAD_PRIVATE,
Cfg_FOLDER_ZIP,
Gbl.FileBrowser.ZIP.TmpDir,
FullNameAndUsrID);
- if (symlink (PathFolderUsrInsideCrs,LinkRelTmpUsr) != 0)
- Lay_ShowErrorAndExit ("Can not create temporary folder for compression.");
+
+ /* Try to create a link named LinkTmpUsr to PathFolderUsrInsideCrs */
+ if (symlink (PathFolderUsrInsideCrs,LinkTmpUsr) != 0)
+ {
+ for (Success = false, NumTry = 2;
+ !Success && errno == EEXIST && NumTry<=1000;
+ NumTry++)
+ {
+ // Link exists ==> a former user share the same name and ID
+ // (probably a unique user has created two or more accounts)
+ sprintf (Link,"%s-%u",LinkTmpUsr,NumTry);
+ if (symlink (PathFolderUsrInsideCrs,Link) == 0)
+ Success = true;
+ }
+
+ if (!Success)
+ Lay_ShowErrorAndExit ("Can not create temporary link for compression.");
+ }
}
/*****************************************************************************/
@@ -499,7 +520,7 @@ static unsigned long long ZIP_CloneDir (const char *Path,const char *PathClone,c
/***** Create clone of subdirectory *****/
if (mkdir (PathFileClone,(mode_t) 0xFFF))
- Lay_ShowErrorAndExit ("Can not create temporary folder for compression.");
+ Lay_ShowErrorAndExit ("Can not create temporary subfolder for compression.");
/***** Clone subtree starting at this this directory *****/
FullSize += ZIP_CloneDir (PathFile,PathFileClone,PathFileInTree);