Annotation of parser3/src/targets/apache/mod_parser3.c, revision 1.1
1.1 ! moko 1: /** @file
! 2: Parser: apache 1.3 module, part, compiled by Apache.
! 3:
! 4: Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)
! 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
! 6: */
! 7:
! 8: static const char * const IDENT_MOD_PARSER3_C="$Date: 2005-08-09 08:14:53 $";
! 9:
! 10: #ifdef WIN32
! 11: #include <winsock2.h>
! 12: #endif
! 13:
! 14: #include "httpd.h"
! 15: #include "http_config.h"
! 16: #include "http_core.h"
! 17: #include "http_log.h"
! 18: #include "http_main.h"
! 19: #include "http_protocol.h"
! 20: #include "util_script.h"
! 21: #include "ap_md5.h"
! 22: #include "ap_alloc.h"
! 23:
! 24: #include "pa_httpd.h"
! 25:
! 26: /*
! 27: * Declare ourselves so the configuration routines can find and know us.
! 28: * We'll fill it in at the end of the module.
! 29: */
! 30: extern module MODULE_VAR_EXPORT parser3_module;
! 31:
! 32: /*
! 33: * Locate our directory configuration record for the current request.
! 34: */
! 35: static Parser_module_config *our_dconfig(request_rec *r) {
! 36: return (Parser_module_config *)
! 37: ap_get_module_config(r->per_dir_config, &parser3_module);
! 38: }
! 39:
! 40: static const char* cmd_parser_config(cmd_parms *cmd, void *mconfig, char *file_spec) {
! 41: Parser_module_config *cfg = (Parser_module_config *) mconfig;
! 42:
! 43: // remember assigned filespec into cfg
! 44: cfg->parser_config_filespec=file_spec;
! 45:
! 46: return NULL;
! 47: }
! 48: static const char* cmd_parser_status_allowed(cmd_parms *cmd, void *mconfig, char *file_spec) {
! 49: //_asm int 3;
! 50: Parser_module_config *cfg = (Parser_module_config *) mconfig;
! 51:
! 52: cfg->parser_status_allowed=1;
! 53:
! 54: return NULL;
! 55: }
! 56:
! 57:
! 58: /*--------------------------------------------------------------------------*/
! 59: /* */
! 60: /* Now we declare our content handlers, which are invoked when the server */
! 61: /* encounters a document which our module is supposed to have a chance to */
! 62: /* see. (See mod_mime's SetHandler and AddHandler directives, and the */
! 63: /* mod_info and mod_status examples, for more details.) */
! 64: /* */
! 65: /* Since content handlers are dumping data directly into the connexion */
! 66: /* (using the r*() routines, such as rputs() and rprintf()) without */
! 67: /* intervention by other parts of the server, they need to make */
! 68: /* sure any accumulated HTTP headers are sent first. This is done by */
! 69: /* calling send_http_header(). Otherwise, no header will be sent at all, */
! 70: /* and the output sent to the client will actually be HTTP-uncompliant. */
! 71: /*--------------------------------------------------------------------------*/
! 72: /*
! 73: * Sample content handler. All this does is display the call list that has
! 74: * been built up so far.
! 75: *
! 76: * The return value instructs the caller concerning what happened and what to
! 77: * do next:
! 78: * OK ("we did our thing")
! 79: * DECLINED ("this isn't something with which we want to get involved")
! 80: * HTTP_mumble ("an error status should be reported")
! 81: */
! 82:
! 83:
! 84: /*--------------------------------------------------------------------------*/
! 85: /* */
! 86: /* Now let's declare routines for each of the callback phase in order. */
! 87: /* (That's the order in which they're listed in the callback list, *not */
! 88: /* the order in which the server calls them! See the command_rec */
! 89: /* declaration near the bottom of this file.) Note that these may be */
! 90: /* called for situations that don't relate primarily to our function - in */
! 91: /* other words, the fixup handler shouldn't assume that the request has */
! 92: /* to do with "example" stuff. */
! 93: /* */
! 94: /* With the exception of the content handler, all of our routines will be */
! 95: /* called for each request, unless an earlier handler from another module */
! 96: /* aborted the sequence. */
! 97: /* */
! 98: /* Handlers that are declared as "int" can return the following: */
! 99: /* */
! 100: /* OK Handler accepted the request and did its thing with it. */
! 101: /* DECLINED Handler took no action. */
! 102: /* HTTP_mumble Handler looked at request and found it wanting. */
! 103: /* */
! 104: /* What the server does after calling a module handler depends upon the */
! 105: /* handler's return value. In all cases, if the handler returns */
! 106: /* DECLINED, the server will continue to the next module with an handler */
! 107: /* for the current phase. However, if the handler return a non-OK, */
! 108: /* non-DECLINED status, the server aborts the request right there. If */
! 109: /* the handler returns OK, the server's next action is phase-specific; */
! 110: /* see the individual handler comments below for details. */
! 111: /* */
! 112: /*--------------------------------------------------------------------------*/
! 113:
! 114: static int parser_handler(request_rec *ar) {
! 115: // record clone
! 116: pa_request_rec lr={
! 117: ar,
! 118: ar->pool,
! 119: ar->header_only,
! 120: &ar->status,
! 121: ar->method,
! 122: ar->headers_out,
! 123: ar->subprocess_env,
! 124: &ar->content_type,
! 125: ar->uri,
! 126: ar->filename,
! 127: ar->path_info,
! 128: ar->args,
! 129: &ar->finfo
! 130: };
! 131:
! 132: // config
! 133: Parser_module_config *dcfg=our_dconfig(ar);
! 134:
! 135: return pa_parser_handler(&lr, dcfg);
! 136: }
! 137:
! 138: /*
! 139: * This function is called during server initialisation. Any information
! 140: * that needs to be recorded must be in static cells, since there's no
! 141: * configuration record.
! 142: *
! 143: * There is no return value.
! 144: */
! 145:
! 146: static void parser_module_init(server_rec *s, pool *p) {
! 147: #if MODULE_MAGIC_NUMBER >= 19980527
! 148: ap_add_version_component(pa_version());
! 149: #endif
! 150:
! 151: /*
! 152: * Set up any module cells that ought to be initialised.
! 153: */
! 154: pa_setup_module_cells();
! 155: }
! 156:
! 157: /*
! 158: * This function is called when an heavy-weight process (such as a child) is
! 159: * being run down or destroyed. As with the child-initialisation function,
! 160: * any information that needs to be recorded must be in static cells, since
! 161: * there's no configuration record.
! 162: *
! 163: * There is no return value.
! 164: */
! 165:
! 166: /*
! 167: * All our process-death routine does is add its trace to the log.
! 168: */
! 169: static void parser_module_done(server_rec *s, pool *p) {
! 170: pa_destroy_module_cells();
! 171: }
! 172:
! 173: /*
! 174: * This function gets called to create a per-directory configuration
! 175: * record. This will be called for the "default" server environment, and for
! 176: * each directory for which the parser finds any of our directives applicable.
! 177: * If a directory doesn't have any of our directives involved (i.e., they
! 178: * aren't in the .htaccess file, or a <Location>, <Directory>, or related
! 179: * block), this routine will *not* be called - the configuration for the
! 180: * closest ancestor is used.
! 181: *
! 182: * The return value is a pointer to the created module-specific
! 183: * structure.
! 184: */
! 185: static void *parser_create_dir_config(pool *p, char *dirspec) {
! 186: //_asm int 3;
! 187: /*
! 188: * Allocate the space for our record from the pool supplied.
! 189: */
! 190: Parser_module_config *cfg=
! 191: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
! 192: /*
! 193: * Now fill in the defaults. If there are any `parent' configuration
! 194: * records, they'll get merged as part of a separate callback.
! 195: */
! 196:
! 197: return (void *) cfg;
! 198: }
! 199:
! 200: /*
! 201: * This function gets called to merge two per-directory configuration
! 202: * records. This is typically done to cope with things like .htaccess files
! 203: * or <Location> directives for directories that are beneath one for which a
! 204: * configuration record was already created. The routine has the
! 205: * responsibility of creating a new record and merging the contents of the
! 206: * other two into it appropriately. If the module doesn't declare a merge
! 207: * routine, the record for the closest ancestor location (that has one) is
! 208: * used exclusively.
! 209: *
! 210: * The routine MUST NOT modify any of its arguments!
! 211: *
! 212: * The return value is a pointer to the created module-specific structure
! 213: * containing the merged values.
! 214:
! 215: 20011126 paf: noticed, that this is called even on virtual root merge with something "parent",
! 216: while thought that that is part of merge_server...
! 217:
! 218: */
! 219: static void *parser_merge_dir_config(pool *p, void *parent_conf,
! 220: void *newloc_conf) {
! 221: //_asm int 3;
! 222: Parser_module_config *merged_config =
! 223: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
! 224: Parser_module_config *pconf = (Parser_module_config *) parent_conf;
! 225: Parser_module_config *nconf = (Parser_module_config *) newloc_conf;
! 226:
! 227: merged_config->parser_config_filespec = ap_pstrdup(p, nconf->parser_config_filespec?
! 228: nconf->parser_config_filespec:pconf->parser_config_filespec);
! 229: merged_config->parser_status_allowed=
! 230: pconf->parser_status_allowed ||
! 231: nconf->parser_status_allowed;
! 232:
! 233: /*
! 234: * Some things get copied directly from the more-specific record, rather
! 235: * than getting merged.
! 236: */
! 237:
! 238: return (void *) merged_config;
! 239: }
! 240:
! 241: /*
! 242: * This function gets called to create a per-server configuration
! 243: * record. It will always be called for the "default" server.
! 244: *
! 245: * The return value is a pointer to the created module-specific
! 246: * structure.
! 247: */
! 248: static void *parser_create_server_config(pool *p, server_rec *s) {
! 249: //_asm int 3;
! 250: /*
! 251: * As with the parser_create_dir_config() routine, we allocate and fill
! 252: * in an empty record.
! 253: */
! 254: Parser_module_config *cfg=
! 255: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
! 256:
! 257: return (void *) cfg;
! 258: }
! 259:
! 260: /*
! 261: * This function gets called to merge two per-server configuration
! 262: * records. This is typically done to cope with things like virtual hosts and
! 263: * the default server configuration The routine has the responsibility of
! 264: * creating a new record and merging the contents of the other two into it
! 265: * appropriately. If the module doesn't declare a merge routine, the more
! 266: * specific existing record is used exclusively.
! 267: *
! 268: * The routine MUST NOT modify any of its arguments!
! 269: *
! 270: * The return value is a pointer to the created module-specific structure
! 271: * containing the merged values.
! 272: */
! 273: static void *parser_merge_server_config(pool *p, void *server1_conf,
! 274: void *server2_conf)
! 275: {
! 276: //_asm int 3;
! 277:
! 278: Parser_module_config *merged_config =
! 279: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
! 280: Parser_module_config *s1conf = (Parser_module_config *) server1_conf;
! 281: Parser_module_config *s2conf = (Parser_module_config *) server2_conf;
! 282:
! 283: /*
! 284: * Our inheritance rules are our own, and part of our module's semantics.
! 285: * Basically, just note whence we came.
! 286: */
! 287: merged_config->parser_config_filespec = ap_pstrdup(p, s2conf->parser_config_filespec?
! 288: s2conf->parser_config_filespec:s1conf->parser_config_filespec);
! 289: merged_config->parser_status_allowed=
! 290: s1conf->parser_status_allowed ||
! 291: s2conf->parser_status_allowed;
! 292:
! 293: return (void *) merged_config;
! 294: }
! 295:
! 296: /*
! 297: * This routine gives our module an opportunity to translate the URI into an
! 298: * actual filename. If we don't do anything special, the server's default
! 299: * rules (Alias directives and the like) will continue to be followed.
! 300: *
! 301: * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
! 302: * further modules are called for this phase.
! 303: */
! 304: static int parser_translate_handler(request_rec *r) {
! 305: Parser_module_config *cfg=our_dconfig(r);
! 306: return DECLINED;
! 307: }
! 308:
! 309: /*
! 310: * This routine is called to check the authentication information sent with
! 311: * the request (such as looking up the user in a database and verifying that
! 312: * the [encrypted] password sent matches the one in the database).
! 313: *
! 314: * The return value is OK, DECLINED, or some HTTP_mumble error (typically
! 315: * HTTP_UNAUTHORIZED). If we return OK, no other modules are given a chance
! 316: * at the request during this phase.
! 317: */
! 318: static int parser_check_user_id(request_rec *r) {
! 319: Parser_module_config *cfg=our_dconfig(r);
! 320: return DECLINED;
! 321: }
! 322:
! 323: /*
! 324: * This routine is called to check to see if the resource being requested
! 325: * requires authorisation.
! 326: *
! 327: * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
! 328: * other modules are called during this phase.
! 329: *
! 330: * If *all* modules return DECLINED, the request is aborted with a server
! 331: * error.
! 332: */
! 333: static int parser_auth_checker(request_rec *r) {
! 334: Parser_module_config *cfg=our_dconfig(r);
! 335: return DECLINED;
! 336: }
! 337:
! 338: /*
! 339: * This routine is called to check for any module-specific restrictions placed
! 340: * upon the requested resource. (See the mod_access module for an example.)
! 341: *
! 342: * The return value is OK, DECLINED, or HTTP_mumble. All modules with an
! 343: * handler for this phase are called regardless of whether their predecessors
! 344: * return OK or DECLINED. The first one to return any other status, however,
! 345: * will abort the sequence (and the request) as usual.
! 346: */
! 347: static int parser_access_checker(request_rec *r) {
! 348:
! 349: Parser_module_config *cfg=our_dconfig(r);
! 350: return DECLINED;
! 351: }
! 352:
! 353: /*--------------------------------------------------------------------------*/
! 354: /* */
! 355: /* All of the routines have been declared now. Here's the list of */
! 356: /* directives specific to our module, and information about where they */
! 357: /* may appear and how the command parser should pass them to us for */
! 358: /* processing. Note that care must be taken to ensure that there are NO */
! 359: /* collisions of directive names between modules. */
! 360: /* */
! 361: /*--------------------------------------------------------------------------*/
! 362: /*
! 363: * List of directives specific to our module.
! 364: */
! 365: static const command_rec parser_cmds[] =
! 366: {
! 367: {
! 368: "ParserConfig", /* directive name */
! 369: (const char* (*)(void))((void *)cmd_parser_config), // config action routine
! 370: (void*)0, /* argument to include in call */
! 371: (int)(OR_OPTIONS), /* where available */
! 372: TAKE1, /* arguments */
! 373: "Parser config filespec" // directive description
! 374: },
! 375: {
! 376: "ParserStatusAllowed", /* directive name */
! 377: (const char* (*)(void))((void *)cmd_parser_status_allowed), // config action routine
! 378: (void*)0, /* argument to include in call */
! 379: (int)(ACCESS_CONF), /* where available */
! 380: NO_ARGS, /* arguments */
! 381: "Parser status class can be used" // directive description
! 382: },
! 383: {NULL}
! 384: };
! 385:
! 386: /*--------------------------------------------------------------------------*/
! 387: /* */
! 388: /* Now the list of content handlers available from this module. */
! 389: /* */
! 390: /*--------------------------------------------------------------------------*/
! 391: /*
! 392: * List of content handlers our module supplies. Each handler is defined by
! 393: * two parts: a name by which it can be referenced (such as by
! 394: * {Add,Set}Handler), and the actual routine name. The list is terminated by
! 395: * a NULL block, since it can be of variable length.
! 396: *
! 397: * Note that content-handlers are invoked on a most-specific to least-specific
! 398: * basis; that is, a handler that is declared for "text/plain" will be
! 399: * invoked before one that was declared for "text / *". Note also that
! 400: * if a content-handler returns anything except DECLINED, no other
! 401: * content-handlers will be called.
! 402: */
! 403: static const handler_rec parser_handlers[] =
! 404: {
! 405: {"parser3-handler", parser_handler},
! 406: {NULL}
! 407: };
! 408:
! 409: /*--------------------------------------------------------------------------*/
! 410: /* */
! 411: /* Finally, the list of callback routines and data structures that */
! 412: /* provide the hooks into our module from the other parts of the server. */
! 413: /* */
! 414: /*--------------------------------------------------------------------------*/
! 415: /*
! 416: * Module definition for configuration. If a particular callback is not
! 417: * needed, replace its routine name below with the word NULL.
! 418: *
! 419: * The number in brackets indicates the order in which the routine is called
! 420: * during request processing. Note that not all routines are necessarily
! 421: * called (such as if a resource doesn't have access restrictions).
! 422: */
! 423: module MODULE_VAR_EXPORT parser3_module =
! 424: {
! 425: STANDARD_MODULE_STUFF,
! 426: parser_module_init, /* module initializer */
! 427: parser_create_dir_config, /* per-directory config creator */
! 428: parser_merge_dir_config, /* dir config merger */
! 429: parser_create_server_config, /* server config creator */
! 430: parser_merge_server_config, /* server config merger */
! 431: parser_cmds, /* command table */
! 432: parser_handlers, /* [9] list of handlers */
! 433: parser_translate_handler, /* [2] filename-to-URI translation */
! 434: parser_check_user_id, /* [5] check/validate user_id */
! 435: parser_auth_checker, /* [6] check user_id is valid *here* */
! 436: parser_access_checker, /* [4] check access by host address */
! 437: 0, /* [7] MIME type checker/setter */
! 438: 0, /* [8] fixups */
! 439: 0 /* [10] logger */
! 440: #if MODULE_MAGIC_NUMBER >= 19970103
! 441: ,0 /* [3] header parser */
! 442: #endif
! 443: #if MODULE_MAGIC_NUMBER >= 19970719
! 444: ,0 /* process initializer */
! 445: #endif
! 446: #if MODULE_MAGIC_NUMBER >= 19970728
! 447: ,parser_module_done /* process exit/cleanup */
! 448: #endif
! 449: #if MODULE_MAGIC_NUMBER >= 19970902
! 450: ,0 /* [1] post read_request handling */
! 451: #endif
! 452: };
! 453:
! 454: #if defined(_MSC_VER)
! 455: # define APACHE_WIN32_SRC "../../../../win32/apache13/src"
! 456: # ifdef _DEBUG
! 457: # pragma comment(lib, APACHE_WIN32_SRC "/CoreD/ApacheCore.lib")
! 458: # else
! 459: # pragma comment(lib, APACHE_WIN32_SRC "/CoreR/ApacheCore.lib")
! 460: # endif
! 461: #endif
! 462:
! 463:
! 464: // interface to C++
! 465:
! 466: #define PA_APLOG_EMERG 0 /* system is unusable */
! 467: #define PA_APLOG_ALERT 1 /* action must be taken immediately */
! 468: #define PA_APLOG_CRIT 2 /* critical conditions */
! 469: #define PA_APLOG_ERR 3 /* error conditions */
! 470: #define PA_APLOG_WARNING 4 /* warning conditions */
! 471: #define PA_APLOG_NOTICE 5 /* normal but significant condition */
! 472: #define PA_APLOG_INFO 6 /* informational */
! 473: #define PA_APLOG_DEBUG 7 /* debug-level messages */
! 474:
! 475: #define PA_APLOG_LEVELMASK 7 /* mask off the level value */
! 476:
! 477: #define PA_APLOG_NOERRNO (PA_APLOG_LEVELMASK + 1)
! 478:
! 479: #define PA_APLOG_MARK __FILE__,__LINE__
! 480:
! 481: void pa_ap_log_rerror(const char *file, int line, int level,
! 482: const pa_request_rec *s, const char *fmt, ...) {
! 483: const char* str;
! 484: va_list l;
! 485: va_start(l, fmt);
! 486: str=va_arg(l, const char*);
! 487: va_end(l);
! 488:
! 489: ap_log_rerror(file, line, level,
! 490: (request_rec*)s->real_request_rec, "%s", str);
! 491: }
! 492:
! 493:
! 494: void pa_ap_log_error(const char *file, int line, int level,
! 495: const pa_server_rec *s, const char *fmt, ...) {
! 496: const char* str;
! 497: va_list l;
! 498: va_start(l, fmt);
! 499: str=va_arg(l, const char*);
! 500: va_end(l);
! 501:
! 502: ap_log_error(file, line, level,
! 503: (server_rec*)s, "%s", str);
! 504: }
! 505:
! 506: // ap_alloc.h
! 507:
! 508: const char* pa_ap_table_get(const pa_table *t, const char *name) {
! 509: return ap_table_get((const table*)t, name);
! 510: }
! 511: void pa_ap_table_addn(pa_table *t, const char *name, const char *val) {
! 512: ap_table_addn((table*)t, name, val);
! 513: }
! 514:
! 515: int pa_ap_table_size(const pa_table *t) {
! 516: return ap_table_elts((const table*)t)->nelts;
! 517: }
! 518:
! 519: void pa_ap_table_do(int (*comp) (void *, const char *, const char *),
! 520: void *rec, const pa_table *t, ...) {
! 521: ap_table_do(comp, rec, (table*)t, 0);
! 522: }
! 523:
! 524: char * pa_ap_pstrdup(pa_pool *p, const char *s) {
! 525: return ap_pstrdup((pool*)p, s);
! 526: }
! 527:
! 528: // http_protocol.h
! 529:
! 530: int pa_ap_setup_client_block(pa_request_rec *r, int read_policy) {
! 531: return ap_setup_client_block((request_rec*)r->real_request_rec,
! 532: read_policy);
! 533: }
! 534: int pa_ap_should_client_block(pa_request_rec *r) {
! 535: return ap_should_client_block((request_rec*)r->real_request_rec);
! 536: }
! 537: long pa_ap_get_client_block(pa_request_rec *r, char *buffer, int bufsiz) {
! 538: return ap_get_client_block((request_rec*)r->real_request_rec,
! 539: buffer, bufsiz);
! 540: }
! 541: void pa_ap_send_http_header(pa_request_rec *r) {
! 542: ap_send_http_header((request_rec*)r->real_request_rec);
! 543: }
! 544: int pa_ap_rwrite(const void *buf, int nbyte, pa_request_rec *r) {
! 545: return ap_rwrite(buf, nbyte, (request_rec*)r->real_request_rec);
! 546: }
! 547:
! 548:
! 549: // http_main.h
! 550:
! 551: void pa_ap_hard_timeout(char *s, pa_request_rec *r) {
! 552: ap_hard_timeout(s, (request_rec*)r->real_request_rec);
! 553: }
! 554: void pa_ap_reset_timeout(pa_request_rec *r) {
! 555: ap_reset_timeout((request_rec*)r->real_request_rec);
! 556: }
! 557: void pa_ap_kill_timeout(pa_request_rec *r) {
! 558: ap_kill_timeout((request_rec*)r->real_request_rec);
! 559: }
! 560:
! 561:
! 562: // util_script.h
! 563:
! 564: void pa_ap_add_cgi_vars(pa_request_rec *r) {
! 565: ap_add_cgi_vars((request_rec*)r->real_request_rec);
! 566: }
! 567: void pa_ap_add_common_vars(pa_request_rec *r) {
! 568: ap_add_common_vars((request_rec*)r->real_request_rec);
! 569: }
! 570:
! 571:
! 572: // ap_md5.h
! 573:
! 574: void pa_MD5Init(PA_MD5_CTX *context) { ap_MD5Init((AP_MD5_CTX*)context); }
! 575: void pa_MD5Update(PA_MD5_CTX *context, const unsigned char *input,
! 576: unsigned int inputLen) { ap_MD5Update((AP_MD5_CTX *)context, input, inputLen); }
! 577: void pa_MD5Final(unsigned char digest[MD5_DIGESTSIZE],
! 578: PA_MD5_CTX *context) { ap_MD5Final(digest, (AP_MD5_CTX *)context); }
! 579: void pa_MD5Encode(const unsigned char *password,
! 580: const unsigned char *salt,
! 581: char *result, size_t nbytes) { ap_MD5Encode(password, salt, result, nbytes); }
! 582: void pa_to64(char *s, unsigned long v, int n) { ap_to64(s, v, n); }
! 583:
! 584:
! 585: // signal.h
! 586:
! 587: void (*pa_signal (int sig, void (*disp)(int)))(int) {
! 588: if(sig==PA_SIGPIPE && disp==PA_SIG_IGN)
! 589: return signal(SIGPIPE, SIG_IGN);
! 590:
! 591: return 0;
! 592: }
E-mail: