Właśnie opublikowałem jedno z dziwniejszych przeżyć programistycznych. Niby jest to stare dobre C… Jednak sami powiedzcie, jak to Wam wygląda.
Plik poniższy wprowadza do Fossila możliwość rejestracji użytkownika przez HTTP.
/*
** Copyright (c) 2010 Remigiusz Modrzejewski
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
** 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.
**
** Author contact information:
** Firstname.Lastname@gmail.com
** <http://lrem.net/>
**
*******************************************************************************
**
** This file contains code for generating the register screen.
**
*/
#include "config.h"
#include "register.h"
#if defined(_WIN32)
# include <windows.h> /* for Sleep */
# if defined(__MINGW32__) || defined(_MSC_VER)
# define sleep Sleep /* windows does not have sleep, but Sleep */
# endif
#endif
#include <time.h>
/*
** WEBPAGE: register
**
** Generate the register page.
**
*/
void register_page(void){
const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap;
style_header("Register");
zUsername = P("u");
zPasswd = P("p");
zConfirm = P("cp");
zContact = P("c");
zCap = P("cap");
zCS = P("cs"); /* Captcha Secret */
/* Try to make any sense from user input. */
if( P("new") ){
zPw = captcha_decode((unsigned int)atoi(zCS)); /* If zCS == null this will
kill the page, what is in
fact good, as the request
is forged.*/
if( !(zUsername && zPasswd && zConfirm && zContact) ){
@ <p><span class="loginError">
@ All fields are obligatory.
@ </span></p>
}else if( strcmp(zPasswd,zConfirm)!=0 ){
@ <p><span class="loginError">
@ The two copies of your new passwords do not match.
@ </span></p>
}else if( strcasecmp(zPw, zCap)!=0 ){
@ <p><span class="loginError">
@ Captcha text invalid.
@ </span></p>
}else{
/* This almost is stupid copy-paste of code from user.c:user_cmd(). Meh. */
Blob passwd, login, contact;
blob_init(&login, zUsername, -1);
blob_init(&contact, zContact, -1);
blob_init(&passwd, zPasswd, -1);
if( db_exists("SELECT 1 FROM user WHERE login=%B", &login) ){
/* Here lies the reason I don't use zErrMsg - it would not substitute
* this %s(zUsername), or at least I don't know how to force it to.*/
@ <p><span class="loginError">
@ %s(zUsername) already exists.
@ </span></p>
}else{
char *zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login));
db_multi_exec(
"INSERT INTO user(login,pw,cap,info)"
"VALUES(%B,%Q,'u',%B)", /* u - register as reader, not developer! */
&login, zPw, &contact
);
free(zPw);
/* The user is registered, now just log him in. */
int uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUsername);
char *zCookie;
const char *zCookieName = login_cookie_name();
const char *zExpire = db_get("cookie-expire","8766");
int expires = atoi(zExpire)*3600;
const char *zIpAddr = PD("REMOTE_ADDR","nil");
zCookie = db_text(0, "SELECT '%d/' || hex(randomblob(25))", uid);
cgi_set_cookie(zCookieName, zCookie, 0, expires);
db_multi_exec(
"UPDATE user SET cookie=%Q, ipaddr=%Q, "
" cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
zCookie, zIpAddr, expires, uid
);
redirect_to_g();
}
}
}
/* Prepare the captcha. */
unsigned int uSeed = captcha_seed();
char const *zDecoded = captcha_decode(uSeed);
char *zCaptcha = captcha_render(zDecoded);
/* Print out the registration form. */
@ <form action="register" method="post">
if( P("g") ){
@ <input type="hidden" name="g" value="%h(P("g"))" />
}
@ <p><input type="hidden" name="cs" value="%u(uSeed)" />
@ <table class="login_out">
@ <tr>
@ <td class="login_out_label">User ID:</td>
@ <td><input type="text" id="u" name="u" value="" size="30" /></td>
@ </tr>
@ <tr>
@ <td class="login_out_label">Password:</td>
@ <td><input type="password" id="p" name="p" value="" size="30" /></td>
@ </tr>
@ <tr>
@ <td class="login_out_label">Confirm password:</td>
@ <td><input type="password" id="cp" name="cp" value="" size="30" /></td>
@ </tr>
@ <tr>
@ <td class="login_out_label">Contact info:</td>
@ <td><input type="text" id="c" name="c" value="" size="30" /></td>
@ </tr>
@ <tr>
@ <td class="login_out_label">Captcha text (below):</td>
@ <td><input type="text" id="cap" name="cap" value="" size="30" /></td>
@ </tr>
@ <tr><td></td>
@ <td><input type="submit" name="new" value="Register" /></td></tr>
@ </table>
@ <div class="captcha"><table class="captcha"><tr><td><pre>
@ %s(zCaptcha)
@ </pre></td></tr></table>
@ </form>
;
style_footer();
free(zCaptcha);
}
// vim: set ts=2 sw=2 sts=2 et :
Komentarze
- airborn (2010-12-05 17:31:47): prawie jak bym widział swoją magisterkę…
- Remigiusz ‘lRem’ Modrzejewski (2010-12-05 17:37:15): Współczuję… Ja do swojej kodowałem w Pythonie, acz i to było małym dodatkiem do teorii.
- Bartek (2010-12-06 14:46:56): W C jest operator @ ? co on robi?
- Remigiusz ‘lRem’ Modrzejewski (2010-12-06 14:48:22): To jest magia preprocessingu. W którymś momencie procesu kompilacji jest to tłumaczone na coś printf-o-podobnego wysyłającego do klienta html.
- pecet (2010-12-06 21:51:31): Taki postprocessing tylko zaciemnia kod. C lubię za prostotę i dość dużą kontrolę nad tym co się dzieje, to jest niestety przeciwieństwem tego :/
- lRem (2010-12-07 13:32:17): No sam nie wiem. Co jest jaśniejsze. Wersja z tym dzikim preprocesingiem: @ <input type=“hidden” name=“g” value="%h(P(“g”))" /> Czy bez niego:
- SebaS86 (2010-12-07 18:44:50): Ale to chyba jakiś zewnętrzny preprocesor?
- pecet (2010-12-07 20:32:55): lrem – pomijając konieczność escapowania " " " to wydaje się całkiem czytelna wersja z printf IMHO
- Remigiusz ‘lRem’ Modrzejewski (2010-12-08 15:38:56): SebaS86: ta, to jest w ogóle dziki makesystem gdzie make wywołuje skrypt w TCL-u który tworzy następny Makefile, wszystkie źródła są przemielone przez dodatkowy preprocesor, który również jest kompilowany w międzyczasie, na koniec nawet tworzy toto paczki. Część plików .c tworzonych jest podczas budowania na podstawie informacji zaszytych w komentarzach innych plików. Jak dodasz do tego jeszcze natywną obsługę cross-compile, to wyobrazisz sobie z jakim monstrum ma się do czynienia chcąc cokolwiek dodać.