internal self-recover fix and bones name buffers
This commit is contained in:
@@ -7,6 +7,8 @@ hero polymorphed into a vampire can use #monster to shape-shift rather than
|
|||||||
just do a one-shot polymorph into bat/cloud/wolf and shifted vampire
|
just do a one-shot polymorph into bat/cloud/wolf and shifted vampire
|
||||||
hero can use #monster again to take on another form (randomly chosen
|
hero can use #monster again to take on another form (randomly chosen
|
||||||
among the shiftable shapes and true vampire form)
|
among the shiftable shapes and true vampire form)
|
||||||
|
adjust bones filename buffer sizes to accommodate suffix
|
||||||
|
fix internal self-recover to work with recent fields added to checkpoint file
|
||||||
|
|
||||||
|
|
||||||
Fixes to Pre-3.7.0 Problems that Were Exposed Via git Repository
|
Fixes to Pre-3.7.0 Problems that Were Exposed Via git Repository
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#if !defined(MICRO) && !defined(VMS) && !defined(WIN32)
|
#if !defined(MICRO) && !defined(VMS) && !defined(WIN32)
|
||||||
#define LOCKNAMESIZE (PL_NSIZ + 14) /* long enough for uid+name+.99 */
|
#define LOCKNAMESIZE (PL_NSIZ + 14) /* long enough for uid+name+.99 */
|
||||||
#define LOCKNAMEINIT "1lock"
|
#define LOCKNAMEINIT "1lock"
|
||||||
#define BONESINIT "bonesnn.xxx"
|
#define BONESINIT "bonesnn.xxx.le"
|
||||||
#define BONESSIZE sizeof(BONESINIT)
|
#define BONESSIZE sizeof(BONESINIT)
|
||||||
#else
|
#else
|
||||||
#if defined(MICRO)
|
#if defined(MICRO)
|
||||||
@@ -22,13 +22,13 @@
|
|||||||
#if defined(VMS)
|
#if defined(VMS)
|
||||||
#define LOCKNAMESIZE (PL_NSIZ + 17) /* long enough for _uid+name+.99;1 */
|
#define LOCKNAMESIZE (PL_NSIZ + 17) /* long enough for _uid+name+.99;1 */
|
||||||
#define LOCKNAMEINIT "1lock"
|
#define LOCKNAMEINIT "1lock"
|
||||||
#define BONESINIT "bonesnn.xxx;1"
|
#define BONESINIT "bonesnn.xxx_le;1"
|
||||||
#define BONESSIZE sizeof(BONESINIT)
|
#define BONESSIZE sizeof(BONESINIT)
|
||||||
#endif
|
#endif
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
#define LOCKNAMESIZE (PL_NSIZ + 25) /* long enough for username+-+name+.99 */
|
#define LOCKNAMESIZE (PL_NSIZ + 25) /* long enough for username+-+name+.99 */
|
||||||
#define LOCKNAMEINIT ""
|
#define LOCKNAMEINIT ""
|
||||||
#define BONESINIT "bonesnn.xxx"
|
#define BONESINIT "bonesnn.xxx.le"
|
||||||
#define BONESSIZE sizeof(BONESINIT)
|
#define BONESSIZE sizeof(BONESINIT)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -170,6 +170,7 @@ struct sinfo {
|
|||||||
int exiting; /* an exit handler is executing */
|
int exiting; /* an exit handler is executing */
|
||||||
int in_moveloop;
|
int in_moveloop;
|
||||||
int in_impossible;
|
int in_impossible;
|
||||||
|
int in_self_recover;
|
||||||
#ifdef PANICLOG
|
#ifdef PANICLOG
|
||||||
int in_paniclog;
|
int in_paniclog;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
190
src/files.c
190
src/files.c
@@ -757,12 +757,12 @@ d_level *lev;
|
|||||||
char *dptr;
|
char *dptr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "bonD0.nn" = bones for level nn in the main dungeon;
|
* "bonD0.nn.le" = bones for level nn in the main dungeon;
|
||||||
* "bonM0.T" = bones for Minetown;
|
* "bonM0.T.le" = bones for Minetown;
|
||||||
* "bonQBar.n" = bones for level n in the Barbarian quest;
|
* "bonQBar.n.le" = bones for level n in the Barbarian quest;
|
||||||
* "bon3D0.nn" = \
|
* "bon3D0.nn.le" = \
|
||||||
* "bon3M0.T" = > same as above, but for bones pool #3.
|
* "bon3M0.T.le" = > same as above, but for bones pool #3.
|
||||||
* "bon3QBar.n" = /
|
* "bon3QBar.n.le" = /
|
||||||
*
|
*
|
||||||
* Return value for content validation skips "bon" and the
|
* Return value for content validation skips "bon" and the
|
||||||
* pool number (if present), making it feasible for the admin
|
* pool number (if present), making it feasible for the admin
|
||||||
@@ -1032,6 +1032,17 @@ boolean regularize_it;
|
|||||||
if (idx > historical && idx <= ascii)
|
if (idx > historical && idx <= ascii)
|
||||||
sfindicator = sfoprocs[idx].ext;
|
sfindicator = sfoprocs[idx].ext;
|
||||||
#endif
|
#endif
|
||||||
|
if (g.program_state.in_self_recover) {
|
||||||
|
/* self_recover needs to be done as historical
|
||||||
|
structlevel content until that process is
|
||||||
|
re-written to use something other than
|
||||||
|
copy_bytes() to retrieve data content from
|
||||||
|
level files (which are structlevel) and
|
||||||
|
place it into the save file.
|
||||||
|
*/
|
||||||
|
idx = historical;
|
||||||
|
sfindicator = sfoprocs[idx].ext;
|
||||||
|
}
|
||||||
#ifdef VMS
|
#ifdef VMS
|
||||||
Sprintf(g.SAVEF, "[.save]%d%s", getuid(), g.plname);
|
Sprintf(g.SAVEF, "[.save]%d%s", getuid(), g.plname);
|
||||||
regoffset = 7;
|
regoffset = 7;
|
||||||
@@ -1108,7 +1119,7 @@ boolean regularize_it;
|
|||||||
(idx == lendian) ? 'l' :
|
(idx == lendian) ? 'l' :
|
||||||
(idx == ascii) ? 'a' : '\0';
|
(idx == ascii) ? 'a' : '\0';
|
||||||
}
|
}
|
||||||
sfindicator = sfoprocs[idx].ext;
|
sfindicator = (g.program_state.in_self_recover) ? "" : sfoprocs[idx].ext;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
} else
|
} else
|
||||||
@@ -1176,6 +1187,7 @@ create_savefile()
|
|||||||
int failed = 0;
|
int failed = 0;
|
||||||
const char *fq_save;
|
const char *fq_save;
|
||||||
NHFILE *nhfp = (NHFILE *) 0;
|
NHFILE *nhfp = (NHFILE *) 0;
|
||||||
|
boolean do_historical = TRUE;
|
||||||
|
|
||||||
fq_save = fqname(g.SAVEF, SAVEPREFIX, 0);
|
fq_save = fqname(g.SAVEF, SAVEPREFIX, 0);
|
||||||
nhfp = new_nhfile();
|
nhfp = new_nhfile();
|
||||||
@@ -1186,7 +1198,21 @@ create_savefile()
|
|||||||
nhfp->mode = WRITING;
|
nhfp->mode = WRITING;
|
||||||
#ifdef SYSCF
|
#ifdef SYSCF
|
||||||
if (sysopt.saveformat[0] > historical &&
|
if (sysopt.saveformat[0] > historical &&
|
||||||
sysopt.saveformat[0] <= ascii) {
|
sysopt.saveformat[0] <= ascii)
|
||||||
|
do_historical = FALSE;
|
||||||
|
#endif /* SYSCF */
|
||||||
|
if (g.program_state.in_self_recover) {
|
||||||
|
do_historical = TRUE; /* force it */
|
||||||
|
nhfp->structlevel = TRUE;
|
||||||
|
nhfp->fieldlevel = FALSE;
|
||||||
|
nhfp->addinfo = FALSE;
|
||||||
|
nhfp->style.deflt = FALSE;
|
||||||
|
nhfp->style.binary = TRUE;
|
||||||
|
nhfp->fnidx = historical;
|
||||||
|
nhfp->fd = -1;
|
||||||
|
nhfp->fpdef = (FILE *) 0;
|
||||||
|
}
|
||||||
|
if (!do_historical) {
|
||||||
nhfp->structlevel = FALSE;
|
nhfp->structlevel = FALSE;
|
||||||
nhfp->fieldlevel = TRUE;
|
nhfp->fieldlevel = TRUE;
|
||||||
nhfp->addinfo = TRUE;
|
nhfp->addinfo = TRUE;
|
||||||
@@ -1203,7 +1229,6 @@ create_savefile()
|
|||||||
failed = errno;
|
failed = errno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SYSCF */
|
|
||||||
if (nhfp->structlevel) {
|
if (nhfp->structlevel) {
|
||||||
#if defined(MICRO) || defined(WIN32)
|
#if defined(MICRO) || defined(WIN32)
|
||||||
nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
|
nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
|
||||||
@@ -1240,6 +1265,7 @@ open_savefile()
|
|||||||
int failed = 0;
|
int failed = 0;
|
||||||
const char *fq_save;
|
const char *fq_save;
|
||||||
NHFILE *nhfp = (NHFILE *) 0;
|
NHFILE *nhfp = (NHFILE *) 0;
|
||||||
|
boolean do_historical = TRUE;
|
||||||
|
|
||||||
fq_save = fqname(g.SAVEF, SAVEPREFIX, 0);
|
fq_save = fqname(g.SAVEF, SAVEPREFIX, 0);
|
||||||
nhfp = new_nhfile();
|
nhfp = new_nhfile();
|
||||||
@@ -1250,7 +1276,21 @@ open_savefile()
|
|||||||
nhfp->mode = READING;
|
nhfp->mode = READING;
|
||||||
#ifdef SYSCF
|
#ifdef SYSCF
|
||||||
if (sysopt.saveformat[0] > historical &&
|
if (sysopt.saveformat[0] > historical &&
|
||||||
sysopt.saveformat[0] <= ascii) {
|
sysopt.saveformat[0] <= ascii)
|
||||||
|
do_historical = FALSE;
|
||||||
|
#endif /* SYSCF */
|
||||||
|
if (g.program_state.in_self_recover) {
|
||||||
|
do_historical = TRUE; /* force it */
|
||||||
|
nhfp->structlevel = TRUE;
|
||||||
|
nhfp->fieldlevel = FALSE;
|
||||||
|
nhfp->addinfo = FALSE;
|
||||||
|
nhfp->style.deflt = FALSE;
|
||||||
|
nhfp->style.binary = TRUE;
|
||||||
|
nhfp->fnidx = historical;
|
||||||
|
nhfp->fd = -1;
|
||||||
|
nhfp->fpdef = (FILE *) 0;
|
||||||
|
}
|
||||||
|
if (!do_historical) {
|
||||||
nhfp->structlevel = FALSE;
|
nhfp->structlevel = FALSE;
|
||||||
nhfp->fieldlevel = TRUE;
|
nhfp->fieldlevel = TRUE;
|
||||||
nhfp->addinfo = TRUE;
|
nhfp->addinfo = TRUE;
|
||||||
@@ -1267,7 +1307,6 @@ open_savefile()
|
|||||||
failed = errno;
|
failed = errno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SYSCF */
|
|
||||||
if (nhfp->structlevel) {
|
if (nhfp->structlevel) {
|
||||||
#ifdef MAC
|
#ifdef MAC
|
||||||
nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
|
nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
|
||||||
@@ -3943,13 +3982,14 @@ boolean
|
|||||||
recover_savefile()
|
recover_savefile()
|
||||||
{
|
{
|
||||||
NHFILE *gnhfp, *lnhfp, *snhfp;
|
NHFILE *gnhfp, *lnhfp, *snhfp;
|
||||||
int lev, savelev, hpid, pltmpsiz;
|
int lev, savelev, hpid, pltmpsiz, filecmc;
|
||||||
xchar levc;
|
xchar levc;
|
||||||
struct version_info version_data;
|
struct version_info version_data;
|
||||||
int processed[256];
|
int processed[256];
|
||||||
char savename[SAVESIZE], errbuf[BUFSZ];
|
char savename[SAVESIZE], errbuf[BUFSZ], indicator;
|
||||||
struct savefile_info sfi;
|
struct savefile_info sfi;
|
||||||
char tmpplbuf[PL_NSIZ];
|
char tmpplbuf[PL_NSIZ];
|
||||||
|
const char *savewrite_failure = (const char *) 0;
|
||||||
|
|
||||||
for (lev = 0; lev < 256; lev++)
|
for (lev = 0; lev < 256; lev++)
|
||||||
processed[lev] = 0;
|
processed[lev] = 0;
|
||||||
@@ -3985,6 +4025,10 @@ recover_savefile()
|
|||||||
}
|
}
|
||||||
if ((read(gnhfp->fd, (genericptr_t) savename, sizeof savename)
|
if ((read(gnhfp->fd, (genericptr_t) savename, sizeof savename)
|
||||||
!= sizeof savename)
|
!= sizeof savename)
|
||||||
|
|| (read(gnhfp->fd, (genericptr_t) &indicator, sizeof indicator)
|
||||||
|
!= sizeof indicator)
|
||||||
|
|| (read(gnhfp->fd, (genericptr_t) &filecmc, sizeof filecmc)
|
||||||
|
!= sizeof filecmc)
|
||||||
|| (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data)
|
|| (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data)
|
||||||
!= sizeof version_data)
|
!= sizeof version_data)
|
||||||
|| (read(gnhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi)
|
|| (read(gnhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi)
|
||||||
@@ -3997,6 +4041,7 @@ recover_savefile()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* save file should contain:
|
/* save file should contain:
|
||||||
|
* format indicator and cmc
|
||||||
* version info
|
* version info
|
||||||
* savefile info
|
* savefile info
|
||||||
* player name
|
* player name
|
||||||
@@ -4004,6 +4049,22 @@ recover_savefile()
|
|||||||
* (non-level-based) game state
|
* (non-level-based) game state
|
||||||
* other levels
|
* other levels
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Things are different now. We could be in a situation
|
||||||
|
* where the default save file format is not structlevel.
|
||||||
|
* self-recover is currently written to use copy_bytes()
|
||||||
|
* to move content from the level files into the savefile.
|
||||||
|
* Until the code is updated to use something other than
|
||||||
|
* copy_bytes, what we need to do is force the recovery
|
||||||
|
* save to be structlevel, finish creating it, then read
|
||||||
|
* it back in. The save after that can be fieldlevel again.
|
||||||
|
*
|
||||||
|
* Set a flag for the savefile routines to know the
|
||||||
|
* circumstances and act accordingly:
|
||||||
|
* g.program_state.in_self_recover
|
||||||
|
*/
|
||||||
|
g.program_state.in_self_recover = TRUE;
|
||||||
set_savefile_name(TRUE);
|
set_savefile_name(TRUE);
|
||||||
snhfp = create_savefile();
|
snhfp = create_savefile();
|
||||||
if (!snhfp) {
|
if (!snhfp) {
|
||||||
@@ -4021,47 +4082,66 @@ recover_savefile()
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write(snhfp->fd, (genericptr_t) &version_data, sizeof version_data)
|
/*
|
||||||
!= sizeof version_data) {
|
* Our savefile output format might _not_ be structlevel.
|
||||||
raw_printf("\nError writing %s; recovery failed.", g.SAVEF);
|
* We have to check and use the correct output routine here.
|
||||||
close_nhfile(gnhfp);
|
*/
|
||||||
close_nhfile(snhfp);
|
/*store_formatindicator(snhfp); */
|
||||||
close_nhfile(lnhfp);
|
store_version(snhfp);
|
||||||
delete_savefile();
|
#if 0
|
||||||
return FALSE;
|
if (snhfp->structlevel) {
|
||||||
|
if (write(snhfp->fd, (genericptr_t) &version_data, sizeof version_data)
|
||||||
|
!= sizeof version_data)
|
||||||
|
savewrite_failure = "version_info";
|
||||||
}
|
}
|
||||||
|
if (snhfp->fieldlevel) {
|
||||||
if (write(snhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) {
|
sfo_version_info(snhfp, (struct version_info *) &version_data,
|
||||||
raw_printf("\nError writing %s; recovery failed (savefile_info).\n",
|
"version", "version_info", 1);
|
||||||
g.SAVEF);
|
savewrite_failure = (const char *) 0;
|
||||||
close_nhfile(gnhfp);
|
|
||||||
close_nhfile(snhfp);
|
|
||||||
close_nhfile(lnhfp);
|
|
||||||
delete_savefile();
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
if (savewrite_failure)
|
||||||
|
goto cleanup;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (write(snhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
|
if (snhfp->structlevel) {
|
||||||
!= sizeof pltmpsiz) {
|
if (write(snhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi)
|
||||||
raw_printf("Error writing %s; recovery failed (player name size).\n",
|
savewrite_failure = "savefileinfo";
|
||||||
g.SAVEF);
|
|
||||||
close_nhfile(gnhfp);
|
|
||||||
close_nhfile(snhfp);
|
|
||||||
close_nhfile(lnhfp);
|
|
||||||
delete_savefile();
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
if (snhfp->fieldlevel) {
|
||||||
if (write(snhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) {
|
sfo_savefile_info(snhfp, &sfsaveinfo, "savefileinfo", "savefile_info", 1);
|
||||||
raw_printf("Error writing %s; recovery failed (player name).\n",
|
savewrite_failure = (const char *) 0;
|
||||||
g.SAVEF);
|
|
||||||
close_nhfile(gnhfp);
|
|
||||||
close_nhfile(snhfp);
|
|
||||||
close_nhfile(lnhfp);
|
|
||||||
delete_savefile();
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
if (savewrite_failure)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (snhfp->structlevel) {
|
||||||
|
if (write(snhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
|
||||||
|
!= sizeof pltmpsiz)
|
||||||
|
savewrite_failure = "player name size";
|
||||||
|
}
|
||||||
|
if (snhfp->fieldlevel) {
|
||||||
|
sfo_int(snhfp, &pltmpsiz, "plname", "plname_size", 1);
|
||||||
|
savewrite_failure = (const char *) 0;
|
||||||
|
}
|
||||||
|
if (savewrite_failure)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (snhfp->structlevel) {
|
||||||
|
if (write(snhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)
|
||||||
|
savewrite_failure = "player name";
|
||||||
|
}
|
||||||
|
if (snhfp->fieldlevel) {
|
||||||
|
sfo_str(snhfp, tmpplbuf, "plname", "tmpplbuf", pltmpsiz);
|
||||||
|
savewrite_failure = (const char *) 0;
|
||||||
|
}
|
||||||
|
if (savewrite_failure)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy_bytes isn't good enough anymore.
|
||||||
|
* We could be reading from a structlevel file but
|
||||||
|
* writing into a fieldlevel save file. Yikes!
|
||||||
|
*/
|
||||||
if (!copy_bytes(lnhfp->fd, snhfp->fd)) {
|
if (!copy_bytes(lnhfp->fd, snhfp->fd)) {
|
||||||
close_nhfile(gnhfp);
|
close_nhfile(gnhfp);
|
||||||
close_nhfile(snhfp);
|
close_nhfile(snhfp);
|
||||||
@@ -4116,6 +4196,20 @@ recover_savefile()
|
|||||||
(void) unlink(fq_lock);
|
(void) unlink(fq_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cleanup:
|
||||||
|
if (savewrite_failure) {
|
||||||
|
raw_printf("\nError writing %s; recovery failed (%s).\n",
|
||||||
|
g.SAVEF, savewrite_failure);
|
||||||
|
close_nhfile(gnhfp);
|
||||||
|
close_nhfile(snhfp);
|
||||||
|
close_nhfile(lnhfp);
|
||||||
|
g.program_state.in_self_recover = FALSE;
|
||||||
|
delete_savefile();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* we don't clear g.program_state.in_self_recover here, we
|
||||||
|
leave it as a flag to reload the structlevel savefile
|
||||||
|
in the caller. The caller should then clear it. */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2027,6 +2027,7 @@ $(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h
|
|||||||
$(O)weapon.o: weapon.c $(HACK_H)
|
$(O)weapon.o: weapon.c $(HACK_H)
|
||||||
$(O)were.o: were.c $(HACK_H)
|
$(O)were.o: were.c $(HACK_H)
|
||||||
$(O)wield.o: wield.c $(HACK_H)
|
$(O)wield.o: wield.c $(HACK_H)
|
||||||
|
$(O)windmain.o: $(MSWSYS)\windmain.c $(HACK_H)
|
||||||
#$(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h
|
#$(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h
|
||||||
$(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h
|
$(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h
|
||||||
$(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h
|
$(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h
|
||||||
|
|||||||
@@ -503,6 +503,10 @@ attempt_restore:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (g.program_state.in_self_recover) {
|
||||||
|
g.program_state.in_self_recover = FALSE;
|
||||||
|
set_savefile_name(TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resuming) {
|
if (!resuming) {
|
||||||
|
|||||||
Reference in New Issue
Block a user