// swad_ID.c: Users' IDs /* 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-2016 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 ***********************************/ /*****************************************************************************/ #include // For isalnum, isdigit, etc. #include // For boolean type #include // For exit, system, malloc, free, rand, etc. #include // For string functions #include "swad_account.h" #include "swad_database.h" #include "swad_global.h" #include "swad_ID.h" #include "swad_parameter.h" #include "swad_QR.h" #include "swad_user.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ #define ID_MAX_IDS_PER_USER 3 // Maximum number of IDs per user /*****************************************************************************/ /******************************* Private types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private variables *****************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static bool ID_CheckIfUsrIDIsValidUsingMinDigits (const char *UsrID,unsigned MinDigits); static bool ID_ICanSeeAnotherUsrID (struct UsrData *UsrDat); static void ID_PutButtonToReqConfirmID (struct UsrData *UsrDat,unsigned NumID); static void ID_PutButtonToConfirmID (struct UsrData *UsrDat,unsigned NumID); static void ID_RemoveUsrID (const struct UsrData *UsrDat,bool ItsMe); static bool ID_CheckIfConfirmed (long UsrCod,const char *UsrID); static void ID_RemoveUsrIDFromDB (long UsrCod,const char *UsrID); static void ID_NewUsrID (const struct UsrData *UsrDat,bool ItsMe); static void ID_InsertANewUsrIDInDB (long UsrCod,const char *NewID,bool Confirmed); /*****************************************************************************/ /********************** Get list of IDs of a user ****************************/ /*****************************************************************************/ void ID_GetListIDsFromUsrCod (struct UsrData *UsrDat) { char Query[256]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumIDs; unsigned NumID; /***** Initialize list of IDs to an empty list *****/ ID_FreeListIDs (UsrDat); if (UsrDat->UsrCod > 0) { /***** Get user's IDs from database *****/ // First the confirmed (Confirmed == 'Y') // Then the unconfirmed (Confirmed == 'N') sprintf (Query,"SELECT UsrID,Confirmed FROM usr_IDs" " WHERE UsrCod='%ld'" \ " ORDER BY Confirmed DESC,UsrID", UsrDat->UsrCod); if ((NumIDs = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get user's IDs"))) { /***** Allocate space for the list *****/ ID_ReallocateListIDs (UsrDat,NumIDs); /***** Get list of IDs *****/ for (NumID = 0; NumID < NumIDs; NumID++) { row = mysql_fetch_row (mysql_res); /* Get ID from row[0] */ strncpy (UsrDat->IDs.List[NumID].ID,row[0],ID_MAX_LENGTH_USR_ID); UsrDat->IDs.List[NumID].ID[ID_MAX_LENGTH_USR_ID] = '\0'; /* Get if ID is confirmed from row[1] */ UsrDat->IDs.List[NumID].Confirmed = (Str_ConvertToUpperLetter (row[1][0]) == 'Y'); } } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } } /*****************************************************************************/ /***************** Free memory allocated for list of IDs *********************/ /*****************************************************************************/ void ID_ReallocateListIDs (struct UsrData *UsrDat,unsigned NumIDs) { /***** Free list of IDs if used *****/ ID_FreeListIDs (UsrDat); /***** Assign number of IDs in list *****/ UsrDat->IDs.Num = NumIDs; /***** Allocate space for the list *****/ if ((UsrDat->IDs.List = (struct ListIDs *) malloc (NumIDs * sizeof (struct ListIDs))) == NULL) Lay_ShowErrorAndExit ("Not enough memory to store list of user's IDs."); } /*****************************************************************************/ /***************** Free memory allocated for list of IDs *********************/ /*****************************************************************************/ void ID_FreeListIDs (struct UsrData *UsrDat) { /***** Free list *****/ if (UsrDat->IDs.Num && UsrDat->IDs.List) free ((void *) UsrDat->IDs.List); /***** Reset list *****/ UsrDat->IDs.List = NULL; UsrDat->IDs.Num = 0; } /*****************************************************************************/ /***************** Get list of user codes from user's IDs ********************/ /*****************************************************************************/ // Returns the number of users with any of these IDs // The list of users' codes is allocated inside this function and should be freed by caller unsigned ID_GetListUsrCodsFromUsrID (struct UsrData *UsrDat, const char *EncryptedPassword, // If NULL or empty ==> do not check password struct ListUsrCods *ListUsrCods, bool OnlyConfirmedIDs) { char SubQuery[256]; char *Query; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumID; unsigned NumUsr; bool CheckPassword = false; if (UsrDat->IDs.Num) { if (EncryptedPassword) if (EncryptedPassword[0]) CheckPassword = true; /***** Allocate memory for query string *****/ if ((Query = (char *) malloc (512 + UsrDat->IDs.Num * (1 + ID_MAX_LENGTH_USR_ID + 1))) == NULL) Lay_ShowErrorAndExit ("Not enough memory to store list of user's IDs."); /***** Get user's code(s) from database *****/ strcpy (Query,CheckPassword ? "SELECT DISTINCT(usr_IDs.UsrCod) FROM usr_IDs,usr_data" " WHERE usr_IDs.UsrID IN (" : "SELECT DISTINCT(UsrCod) FROM usr_IDs" " WHERE UsrID IN ("); for (NumID = 0; NumID < UsrDat->IDs.Num; NumID++) { if (NumID) strcat (Query,","); sprintf (SubQuery,"'%s'",UsrDat->IDs.List[NumID].ID); strcat (Query,SubQuery); } strcat (Query,")"); if (CheckPassword) { if (OnlyConfirmedIDs) strcat (Query," AND usr_IDs.Confirmed='Y'"); // Get user's code if I have written the correct password // or if password in database is empty (new user) sprintf (SubQuery," AND usr_IDs.UsrCod=usr_data.UsrCod" " AND (usr_data.Password='%s' OR usr_data.Password='')", EncryptedPassword); strcat (Query,SubQuery); } else if (OnlyConfirmedIDs) strcat (Query," AND Confirmed='Y'"); ListUsrCods->NumUsrs = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get user's codes"); /***** Free memory for query string *****/ free ((void *) Query); if (ListUsrCods->NumUsrs) { /***** Allocate space for the list of users' codes *****/ Usr_AllocateListUsrCods (ListUsrCods); // The list should be freed by caller /***** Fill the list *****/ for (NumUsr = 0; NumUsr < ListUsrCods->NumUsrs; NumUsr++) { /***** Get user's code *****/ row = mysql_fetch_row (mysql_res); ListUsrCods->Lst[NumUsr] = Str_ConvertStrCodToLongCod (row[0]); } UsrDat->UsrCod = ListUsrCods->Lst[0]; // The first user found } else // ListUsrCods->NumUsrs == 0 { ListUsrCods->Lst = NULL; UsrDat->UsrCod = -1L; } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } else // List of user's IDs is empty { ListUsrCods->NumUsrs = 0; ListUsrCods->Lst = NULL; UsrDat->UsrCod = -1L; } return ListUsrCods->NumUsrs; } /*****************************************************************************/ /******* Put hidden parameter with the plain user's ID of other user *********/ /*****************************************************************************/ void ID_PutParamOtherUsrIDPlain (void) { Par_PutHiddenParamString ("OtherUsrID", (Gbl.Usrs.Other.UsrDat.IDs.Num && Gbl.Usrs.Other.UsrDat.IDs.List) ? Gbl.Usrs.Other.UsrDat.IDs.List[0].ID : ""); } /*****************************************************************************/ /********* Get parameter plain user's ID of other user from a form ***********/ /*****************************************************************************/ void ID_GetParamOtherUsrIDPlain (void) { /***** Allocate space for the list *****/ ID_ReallocateListIDs (&Gbl.Usrs.Other.UsrDat,1); /***** Get parameter *****/ Par_GetParToText ("OtherUsrID",Gbl.Usrs.Other.UsrDat.IDs.List[0].ID,ID_MAX_LENGTH_USR_ID); // Users' IDs are always stored internally in capitals and without leading zeros Str_RemoveLeadingZeros (Gbl.Usrs.Other.UsrDat.IDs.List[0].ID); Str_ConvertToUpperText (Gbl.Usrs.Other.UsrDat.IDs.List[0].ID); Gbl.Usrs.Other.UsrDat.IDs.List[0].Confirmed = true; } /*****************************************************************************/ /****** Check whether a user's ID without the ending letter is valid *********/ /*****************************************************************************/ // Returns true if the user's ID string is valid, or false if not // A valid user's ID must...: // 1. Must be ID_MIN_LENGTH_USR_ID <= characters <= ID_MAX_LENGTH_USR_ID. // 2. All characters must be digits or letters // 3. Must have a minimum number of digits // Wrapper function to avoid passing extra parameters bool ID_CheckIfUsrIDIsValid (const char *UsrID) { if (UsrID) if (UsrID[0]) return ID_CheckIfUsrIDIsValidUsingMinDigits (UsrID,ID_MIN_DIGITS_USR_ID); return false; } // Wrapper function to avoid passing extra parameters bool ID_CheckIfUsrIDSeemsAValidID (const char *UsrID) { if (UsrID) if (UsrID[0]) return ID_CheckIfUsrIDIsValidUsingMinDigits (UsrID,ID_MIN_DIGITS_AUTOMATIC_DETECT_USR_ID); return false; } static bool ID_CheckIfUsrIDIsValidUsingMinDigits (const char *UsrID,unsigned MinDigits) { const char *Ptr; unsigned NumDigits = 0; unsigned Length; /***** Check length *****/ if (!UsrID) return false; if (!UsrID[0]) return false; Length = strlen (UsrID); if (Length < ID_MIN_LENGTH_USR_ID || Length > ID_MAX_LENGTH_USR_ID) return false; // 1. Must be ID_MIN_LENGTH_USR_ID <= characters <= ID_MAX_LENGTH_USR_ID /**** Loop through user's ID *****/ for (Ptr = UsrID; *Ptr; Ptr++) if (isdigit ((int) *Ptr)) // If character is digit NumDigits++; else if (!((*Ptr >= 'A' && *Ptr <= 'Z') || (*Ptr >= 'a' && *Ptr <= 'z'))) // If character is not alpha return false; // 2. All characters must be digits or letters return (NumDigits >= MinDigits); // 3. Must have MinDigits digits at least } /*****************************************************************************/ /*************************** Write list of user's ID *************************/ /*****************************************************************************/ void ID_WriteUsrIDs (struct UsrData *UsrDat) { extern struct Act_Actions Act_Actions[Act_NUM_ACTIONS]; unsigned NumID; bool ItsMe = (UsrDat->UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod); bool ICanSeeUsrID; bool ICanConfirmUsrID; if (ItsMe) { ICanSeeUsrID = true; ICanConfirmUsrID = false; } else // A user distinct than me { ICanSeeUsrID = ID_ICanSeeAnotherUsrID (UsrDat); ICanConfirmUsrID = ICanSeeUsrID && !Gbl.Form.Inside && // Only if not inside another form Act_Actions[Gbl.Action.Act].BrowserWindow == Act_MAIN_WINDOW; // Only in main window } for (NumID = 0; NumID < UsrDat->IDs.Num; NumID++) { if (NumID) fprintf (Gbl.F.Out,"
"); fprintf (Gbl.F.Out,"", UsrDat->IDs.List[NumID].Confirmed ? "USR_ID_C" : "USR_ID_NC"); if (ICanSeeUsrID) fprintf (Gbl.F.Out,"%s",UsrDat->IDs.List[NumID].ID); else fprintf (Gbl.F.Out,"********"); fprintf (Gbl.F.Out,""); if (ICanConfirmUsrID && !UsrDat->IDs.List[NumID].Confirmed) ID_PutButtonToReqConfirmID (UsrDat,NumID); } } /*****************************************************************************/ /***************** Check if I can see another user's IDs *********************/ /*****************************************************************************/ // This function should not be called when UsrDat->UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod static bool ID_ICanSeeAnotherUsrID (struct UsrData *UsrDat) { /***** Check if I have permission to see another user's IDs *****/ switch (Gbl.Usrs.Me.LoggedRole) { case Rol_TEACHER: /* If I am a teacher of current course, I only can see the user's IDs of students from current course */ return (UsrDat->Accepted && UsrDat->RoleInCurrentCrsDB == Rol_STUDENT); case Rol_DEG_ADM: /* If I am an administrator of current degree, I only can see the user's IDs of users from current degree */ return Usr_CheckIfUsrBelongsToDeg (UsrDat->UsrCod,Gbl.CurrentDeg.Deg.DegCod,true); case Rol_CTR_ADM: /* If I am an administrator of current centre, I only can see the user's IDs of users from current centre */ return Usr_CheckIfUsrBelongsToCtr (UsrDat->UsrCod,Gbl.CurrentCtr.Ctr.CtrCod,true); case Rol_INS_ADM: /* If I am an administrator of current institution, I only can see the user's IDs of users from current institution */ return Usr_CheckIfUsrBelongsToIns (UsrDat->UsrCod,Gbl.CurrentIns.Ins.InsCod,true); case Rol_SYS_ADM: return true; default: return false; } } /*****************************************************************************/ /******* Put a button to request the confirmation of another user's ID *******/ /*****************************************************************************/ static void ID_PutButtonToReqConfirmID (struct UsrData *UsrDat,unsigned NumID) { extern const char *Txt_Confirm; Act_FormStart ( UsrDat->RoleInCurrentCrsDB == Rol_STUDENT ? ActReqCnfID_Std : (UsrDat->RoleInCurrentCrsDB == Rol_TEACHER ? ActReqCnfID_Tch : ActReqCnfID_Oth)); // Guest, visitor or admin Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod); fprintf (Gbl.F.Out,"", UsrDat->IDs.List[NumID].ID); Lay_PutCreateButtonInline (Txt_Confirm); Act_FormEnd (); } /*****************************************************************************/ /**************** Put a button to confirm another user's ID ******************/ /*****************************************************************************/ static void ID_PutButtonToConfirmID (struct UsrData *UsrDat,unsigned NumID) { extern const char *Txt_Confirm; Act_FormStart ( UsrDat->RoleInCurrentCrsDB == Rol_STUDENT ? ActCnfID_Std : (UsrDat->RoleInCurrentCrsDB == Rol_TEACHER ? ActCnfID_Tch : ActCnfID_Oth)); // Guest, visitor or admin Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod); fprintf (Gbl.F.Out,"", UsrDat->IDs.List[NumID].ID); Lay_PutCreateButton (Txt_Confirm); Act_FormEnd (); } /*****************************************************************************/ /*********** Put a link to the action used to request user's IDs *************/ /*****************************************************************************/ void ID_PutLinkToChangeUsrIDs (void) { extern const char *Txt_Change_IDs; /***** Link for changing the password *****/ if (Gbl.Usrs.Other.UsrDat.UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod) // It's me Lay_PutContextualLink (ActFrmUsrAcc,NULL, "arroba64x64.gif", Txt_Change_IDs,Txt_Change_IDs); else // Not me Lay_PutContextualLink ( Gbl.Usrs.Other.UsrDat.RoleInCurrentCrsDB == Rol_STUDENT ? ActFrmIDsStd : (Gbl.Usrs.Other.UsrDat.RoleInCurrentCrsDB == Rol_TEACHER ? ActFrmIDsTch : ActFrmIDsOth), // Guest, visitor or admin Usr_PutParamOtherUsrCodEncrypted, "arroba64x64.gif", Txt_Change_IDs,Txt_Change_IDs); } /*****************************************************************************/ /************* Show form to the change of IDs of another user ****************/ /*****************************************************************************/ void ID_ShowFormOthIDs (void) { extern const char *Txt_ID; extern const char *Txt_User_not_found_or_you_do_not_have_permission_; /***** Get user whose password must be changed *****/ if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { if (Pwd_CheckIfICanChangeOtherUsrPassword (Gbl.Usrs.Other.UsrDat.UsrCod)) { /***** Start frame *****/ Lay_StartRoundFrame (NULL,Txt_ID,NULL); /***** Show user's record *****/ Rec_ShowSharedUsrRecord (Rec_RECORD_LIST,&Gbl.Usrs.Other.UsrDat); /***** Form with the user's ID *****/ fprintf (Gbl.F.Out,""); ID_ShowFormChangeUsrID (&Gbl.Usrs.Other.UsrDat, (Gbl.Usrs.Other.UsrDat.UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod)); // It's me? fprintf (Gbl.F.Out,"
"); /***** End frame *****/ Lay_EndRoundFrame (); } else Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } else // User not found Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } /*****************************************************************************/ /*********************** Show form to change my user's ID ********************/ /*****************************************************************************/ void ID_ShowFormChangeUsrID (const struct UsrData *UsrDat,bool ItsMe) { extern const char *The_ClassForm[The_NUM_THEMES]; extern const char *Txt_ID; extern const char *Txt_ID_X_confirmed; extern const char *Txt_ID_X_not_confirmed; extern const char *Txt_Another_ID; extern const char *Txt_Add_this_ID; extern const char *Txt_If_there_are_multiple_versions_of_the_ID_; extern const char *Txt_The_ID_is_used_in_order_to_facilitate_; unsigned NumID; /***** List existing user's IDs *****/ for (NumID = 0; NumID < UsrDat->IDs.Num; NumID++) { if (NumID == 0) fprintf (Gbl.F.Out,"" "" "%s:" "" "", The_ClassForm[Gbl.Prefs.Theme],Txt_ID); else // NumID >= 1 fprintf (Gbl.F.Out,"
"); if (UsrDat->IDs.Num > 1) // I have two or more IDs { if (ItsMe && UsrDat->IDs.List[NumID].Confirmed) // I can not remove my confirmed IDs /* Put disabled icon to remove user's ID */ Lay_PutIconRemovalNotAllowed (); else // I can remove { /* Form to remove user's ID */ if (ItsMe) Act_FormStart (ActRemID_Me); else { Act_FormStart ( UsrDat->RoleInCurrentCrsDB == Rol_STUDENT ? ActRemID_Std : (UsrDat->RoleInCurrentCrsDB == Rol_TEACHER ? ActRemID_Tch : ActRemID_Oth)); // Guest, visitor or admin Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod); } fprintf (Gbl.F.Out,"", UsrDat->IDs.List[NumID].ID); Lay_PutIconRemove (); Act_FormEnd (); } } /* User's ID */ sprintf (Gbl.Title, UsrDat->IDs.List[NumID].Confirmed ? Txt_ID_X_confirmed : Txt_ID_X_not_confirmed, UsrDat->IDs.List[NumID].ID); fprintf (Gbl.F.Out,"%s", UsrDat->IDs.List[NumID].Confirmed ? "USR_ID_C" : "USR_ID_NC", Gbl.Title, UsrDat->IDs.List[NumID].ID); /* ID confirmed? */ if (UsrDat->IDs.List[NumID].Confirmed) { sprintf (Gbl.Title,Txt_ID_X_confirmed,UsrDat->IDs.List[NumID].ID); fprintf (Gbl.F.Out,"\"%s\"", Gbl.Prefs.IconsURL, Gbl.Title,Gbl.Title); } if (NumID == UsrDat->IDs.Num - 1) fprintf (Gbl.F.Out,"" ""); } /***** Form to enter new user's ID *****/ if (UsrDat->IDs.Num < ID_MAX_IDS_PER_USER) { fprintf (Gbl.F.Out,"" "" "%s:" "" "", The_ClassForm[Gbl.Prefs.Theme], UsrDat->IDs.Num ? Txt_Another_ID : // A new user's ID Txt_ID); // The first user's ID if (ItsMe) Act_FormStart (ActNewIDMe); else { Act_FormStart ( UsrDat->RoleInCurrentCrsDB == Rol_STUDENT ? ActNewID_Std : (UsrDat->RoleInCurrentCrsDB == Rol_TEACHER ? ActNewID_Tch : ActNewID_Oth)); // Guest, visitor or admin Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod); } fprintf (Gbl.F.Out,"
" "" "
", ID_MAX_LENGTH_USR_ID, UsrDat->IDs.Num ? UsrDat->IDs.List[UsrDat->IDs.Num - 1].ID : ""); // Show the most recent ID Lay_PutCreateButtonInline (Txt_Add_this_ID); Act_FormEnd (); fprintf (Gbl.F.Out,"" "" ""); } /***** Write help text *****/ fprintf (Gbl.F.Out,""); if (ItsMe) fprintf (Gbl.F.Out,"%s ", Txt_The_ID_is_used_in_order_to_facilitate_); fprintf (Gbl.F.Out,"%s" "" "", Txt_If_there_are_multiple_versions_of_the_ID_); } /*****************************************************************************/ /********************** Remove one of my user's IDs **************************/ /*****************************************************************************/ void ID_RemoveMyUsrID (void) { /***** Remove user's ID *****/ ID_RemoveUsrID (&Gbl.Usrs.Me.UsrDat,true); // It's me /***** Update list of IDs *****/ ID_GetListIDsFromUsrCod (&Gbl.Usrs.Me.UsrDat); /***** Show my account again *****/ Acc_ShowFormChangeMyAccount (); } /*****************************************************************************/ /**************** Remove one of the user's IDs of another user ***************/ /*****************************************************************************/ void ID_RemoveOtherUsrID (void) { extern const char *Txt_User_not_found_or_you_do_not_have_permission_; /***** Get other user's code from form and get user's data *****/ if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { /***** Remove user's ID *****/ ID_RemoveUsrID (&Gbl.Usrs.Other.UsrDat, (Gbl.Usrs.Other.UsrDat.UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod)); // It's me? /***** Update list of IDs *****/ ID_GetListIDsFromUsrCod (&Gbl.Usrs.Other.UsrDat); /***** Show user's record *****/ Rec_ShowSharedUsrRecord (Rec_RECORD_LIST,&Gbl.Usrs.Other.UsrDat); } else // User not found Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } /*****************************************************************************/ /***************************** Remove user's ID ******************************/ /*****************************************************************************/ static void ID_RemoveUsrID (const struct UsrData *UsrDat,bool ItsMe) { extern const char *Txt_ID_X_removed; extern const char *Txt_You_can_not_delete_this_ID; extern const char *Txt_User_not_found_or_you_do_not_have_permission_; char UsrID[ID_MAX_LENGTH_USR_ID+1]; bool ICanRemove; if (Pwd_CheckIfICanChangeOtherUsrPassword (UsrDat->UsrCod)) { /***** Get user's ID from form *****/ Par_GetParToText ("UsrID",UsrID,ID_MAX_LENGTH_USR_ID); // Users' IDs are always stored internally in capitals and without leading zeros Str_RemoveLeadingZeros (UsrID); Str_ConvertToUpperText (UsrID); if (UsrDat->IDs.Num < 2) // One unique ID ICanRemove = false; else if (ItsMe) // I can remove my ID only if it is not confirmed ICanRemove = !ID_CheckIfConfirmed (UsrDat->UsrCod,UsrID); else ICanRemove = true; if (ICanRemove) { /***** Remove one of the user's IDs *****/ ID_RemoveUsrIDFromDB (UsrDat->UsrCod,UsrID); /***** Show message *****/ sprintf (Gbl.Message,Txt_ID_X_removed,UsrID); Lay_ShowAlert (Lay_SUCCESS,Gbl.Message); } else Lay_ShowAlert (Lay_WARNING,Txt_You_can_not_delete_this_ID); } else Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } /*****************************************************************************/ /************************ Check if an ID is confirmed ************************/ /*****************************************************************************/ static bool ID_CheckIfConfirmed (long UsrCod,const char *UsrID) { char Query[128]; /***** Get if ID is confirmed from database *****/ sprintf (Query,"SELECT COUNT(*) FROM usr_IDs" " WHERE UsrCod='%ld' AND UsrID='%s' AND Confirmed='Y'", UsrCod,UsrID); return (DB_QueryCOUNT (Query,"can not check if ID is confirmed") != 0); } /*****************************************************************************/ /**************** Remove one of my user's IDs from database ******************/ /*****************************************************************************/ static void ID_RemoveUsrIDFromDB (long UsrCod,const char *UsrID) { char Query[256+ID_MAX_LENGTH_USR_ID]; /***** Remove one of my user's IDs *****/ sprintf (Query,"DELETE FROM usr_IDs" " WHERE UsrCod='%ld' AND UsrID='%s'", UsrCod,UsrID); DB_QueryREPLACE (Query,"can not remove a user's ID"); } /*****************************************************************************/ /************************* New user's ID for me ******************************/ /*****************************************************************************/ void ID_NewMyUsrID (void) { /***** Remove user's ID *****/ ID_NewUsrID (&Gbl.Usrs.Me.UsrDat,true); // It's me /***** Update list of IDs *****/ ID_GetListIDsFromUsrCod (&Gbl.Usrs.Me.UsrDat); /***** Show my account again *****/ Acc_ShowFormChangeMyAccount (); } /*****************************************************************************/ /********************* New user's ID for another user ************************/ /*****************************************************************************/ void ID_NewOtherUsrID (void) { extern const char *Txt_User_not_found_or_you_do_not_have_permission_; /***** Get other user's code from form and get user's data *****/ if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { /***** New user's ID *****/ ID_NewUsrID (&Gbl.Usrs.Other.UsrDat, (Gbl.Usrs.Other.UsrDat.UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod)); // It's me? /***** Update list of IDs *****/ ID_GetListIDsFromUsrCod (&Gbl.Usrs.Other.UsrDat); /***** Show user's record *****/ Rec_ShowSharedUsrRecord (Rec_RECORD_LIST,&Gbl.Usrs.Other.UsrDat); } else // User not found Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } /*****************************************************************************/ /***************************** New user's ID *********************************/ /*****************************************************************************/ static void ID_NewUsrID (const struct UsrData *UsrDat,bool ItsMe) { extern const char *Txt_The_ID_X_matches_one_of_the_existing; extern const char *Txt_The_ID_X_has_been_confirmed; extern const char *Txt_A_user_can_not_have_more_than_X_IDs; extern const char *Txt_The_ID_X_has_been_registered_successfully; extern const char *Txt_The_ID_X_is_not_valid; extern const char *Txt_User_not_found_or_you_do_not_have_permission_; char NewID[ID_MAX_LENGTH_USR_ID+1]; unsigned NumID; bool AlreadyExists; bool Confirmed; bool Error = false; if (Pwd_CheckIfICanChangeOtherUsrPassword (UsrDat->UsrCod)) { /***** Get new user's ID from form *****/ Par_GetParToText ("NewID",NewID,ID_MAX_LENGTH_USR_ID); // Users' IDs are always stored internally in capitals and without leading zeros Str_RemoveLeadingZeros (NewID); Str_ConvertToUpperText (NewID); if (ID_CheckIfUsrIDIsValid (NewID)) // If new ID is valid { /***** Check if the new ID matches any of the old IDs *****/ for (NumID = 0, AlreadyExists = false; NumID < UsrDat->IDs.Num && !AlreadyExists; NumID++) { AlreadyExists = !strcasecmp (UsrDat->IDs.List[NumID].ID,NewID); Confirmed = UsrDat->IDs.List[NumID].Confirmed; } if (AlreadyExists) // This new ID was already associated to this user { if (ItsMe || Confirmed) { Error = true; sprintf (Gbl.Message,Txt_The_ID_X_matches_one_of_the_existing, NewID); } else // It's not me && !Confirmed { /***** Mark this ID as confirmed *****/ ID_ConfirmUsrID (UsrDat->UsrCod,NewID); sprintf (Gbl.Message,Txt_The_ID_X_has_been_confirmed, NewID); } } else if (UsrDat->IDs.Num >= ID_MAX_IDS_PER_USER) { Error = true; sprintf (Gbl.Message,Txt_A_user_can_not_have_more_than_X_IDs, ID_MAX_IDS_PER_USER); } else // OK ==> add this new ID to my list of IDs { /***** Save this new ID *****/ // It's me ==> ID not confirmed // It's not me ==> ID confirmed ID_InsertANewUsrIDInDB (UsrDat->UsrCod,NewID,!ItsMe); sprintf (Gbl.Message,Txt_The_ID_X_has_been_registered_successfully, NewID); } } else // New ID is not valid { Error = true; sprintf (Gbl.Message,Txt_The_ID_X_is_not_valid,NewID); } /***** Show message *****/ Lay_ShowAlert (Error ? Lay_WARNING : Lay_INFO, Gbl.Message); } else Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } /*****************************************************************************/ /******************* Insert a new ID for me in database **********************/ /*****************************************************************************/ static void ID_InsertANewUsrIDInDB (long UsrCod,const char *NewID,bool Confirmed) { char Query[256+ID_MAX_LENGTH_USR_ID]; /***** Update my nickname in database *****/ sprintf (Query,"INSERT INTO usr_IDs" " (UsrCod,UsrID,CreatTime,Confirmed)" " VALUES ('%ld','%s',NOW(),'%c')", UsrCod,NewID, Confirmed ? 'Y' : 'N'); DB_QueryINSERT (Query,"can not insert a new ID"); } /*****************************************************************************/ /*************** Request the confirmation of another user's ID ***************/ /*****************************************************************************/ void ID_RequestConfirmOtherUsrID (void) { extern const char *Txt_User_not_found_or_you_do_not_have_permission_; char UsrID[ID_MAX_LENGTH_USR_ID+1]; bool ICanConfirm = false; bool Found; unsigned NumID; unsigned NumIDFound; /***** Get other user's code from form and get user's data *****/ if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) if (Gbl.Usrs.Other.UsrDat.UsrCod != Gbl.Usrs.Me.UsrDat.UsrCod) // Not me if (ID_ICanSeeAnotherUsrID (&Gbl.Usrs.Other.UsrDat)) ICanConfirm = true; if (ICanConfirm) { /***** Get user's ID from form *****/ Par_GetParToText ("UsrID",UsrID,ID_MAX_LENGTH_USR_ID); // Users' IDs are always stored internally in capitals and without leading zeros Str_RemoveLeadingZeros (UsrID); Str_ConvertToUpperText (UsrID); for (NumID = 0, Found = false; NumID < Gbl.Usrs.Other.UsrDat.IDs.Num && !Found; NumID++) if (!strcmp (UsrID,Gbl.Usrs.Other.UsrDat.IDs.List[NumID].ID)) { Found = true; NumIDFound = NumID; } if (Found) // Found { if (Gbl.Usrs.Other.UsrDat.IDs.List[NumIDFound].Confirmed) { /***** ID found and already confirmed *****/ sprintf (Gbl.Message,"El ID %s ya había sido confirmado.", // TODO: Need translation!!! Gbl.Usrs.Other.UsrDat.IDs.List[NumIDFound].ID); Lay_ShowAlert (Lay_INFO,Gbl.Message); } else { /***** Ask for confirmation *****/ sprintf (Gbl.Message,"¿Desea confirmar el ID %s?", // TODO: Need translation!!! Gbl.Usrs.Other.UsrDat.IDs.List[NumIDFound].ID); Lay_ShowAlert (Lay_INFO,Gbl.Message); /***** Put button to confirm ID *****/ ID_PutButtonToConfirmID (&Gbl.Usrs.Other.UsrDat,NumIDFound); } } else // User's ID not found Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); /***** Show user's record *****/ Rec_ShowSharedUsrRecord (Rec_RECORD_LIST,&Gbl.Usrs.Other.UsrDat); } else // User not found Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); } /*****************************************************************************/ /************************ Confirm another user's ID **************************/ /*****************************************************************************/ void ID_ConfirmOtherUsrID (void) { Lay_ShowAlert (Lay_SUCCESS,"Confirmado"); // TODO: Need translation!!!! } /*****************************************************************************/ /*********************** Set a user's ID as confirmed ************************/ /*****************************************************************************/ void ID_ConfirmUsrID (long UsrCod,const char *UsrID) { char Query[256+ID_MAX_LENGTH_USR_ID]; /***** Update my nickname in database *****/ sprintf (Query,"UPDATE usr_IDs SET Confirmed='Y'" " WHERE UsrCod='%ld' AND UsrID='%s' AND Confirmed<>'Y'", UsrCod,UsrID); DB_QueryINSERT (Query,"can not confirm a user's ID"); }