Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch orefkovs-change Excluding Merge-Ins
This is equivalent to a diff from ab9b449190 to 102bfeae46
2013-02-19
| ||
05:15 | merge with trunk Leaf check-in: 102bfeae46 user: orefkov tags: orefkovs-change | |
2013-02-18
| ||
22:35 | Update version of OpenSSL that is referred to in the makefiles. Leaf check-in: ab9b449190 user: mistachkin tags: trunk | |
13:46 | Fixed ticket [5df2715635b99bd46a] (check-in count mismatch). check-in: b27c0d6d3f user: stephan tags: trunk | |
2013-01-31
| ||
05:10 | Очередное слияние с транком check-in: 738c8b3779 user: orefkov tags: orefkovs-change | |
Changes to Makefile.classic.
34 34 # for building intermediate code-generator tools. 35 35 # 36 36 #TCC = gcc -O6 37 37 #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage 38 38 TCC = gcc -g -Os -Wall 39 39 40 40 # To add support for HTTPS 41 -TCC += -DFOSSIL_ENABLE_SSL 41 +#TCC += -DFOSSIL_ENABLE_SSL 42 42 43 43 #### Extra arguments for linking the finished binary. Fossil needs 44 44 # to link against the Z-Lib compression library. There are no 45 45 # other dependencies. We sometimes add the -static option here 46 46 # so that we can build a static executable that will run in a 47 47 # chroot jail. 48 48 # 49 49 LIB = -lz $(LDFLAGS) 50 50 51 51 # If using HTTPS: 52 -LIB += -lcrypto -lssl 52 +#LIB += -lcrypto -lssl 53 53 54 54 #### Tcl shell for use in running the fossil testsuite. If you do not 55 55 # care about testing the end result, this can be blank. 56 56 # 57 57 TCLSH = tclsh 58 58 59 59 # You should not need to change anything below this line
Changes to src/attach.c.
47 47 " comment, user," 48 48 " (SELECT uuid FROM blob WHERE rid=attachid), attachid" 49 49 " FROM attachment", 50 50 -1 51 51 ); 52 52 if( zPage ){ 53 53 if( g.perm.RdWiki==0 ) login_needed(); 54 - style_header("Attachments To %h", zPage); 54 + style_header( 55 +#ifdef LANG_RU 56 + "Файлы к %h", 57 +#elif LANG_EN 58 + "Attachments To %h", 59 +#endif 60 + zPage); 55 61 blob_appendf(&sql, " WHERE target=%Q", zPage); 56 62 }else if( zTkt ){ 57 63 if( g.perm.RdTkt==0 ) login_needed(); 58 - style_header("Attachments To Ticket %.10s", zTkt); 64 + style_header( 65 +#ifdef LANG_RU 66 + "Файлы к задаче %.10s", 67 +#elif LANG_EN 68 + "Attachments To Ticket %.10s", 69 +#endif 70 + zTkt); 59 71 blob_appendf(&sql, " WHERE target GLOB '%q*'", zTkt); 60 72 }else{ 61 73 if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ) login_needed(); 62 - style_header("All Attachments"); 74 + style_header( 75 +#ifdef LANG_RU 76 + "Все файлы" 77 +#elif LANG_EN 78 + "All Attachments" 79 +#endif 80 + ); 63 81 } 64 82 blob_appendf(&sql, " ORDER BY mtime DESC"); 65 83 db_prepare(&q, "%s", blob_str(&sql)); 66 84 @ <ol> 67 85 while( db_step(&q)==SQLITE_ROW ){ 68 86 const char *zDate = db_column_text(&q, 0); 69 87 const char *zSrc = db_column_text(&q, 1); ................................................................................ 89 107 } 90 108 @ <li><p> 91 109 @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a> 92 110 if( moderation_pending(attachid) ){ 93 111 @ <span class="modpending">*** Awaiting Moderator Approval ***</span> 94 112 } 95 113 @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 96 - @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br /> 114 + @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)"> 115 +#ifdef LANG_RU 116 + @ скачать 117 +#elif LANG_EN 118 + @ download 119 +#endif 120 + @ </a>]<br /> 97 121 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; 98 122 if( zComment && zComment[0] ){ 99 123 @ %w(zComment)<br /> 100 124 } 101 125 if( zPage==0 && zTkt==0 ){ 102 126 if( zSrc==0 || zSrc[0]==0 ){ 127 +#ifdef LANG_RU 128 + zSrc = "Удалён из"; 129 +#elif LANG_EN 103 130 zSrc = "Deleted from"; 131 +#endif 104 132 }else { 133 +#ifdef LANG_RU 134 + zSrc = "Добавлен к"; 135 +#elif LANG_EN 105 136 zSrc = "Added to"; 137 +#endif 106 138 } 107 139 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){ 108 - @ %s(zSrc) ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)"> 140 +#ifdef LANG_RU 141 + @ %s(zSrc) задач%s(zSrc==0 || zSrc[0]==0 ? "и" : "е") 142 +#elif LANG_EN 143 + @ %s(zSrc) ticket 144 +#endif 145 + @ <a href="%s(g.zTop)/tktview?name=%s(zTarget)"> 109 146 @ %S(zTarget)</a> 110 147 }else{ 111 - @ %s(zSrc) wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)"> 148 +#ifdef LANG_RU 149 + @ %s(zSrc) страниц%s(zSrc==0 || zSrc[0]==0 ? "ы" : "е") 150 +#elif LANG_EN 151 + @ %s(zSrc) wiki page 152 +#endif 153 + @ <a href="%s(g.zTop)/wiki?name=%t(zTarget)"> 112 154 @ %h(zTarget)</a> 113 155 } 114 156 }else{ 115 157 if( zSrc==0 || zSrc[0]==0 ){ 158 +#ifdef LANG_RU 159 + @ Удалён 160 +#elif LANG_EN 116 161 @ Deleted 162 +#endif 117 163 }else { 164 +#ifdef LANG_RU 165 + @ Добавлен 166 +#elif LANG_EN 118 167 @ Added 168 +#endif 119 169 } 120 170 } 171 +#ifdef LANG_RU 172 + @ пользователем %h(zDispUser) 173 +#elif LANG_EN 121 174 @ by %h(zDispUser) on 175 +#endif 122 176 hyperlink_to_date(zDate, "."); 123 177 free(zUrlTail); 124 178 } 125 179 db_finalize(&q); 126 180 @ </ol> 127 181 style_footer(); 128 182 return; ................................................................................ 171 225 "SELECT coalesce(src,'x') FROM attachment" 172 226 " WHERE target=%Q AND filename=%Q" 173 227 " ORDER BY mtime DESC LIMIT 1", 174 228 zTarget, zFile 175 229 ); 176 230 } 177 231 if( zUUID==0 || zUUID[0]==0 ){ 232 +#ifdef LANG_RU 233 + style_header("Нет файлов"); 234 + @ Нет файлов.... 235 +#elif LANG_EN 178 236 style_header("No Such Attachment"); 179 237 @ No such attachment.... 238 +#endif 180 239 style_footer(); 181 240 return; 182 241 }else if( zUUID[0]=='x' ){ 242 +#ifdef LANG_RU 243 + style_header("Отсутствует"); 244 + @ Файл был удален 245 +#elif LANG_EN 183 246 style_header("Missing"); 184 247 @ Attachment has been deleted 248 +#endif 185 249 style_footer(); 186 250 return; 187 251 } 188 252 g.perm.Read = 1; 189 253 cgi_replace_parameter("name",zUUID); 190 254 if( fossil_strcmp(g.zPath,"attachview")==0 ){ 191 255 artifact_page(); ................................................................................ 235 299 const char *zFrom = P("from"); 236 300 const char *aContent = P("f"); 237 301 const char *zName = PD("f:filename","unknown"); 238 302 const char *zTarget; 239 303 const char *zTargetType; 240 304 int szContent = atoi(PD("f:bytes","0")); 241 305 int goodCaptcha = 1; 242 - 306 + const char *zComment = PD("comment", ""); 307 + 243 308 if( P("cancel") ) cgi_redirect(zFrom); 244 309 if( zPage && zTkt ) fossil_redirect_home(); 245 310 if( zPage==0 && zTkt==0 ) fossil_redirect_home(); 246 311 login_check_credentials(); 247 312 if( zPage ){ 248 313 if( g.perm.ApndWiki==0 || g.perm.Attach==0 ) login_needed(); 249 314 if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zPage) ){ 250 315 fossil_redirect_home(); 251 316 } 252 317 zTarget = zPage; 253 - zTargetType = mprintf("Wiki Page <a href=\"%s/wiki?name=%h\">%h</a>", 254 - g.zTop, zPage, zPage); 318 + zTargetType = mprintf( 319 +#ifdef LANG_RU 320 + "странице" 321 +#elif LANG_EN 322 + "Wiki Page" 323 +#endif 324 + " <a href=\"%s/wiki?name=%h\">%h</a>", 325 + g.zTop, zPage, zPage); 255 326 }else{ 256 327 if( g.perm.ApndTkt==0 || g.perm.Attach==0 ) login_needed(); 257 328 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){ 258 329 zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag" 259 330 " WHERE tagname GLOB 'tkt-%q*'", zTkt); 260 331 if( zTkt==0 ) fossil_redirect_home(); 261 332 } 262 333 zTarget = zTkt; 263 - zTargetType = mprintf("Ticket <a href=\"%s/tktview/%S\">%S</a>", 334 + zTargetType = mprintf( 335 +#ifdef LANG_RU 336 + "задаче" 337 +#elif LANG_EN 338 + "Ticket" 339 +#endif 340 + " <a href=\"%s/tktview/%S\">%S</a>", 264 341 g.zTop, zTkt, zTkt); 265 342 } 266 343 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); 267 344 if( P("cancel") ){ 268 345 cgi_redirect(zFrom); 269 346 } 270 347 if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){ 271 348 Blob content; 272 349 Blob manifest; 273 350 Blob cksum; 274 351 char *zUUID; 275 - const char *zComment; 276 352 char *zDate; 277 353 int rid; 278 354 int i, n; 279 355 int addCompress = 0; 280 356 Manifest *pManifest; 281 357 int needModerator; 282 358 ................................................................................ 298 374 for(i=n=0; zName[i]; i++){ 299 375 if( zName[i]=='/' || zName[i]=='\\' ) n = i; 300 376 } 301 377 zName += n; 302 378 if( zName[0]==0 ) zName = "unknown"; 303 379 blob_appendf(&manifest, "A %F%s %F %s\n", 304 380 zName, addCompress ? ".gz" : "", zTarget, zUUID); 305 - zComment = PD("comment", ""); 306 381 while( fossil_isspace(zComment[0]) ) zComment++; 307 382 n = strlen(zComment); 308 383 while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; } 309 384 if( n>0 ){ 310 385 blob_appendf(&manifest, "C %F\n", zComment); 311 386 } 312 387 zDate = date_in_standard_format("now"); ................................................................................ 315 390 md5sum_blob(&manifest, &cksum); 316 391 blob_appendf(&manifest, "Z %b\n", &cksum); 317 392 attach_put(&manifest, rid, needModerator); 318 393 assert( blob_is_reset(&manifest) ); 319 394 db_end_transaction(0); 320 395 cgi_redirect(zFrom); 321 396 } 397 +#ifdef LANG_RU 398 + style_header("Добавить файл"); 399 +#elif LANG_EN 322 400 style_header("Add Attachment"); 401 +#endif 323 402 if( !goodCaptcha ){ 403 +#ifdef LANG_RU 404 + @ <p class="generalError">Ошибка: неверный код.</p> 405 +#elif LANG_EN 324 406 @ <p class="generalError">Error: Incorrect security code.</p> 407 +#endif 325 408 } 409 +#ifdef LANG_RU 410 + @ <h2>Добавление файла к %s(zTargetType)</h2> 411 +#elif LANG_EN 326 412 @ <h2>Add Attachment To %s(zTargetType)</h2> 413 +#endif 327 414 form_begin("enctype='multipart/form-data'", "%R/attachadd"); 328 415 @ <div> 416 + 417 +#ifdef LANG_RU 418 + @ Файл для добавления: 419 +#elif LANG_EN 329 420 @ File to Attach: 330 - @ <input type="file" name="f" size="60" /><br /> 421 +#endif 422 + @ <input type="file" name="f" size="120" /><br /> 423 +#ifdef LANG_RU 424 + @ Описание:<br /> 425 +#elif LANG_EN 331 426 @ Description:<br /> 332 - @ <textarea name="comment" cols="80" rows="5" wrap="virtual"></textarea><br /> 427 +#endif 428 + @ <textarea name="comment" cols="80" rows="5" wrap="virtual">%h(zComment)</textarea><br /> 333 429 if( zTkt ){ 334 430 @ <input type="hidden" name="tkt" value="%h(zTkt)" /> 335 431 }else{ 336 432 @ <input type="hidden" name="page" value="%h(zPage)" /> 337 433 } 338 434 @ <input type="hidden" name="from" value="%h(zFrom)" /> 435 +#ifdef LANG_RU 436 + @ <input type="submit" name="ok" value="Добавить файл" /> 437 + @ <input type="submit" name="cancel" value="Отмена" /> 438 +#elif LANG_EN 339 439 @ <input type="submit" name="ok" value="Add Attachment" /> 340 440 @ <input type="submit" name="cancel" value="Cancel" /> 441 +#endif 341 442 @ </div> 342 443 captcha_generate(); 343 444 @ </form> 344 445 style_footer(); 345 446 } 346 447 347 448 /* ................................................................................ 431 532 blob_appendf(&manifest, "D %s\n", zDate); 432 533 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody"); 433 534 md5sum_blob(&manifest, &cksum); 434 535 blob_appendf(&manifest, "Z %b\n", &cksum); 435 536 rid = content_put(&manifest); 436 537 manifest_crosslink(rid, &manifest); 437 538 db_end_transaction(0); 539 +#ifdef LANG_RU 540 + @ <p>Указанный файл будет удален.</p> 541 +#elif LANG_EN 438 542 @ <p>The attachment below has been deleted.</p> 543 +#endif 439 544 } 440 545 441 546 if( P("del") 442 547 && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki)) 443 548 ){ 444 549 form_begin(0, "%R/ainfo/%s", zUuid); 550 +#ifdef LANG_RU 551 + @ <p>Подтвердите удаление указанного файла. 552 + @ <input type="submit" name="confirm" value="Подтверждаю"> 553 +#elif LANG_EN 445 554 @ <p>Confirm you want to delete the attachment shown below. 446 555 @ <input type="submit" name="confirm" value="Confirm"> 556 +#endif 447 557 @ </form> 448 558 } 449 559 450 560 isModerator = (zTktUuid && g.perm.ModTkt) || (zWikiName && g.perm.ModWiki); 451 561 if( isModerator && (zModAction = P("modaction"))!=0 ){ 452 562 if( strcmp(zModAction,"delete")==0 ){ 453 563 moderation_disapprove(rid); ................................................................................ 458 568 } 459 569 return; 460 570 } 461 571 if( strcmp(zModAction,"approve")==0 ){ 462 572 moderation_approve(rid); 463 573 } 464 574 } 575 +#ifdef LANG_RU 576 + style_header("Информация о вложении"); 577 + style_submenu_element("Как есть", "Как есть", "%R/artifact/%S", zUuid); 578 + 579 + @ <div class="section">Обзор</div> 580 + @ <p><table class="label-value"> 581 + @ <tr><th>ID артефакта:</th> 582 +#elif LANG_EN 465 583 style_header("Attachment Details"); 466 584 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid); 467 585 468 586 @ <div class="section">Overview</div> 469 587 @ <p><table class="label-value"> 470 588 @ <tr><th>Artifact ID:</th> 589 +#endif 471 590 @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a> 472 591 if( g.perm.Setup ){ 473 592 @ (%d(rid)) 474 593 } 475 594 modPending = moderation_pending(rid); 476 595 if( modPending ){ 596 +#ifdef LANG_RU 597 + @ <span class="modpending">*** Ожидает утверждения модератором ***</span> 598 +#elif LANG_EN 477 599 @ <span class="modpending">*** Awaiting Moderator Approval ***</span> 600 +#endif 478 601 } 479 602 if( zTktUuid ){ 603 +#ifdef LANG_RU 604 + @ <tr><th>Задача:</th> 605 +#elif LANG_EN 480 606 @ <tr><th>Ticket:</th> 607 +#endif 481 608 @ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr> 482 609 } 483 610 if( zWikiName ){ 611 +#ifdef LANG_RU 612 + @ <tr><th>Вики-страница:</th> 613 +#elif LANG_EN 484 614 @ <tr><th>Wiki Page:</th> 615 +#endif 485 616 @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a></td></tr> 486 617 } 618 +#ifdef LANG_RU 619 + @ <tr><th>Дата:</th><td> 620 +#elif LANG_EN 487 621 @ <tr><th>Date:</th><td> 622 +#endif 488 623 hyperlink_to_date(zDate, "</td></tr>"); 489 624 free(zDate); 625 +#ifdef LANG_RU 626 + @ <tr><th>Пользователь:</th><td> 627 +#elif LANG_EN 490 628 @ <tr><th>User:</th><td> 629 +#endif 491 630 hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>"); 631 +#ifdef LANG_RU 632 + @ <tr><th>Артефакт :</th> 633 +#elif LANG_EN 492 634 @ <tr><th>Artifact Attached:</th> 635 +#endif 493 636 @ <td>%z(href("%R/artifact/%s",zSrc))%s(zSrc)</a> 494 637 if( g.perm.Setup ){ 495 638 @ (%d(ridSrc)) 496 639 } 640 +#ifdef LANG_RU 641 + @ <tr><th>Имя файла:</th><td>%h(zName)</td></tr> 642 +#elif LANG_EN 497 643 @ <tr><th>Filename:</th><td>%h(zName)</td></tr> 644 +#endif 498 645 zMime = mimetype_from_name(zName); 499 646 if( g.perm.Setup ){ 500 647 @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr> 501 648 } 649 +#ifdef LANG_RU 650 + @ <tr><th valign="top">Описание:</th><td valign="top">%h(zDesc)</td></tr> 651 +#elif LANG_EN 502 652 @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr> 653 +#endif 503 654 @ </table> 504 655 505 656 if( isModerator && modPending ){ 657 +#ifdef LANG_RU 658 + @ <div class="section">Модерация</div> 659 +#elif LANG_EN 506 660 @ <div class="section">Moderation</div> 661 +#endif 507 662 @ <blockquote> 508 663 form_begin(0, "%R/ainfo/%s", zUuid); 509 664 @ <label><input type="radio" name="modaction" value="delete"> 665 +#ifdef LANG_RU 666 + @ Удалить это изменение</label><br /> 667 +#elif LANG_EN 510 668 @ Delete this change</label><br /> 669 +#endif 511 670 @ <label><input type="radio" name="modaction" value="approve"> 671 +#ifdef LANG_RU 672 + @ Утвердить это изменение</label><br /> 673 +#elif LANG_EN 512 674 @ Approve this change</label><br /> 675 +#endif 513 676 @ <input type="submit" value="Submit"> 514 677 @ </form> 515 678 @ </blockquote> 516 679 } 517 680 681 +#ifdef LANG_RU 682 + @ <div class="section">Содержимое</div> 683 +#elif LANG_EN 518 684 @ <div class="section">Content Appended</div> 685 +#endif 519 686 @ <blockquote> 520 687 blob_zero(&attach); 521 688 if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){ 522 689 const char *z; 523 690 const char *zLn = P("ln"); 524 691 content_get(ridSrc, &attach); 525 692 blob_to_utf8_no_bom(&attach, 0); ................................................................................ 529 696 }else{ 530 697 @ <pre> 531 698 @ %h(z) 532 699 @ </pre> 533 700 } 534 701 }else if( strncmp(zMime, "image/", 6)==0 ){ 535 702 @ <img src="%R/raw/%S(zSrc)?m=%s(zMime)"></img> 536 - style_submenu_element("Image", "Image", "%R/raw/%S?m=%s", zSrc, zMime); 703 + style_submenu_element("Изображение", "Изображение", "%R/raw/%S?m=%s", zSrc, zMime); 537 704 }else{ 538 705 int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc); 539 706 @ <i>(file is %d(sz) bytes of binary data)</i> 540 707 } 541 708 @ </blockquote> 542 709 manifest_destroy(pAttach); 543 710 blob_reset(&attach); ................................................................................ 570 737 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; 571 738 if( cnt==0 ){ 572 739 @ %s(zHeader) 573 740 } 574 741 cnt++; 575 742 @ <li> 576 743 @ %z(href("%R/artifact/%s",zSrc))%h(zFile)</a> 744 +#ifdef LANG_RU 745 + @ добавлено %h(zDispUser) 746 +#elif LANG_EN 577 747 @ added by %h(zDispUser) on 748 +#endif 578 749 hyperlink_to_date(zDate, "."); 750 +#ifdef LANG_RU 751 + @ [%z(href("%R/ainfo/%s",zUuid))детали</a>] 752 +#elif LANG_EN 579 753 @ [%z(href("%R/ainfo/%s",zUuid))details</a>] 754 +#endif 580 755 @ </li> 581 756 } 582 757 if( cnt ){ 583 758 @ </ul> 584 759 } 585 760 db_finalize(&q); 586 761 587 762 }
Changes to src/cgi.c.
1240 1240 cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); 1241 1241 #if 0 1242 1242 }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ 1243 1243 cgi_setenv("HTTP_REFERER", zVal); 1244 1244 #endif 1245 1245 }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ 1246 1246 cgi_setenv("HTTP_USER_AGENT", zVal); 1247 + }else if( fossil_strcmp(zFieldName,"x-real-ip:")==0 ){ 1248 + cgi_replace_parameter("REMOTE_ADDR", mprintf("%s",zVal)); 1247 1249 } 1248 1250 } 1249 1251 cgi_init(); 1250 1252 cgi_trace(0); 1251 1253 } 1252 1254 1253 1255 #if INTERFACE
Changes to src/checkin.c.
650 650 const char *zUuid, /* The artifact ID of the ancestor */ 651 651 const char *zDate /* Date & time of the current check-in */ 652 652 ){ 653 653 #ifndef FOSSIL_ALLOW_OUT_OF_ORDER_DATES 654 654 int b; 655 655 b = db_exists( 656 656 "SELECT 1 FROM event" 657 - " WHERE datetime(mtime)>=%Q" 657 + " WHERE strftime('%%Y-%%m-%%dT%%H:%%M:%%f', mtime)>=strftime('%%Y-%%m-%%dT%%H:%%M:%%f', %Q)" 658 658 " AND type='ci' AND objid=%d", 659 659 zDate, rid 660 660 ); 661 661 if( b ){ 662 662 fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)" 663 663 " Use --allow-older to override.", zUuid, zDate); 664 664 }
Changes to src/diff.c.
43 43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */ 44 44 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */ 45 45 46 46 /* 47 47 ** These error messages are shared in multiple locations. They are defined 48 48 ** here for consistency. 49 49 */ 50 + 50 51 #define DIFF_CANNOT_COMPUTE_BINARY \ 51 52 "cannot compute difference between binary files\n" 52 53 53 54 #define DIFF_CANNOT_COMPUTE_SYMLINK \ 54 55 "cannot compute difference between symlink and regular file\n" 55 56 56 57 #define DIFF_TOO_MANY_CHANGES_TXT \ ................................................................................ 707 708 p->iEnd = p->iEnd2; 708 709 p->iEnd2 = 0; 709 710 } 710 711 } 711 712 } 712 713 if( c=='\t' ){ 713 714 z[j++] = ' '; 714 - while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; } 715 + while( (k&3)!=3 && k<w ){ z[j++] = ' '; k++; } 715 716 }else if( c=='\r' || c=='\f' ){ 716 717 z[j++] = ' '; 717 718 }else if( c=='<' && p->escHtml ){ 718 719 memcpy(&z[j], "<", 4); 719 720 j += 4; 720 721 }else if( c=='&' && p->escHtml ){ 721 722 memcpy(&z[j], "&", 5);
Changes to src/info.c.
83 83 } 84 84 if( showFamily ){ 85 85 db_prepare(&q, "SELECT uuid, pid, isprim FROM plink JOIN blob ON pid=rid " 86 86 " WHERE cid=%d" 87 87 " ORDER BY isprim DESC, mtime DESC /*sort*/", rid); 88 88 while( db_step(&q)==SQLITE_ROW ){ 89 89 const char *zUuid = db_column_text(&q, 0); 90 - const char *zType = db_column_int(&q, 2) ? "parent:" : "merged-from:"; 90 + const char *zType = db_column_int(&q, 2) ? 91 +#ifdef LANG_RU 92 + "родитель:" 93 +#elif LANG_EN 94 + "parent:" 95 +#endif 96 + : 97 +#ifdef LANG_RU 98 + "слито с:" 99 +#elif LANG_EN 100 + "merged-from:" 101 +#endif 102 + ; 91 103 zDate = db_text("", 92 104 "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", 93 105 db_column_int(&q, 1) 94 106 ); 95 107 fossil_print("%-13s %s %s\n", zType, zUuid, zDate); 96 108 free(zDate); 97 109 } 98 110 db_finalize(&q); 99 111 db_prepare(&q, "SELECT uuid, cid, isprim FROM plink JOIN blob ON cid=rid " 100 112 " WHERE pid=%d" 101 113 " ORDER BY isprim DESC, mtime DESC /*sort*/", rid); 102 114 while( db_step(&q)==SQLITE_ROW ){ 103 115 const char *zUuid = db_column_text(&q, 0); 104 - const char *zType = db_column_int(&q, 2) ? "child:" : "merged-into:"; 116 + const char *zType = db_column_int(&q, 2) ? 117 +#ifdef LANG_RU 118 + "потомок:" 119 +#elif LANG_EN 120 + "child:" 121 +#endif 122 + : 123 +#ifdef LANG_RU 124 + "слито в:" 125 +#elif LANG_EN 126 + "merged-into:" 127 +#endif 128 + ; 105 129 zDate = db_text("", 106 130 "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", 107 131 db_column_int(&q, 1) 108 132 ); 109 133 fossil_print("%-13s %s %s\n", zType, zUuid, zDate); 110 134 free(zDate); 111 135 } 112 136 db_finalize(&q); 113 137 } 114 138 zTags = info_tags_of_checkin(rid, 0); 115 139 if( zTags && zTags[0] ){ 116 - fossil_print("tags: %s\n", zTags); 140 + fossil_print( 141 +#ifdef LANG_RU 142 + "теги: %s\n", 143 +#elif LANG_EN 144 + "tags: %s\n", 145 +#endif 146 + zTags); 117 147 } 118 148 free(zTags); 119 149 if( zComment ){ 120 - fossil_print("comment: "); 150 + fossil_print( 151 +#ifdef LANG_RU 152 + "комментарий: " 153 +#elif LANG_EN 154 + "comment: " 155 +#endif 156 + ); 121 157 comment_print(zComment, 14, 79); 122 158 free(zComment); 123 159 } 124 160 } 125 161 126 162 /* 127 163 ** Print information about the URLs used to access a repository and ................................................................................ 459 495 ReCompiled *pRe = 0; /* regex */ 460 496 461 497 login_check_credentials(); 462 498 if( !g.perm.Read ){ login_needed(); return; } 463 499 zName = P("name"); 464 500 rid = name_to_rid_www("name"); 465 501 if( rid==0 ){ 466 - style_header("Check-in Information Error"); 502 + style_header( 503 +#ifdef LANG_RU 504 + "Ошибка информации о фиксации" 505 +#elif LANG_EN 506 + "Check-in Information Error" 507 +#endif 508 + ); 509 +#ifdef LANG_RU 510 + @ Объект не найден: %h(g.argv[2]) 511 +#elif LANG_EN 467 512 @ No such object: %h(g.argv[2]) 513 +#endif 468 514 style_footer(); 469 515 return; 470 516 } 471 517 zRe = P("regex"); 472 518 if( zRe ) re_compile(&pRe, zRe, 0); 473 519 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); 474 520 zParent = db_text(0, ................................................................................ 484 530 " WHERE blob.rid=%d" 485 531 " AND event.objid=%d", 486 532 rid, rid 487 533 ); 488 534 sideBySide = atoi(PD("sbs","1")); 489 535 if( db_step(&q)==SQLITE_ROW ){ 490 536 const char *zUuid = db_column_text(&q, 0); 491 - char *zTitle = mprintf("Check-in [%.10s]", zUuid); 537 + char *zTitle = mprintf( 538 +#ifdef LANG_RU 539 + "Фиксация [%.10s]", 540 +#elif LANG_EN 541 + "Check-in [%.10s]", 542 +#endif 543 + zUuid); 492 544 char *zEUser, *zEComment; 493 545 const char *zUser; 494 546 const char *zComment; 495 547 const char *zDate; 496 548 const char *zOrigDate; 497 549 498 550 style_header(zTitle); ................................................................................ 504 556 zEComment = db_text(0, 505 557 "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d", 506 558 TAG_COMMENT, rid); 507 559 zUser = db_column_text(&q, 2); 508 560 zComment = db_column_text(&q, 3); 509 561 zDate = db_column_text(&q,1); 510 562 zOrigDate = db_column_text(&q, 4); 563 +#ifdef LANG_RU 564 + @ <div class="section">Обзор</div> 565 +#elif LANG_EN 511 566 @ <div class="section">Overview</div> 567 +#endif 512 568 @ <table class="label-value"> 513 - @ <tr><th>SHA1 Hash:</th><td>%s(zUuid) 569 + @ <tr><th> 570 +#ifdef LANG_RU 571 + @ SHA1 хэш: 572 +#elif LANG_EN 573 + @ SHA1 Hash: 574 +#endif 575 + @ </th><td>%s(zUuid) 514 576 if( g.perm.Setup ){ 577 +#ifdef LANG_RU 578 + @ (ID записи: %d(rid)) 579 +#elif LANG_EN 515 580 @ (Record ID: %d(rid)) 581 +#endif 516 582 } 517 583 @ </td></tr> 518 - @ <tr><th>Date:</th><td> 584 +#ifdef LANG_RU 585 + @ <tr><th>Дата:</th><td> 586 +#elif LANG_EN 587 + @ <tr><th>Date:</th><td> 588 +#endif 519 589 hyperlink_to_date(zDate, "</td></tr>"); 520 590 if( zOrigDate && fossil_strcmp(zDate, zOrigDate)!=0 ){ 591 +#ifdef LANG_RU 592 + @ <tr><th>Оригинальная дата:</th><td> 593 +#elif LANG_EN 521 594 @ <tr><th>Original Date:</th><td> 595 +#endif 522 596 hyperlink_to_date(zOrigDate, "</td></tr>"); 523 597 } 524 598 if( zEUser ){ 599 +#ifdef LANG_RU 600 + @ <tr><th>Исправлявший пользователь:</th><td> 601 +#elif LANG_EN 525 602 @ <tr><th>Edited User:</th><td> 603 +#endif 526 604 hyperlink_to_user(zEUser,zDate,"</td></tr>"); 605 +#ifdef LANG_RU 606 + @ <tr><th>Первый пользователь:</th><td> 607 +#elif LANG_EN 527 608 @ <tr><th>Original User:</th><td> 609 +#endif 528 610 hyperlink_to_user(zUser,zDate,"</td></tr>"); 529 611 }else{ 612 +#ifdef LANG_RU 613 + @ <tr><th>Пользователь:</th><td> 614 +#elif LANG_EN 530 615 @ <tr><th>User:</th><td> 616 +#endif 531 617 hyperlink_to_user(zUser,zDate,"</td></tr>"); 532 618 } 533 619 if( zEComment ){ 620 +#ifdef LANG_RU 621 + @ <tr><th>Исправленный комментарий:</th><td>%w(zEComment)</td></tr> 622 + @ <tr><th>Первоначальный комментарий:</th><td>%w(zComment)</td></tr> 623 +#elif LANG_EN 534 624 @ <tr><th>Edited Comment:</th><td>%w(zEComment)</td></tr> 535 625 @ <tr><th>Original Comment:</th><td>%w(zComment)</td></tr> 626 +#endif 536 627 }else{ 628 +#ifdef LANG_RU 629 + @ <tr><th>Comment:</th><td>%w(zComment)</td></tr> 630 +#elif LANG_EN 537 631 @ <tr><th>Comment:</th><td>%w(zComment)</td></tr> 632 +#endif 538 633 } 539 634 if( g.perm.Admin ){ 540 635 db_prepare(&q, 541 636 "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)" 542 637 " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)" 543 638 " WHERE blob.rid=%d", 544 639 rid 545 640 ); 546 641 if( db_step(&q)==SQLITE_ROW ){ 547 642 const char *zIpAddr = db_column_text(&q, 0); 548 643 const char *zUser = db_column_text(&q, 1); 549 644 const char *zDate = db_column_text(&q, 2); 550 645 if( zUser==0 || zUser[0]==0 ) zUser = "unknown"; 646 +#ifdef LANG_RU 647 + @ <tr><th>Получено от:</th> 648 + @ <td>%h(zUser) @ %h(zIpAddr) %s(zDate)</td></tr> 649 +#elif LANG_EN 551 650 @ <tr><th>Received From:</th> 552 651 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr> 652 +#endif 553 653 } 554 654 db_finalize(&q); 555 655 } 556 656 if( g.perm.Hyperlink ){ 557 657 const char *zProjName = db_get("project-name", "unnamed"); 658 +#ifdef LANG_RU 659 + @ <tr><th>События:</th><td> 660 + @ %z(href("%R/timeline?f=%S",zUuid))ближние</a> 661 + if( zParent ){ 662 + @ | %z(href("%R/timeline?p=%S",zUuid))родители</a> 663 + } 664 + if( !isLeaf ){ 665 + @ | %z(href("%R/timeline?d=%S",zUuid))потомки</a> 666 + } 667 + if( zParent && !isLeaf ){ 668 + @ | %z(href("%R/timeline?dp=%S",zUuid))обои</a> 669 + } 670 +#elif LANG_EN 558 671 @ <tr><th>Timelines:</th><td> 559 672 @ %z(href("%R/timeline?f=%S",zUuid))family</a> 560 673 if( zParent ){ 561 674 @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a> 562 675 } 563 676 if( !isLeaf ){ 564 677 @ | %z(href("%R/timeline?d=%S",zUuid))descendants</a> 565 678 } 566 679 if( zParent && !isLeaf ){ 567 680 @ | %z(href("%R/timeline?dp=%S",zUuid))both</a> 568 681 } 682 +#endif 569 683 db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag " 570 684 " WHERE rid=%d AND tagtype>0 " 571 685 " AND tag.tagid=tagxref.tagid " 572 686 " AND +tag.tagname GLOB 'sym-*'", rid); 573 687 while( db_step(&q)==SQLITE_ROW ){ 574 688 const char *zTagName = db_column_text(&q, 0); 575 689 @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a> ................................................................................ 576 690 } 577 691 db_finalize(&q); 578 692 579 693 580 694 /* The Download: line */ 581 695 if( g.perm.Zip ){ 582 696 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s", 583 - zProjName, zUuid, zUuid); 697 + zProjName, zUuid, zUuid); 584 698 @ </td></tr> 585 699 @ <tr><th>Downloads:</th><td> 586 700 @ %z(href("%s",zUrl))Tarball</a> 587 701 @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zProjName,zUuid,zUuid)) 702 +#ifdef LANG_RU 703 + @ ZIP архив</a> 704 +#elif LANG_EN 588 705 @ ZIP archive</a> 706 +#endif 589 707 fossil_free(zUrl); 590 708 } 591 - @ </td></tr> 709 + @ </td></tr> 710 +#ifdef LANG_RU 711 + @ <tr><th>Другие ссылки:</th> 712 + @ <td> 713 + @ %z(href("%R/dir?ci=%S",zUuid))файлы</a> 714 + @ | %z(href("%R/artifact/%S",zUuid))манифест</a> 715 +#elif LANG_EN 592 716 @ <tr><th>Other Links:</th> 593 717 @ <td> 594 718 @ %z(href("%R/dir?ci=%S",zUuid))files</a> 595 719 @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> 596 720 @ | %z(href("%R/artifact/%S",zUuid))manifest</a> 721 +#endif 597 722 if( g.perm.Write ){ 723 +#ifdef LANG_RU 724 + @ | %z(href("%R/ci_edit?r=%S",zUuid))изменить</a> 725 +#elif LANG_EN 598 726 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> 727 +#endif 599 728 } 600 729 @ </td> 601 730 @ </tr> 602 731 } 603 732 @ </table> 604 733 }else{ 605 - style_header("Check-in Information"); 734 + style_header( 735 +#ifdef LANG_RU 736 + "Информация о фиксации" 737 +#elif LANG_EN 738 + "Check-in Information" 739 +#endif 740 + ); 606 741 login_anonymous_available(); 607 742 } 608 743 db_finalize(&q); 609 744 showTags(rid, ""); 610 745 if( zParent ){ 746 +#ifdef LANG_RU 747 + @ <div class="section">Изменения</div> 748 +#elif LANG_EN 611 749 @ <div class="section">Changes</div> 750 +#endif 612 751 @ <div class="sectionmenu"> 613 752 showDiff = g.zPath[0]!='c'; 614 753 if( db_get_boolean("show-version-diffs", 0)==0 ){ 615 754 showDiff = !showDiff; 616 755 if( showDiff ){ 617 756 @ %z(xhref("class='button'","%R/vinfo/%T",zName)) 757 +#ifdef LANG_RU 758 + @ спрятать различия</a> 759 +#elif LANG_EN 618 760 @ hide diffs</a> 761 +#endif 619 762 if( sideBySide ){ 620 763 @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName)) 764 +#ifdef LANG_RU 765 + @ различия разом</a> 766 +#elif LANG_EN 621 767 @ unified diffs</a> 768 +#endif 622 769 }else{ 623 770 @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName)) 771 +#ifdef LANG_RU 772 + @ различия бок-о-бок</a> 773 +#elif LANG_EN 624 774 @ side-by-side diffs</a> 775 +#endif 625 776 } 626 777 }else{ 627 778 @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName)) 779 +#ifdef LANG_RU 780 + @ показать различия разом</a> 781 +#elif LANG_EN 628 782 @ show unified diffs</a> 783 +#endif 629 784 @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName)) 785 +#ifdef LANG_RU 786 + @ показать различия бок-о-бок</a> 787 +#elif LANG_EN 630 788 @ show side-by-side diffs</a> 789 +#endif 631 790 } 632 791 }else{ 633 792 if( showDiff ){ 634 - @ %z(xhref("class='button'","%R/ci/%T",zName))hide diffs</a> 793 + @ %z(xhref("class='button'","%R/ci/%T",zName)) 794 +#ifdef LANG_RU 795 + @ спрятать различия</a> 796 +#elif LANG_EN 797 + @ hide diffs</a> 798 +#endif 635 799 if( sideBySide ){ 636 800 @ %z(xhref("class='button'","%R/info/%T?sbs=0",zName)) 801 +#ifdef LANG_RU 802 + @ различия разом</a> 803 +#elif LANG_EN 637 804 @ unified diffs</a> 805 +#endif 638 806 }else{ 639 807 @ %z(xhref("class='button'","%R/info/%T?sbs=1",zName)) 808 +#ifdef LANG_RU 809 + @ различия бок-о-бок</a> 810 +#elif LANG_EN 640 811 @ side-by-side diffs</a> 812 +#endif 641 813 } 642 814 }else{ 643 815 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=0",zName)) 816 +#ifdef LANG_RU 817 + @ показать различия разом</a> 818 +#elif LANG_EN 644 819 @ show unified diffs</a> 820 +#endif 645 821 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=1",zName)) 822 +#ifdef LANG_RU 823 + @ показать различия бок-о-бок</a> 824 +#elif LANG_EN 646 825 @ show side-by-side diffs</a> 826 +#endif 647 827 } 648 828 } 829 + @ 649 830 @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid)) 650 - @ patch</a></div> 831 +#ifdef LANG_RU 832 + @ патч</a> 833 +#elif LANG_EN 834 + @ patch</a> 835 +#endif 836 + @</div> 837 + 651 838 if( pRe ){ 652 839 @ <p><b>Only differences that match regular expression "%h(zRe)" 653 840 @ are shown.</b></p> 654 841 } 655 842 db_prepare(&q, 656 843 "SELECT name," 657 844 " mperm," ................................................................................ 694 881 int modPending; 695 882 const char *zModAction; 696 883 697 884 login_check_credentials(); 698 885 if( !g.perm.RdWiki ){ login_needed(); return; } 699 886 rid = name_to_rid_www("name"); 700 887 if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){ 701 - style_header("Wiki Page Information Error"); 888 + style_header( 889 +#ifdef LANG_RU 890 + "Ошибка информации о странице" 891 +#elif LANG_EN 892 + "Wiki Page Information Error" 893 +#endif 894 + ); 895 +#ifdef LANG_RU 896 + @ Объект не найден: %h(g.argv[2]) 897 +#elif LANG_EN 702 898 @ No such object: %h(P("name")) 899 +#endif 703 900 style_footer(); 704 901 return; 705 902 } 706 903 if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){ 707 904 if( strcmp(zModAction,"delete")==0 ){ 708 905 moderation_disapprove(rid); 709 906 cgi_redirectf("%R/wiki?name=%T", pWiki->zWikiTitle); 710 907 /*NOTREACHED*/ 711 908 } 712 909 if( strcmp(zModAction,"approve")==0 ){ 713 910 moderation_approve(rid); 714 911 } 715 912 } 913 +#ifdef LANG_RU 914 + style_header("Правка \"%h\"", pWiki->zWikiTitle); 915 +#elif LANG_EN 716 916 style_header("Update of \"%h\"", pWiki->zWikiTitle); 917 +#endif 717 918 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); 718 919 zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); 920 +#ifdef LANG_RU 921 + style_submenu_element("Как есть", "Как есть", "artifact/%S", zUuid); 922 + style_submenu_element("История", "История", "whistory?name=%t", 923 + pWiki->zWikiTitle); 924 + style_submenu_element("Страница", "Страница", "wiki?name=%t", 925 + pWiki->zWikiTitle); 926 +#elif LANG_EN 719 927 style_submenu_element("Raw", "Raw", "artifact/%S", zUuid); 720 928 style_submenu_element("History", "History", "whistory?name=%t", 721 929 pWiki->zWikiTitle); 722 930 style_submenu_element("Page", "Page", "wiki?name=%t", 723 931 pWiki->zWikiTitle); 932 +#endif 724 933 login_anonymous_available(); 934 +#ifdef LANG_RU 935 + @ <div class="section">Обзор</div> 936 +#elif LANG_EN 725 937 @ <div class="section">Overview</div> 938 +#endif 726 939 @ <p><table class="label-value"> 940 +#ifdef LANG_RU 941 + @ <tr><th>ID артефакта:</th> 942 +#elif LANG_EN 727 943 @ <tr><th>Artifact ID:</th> 944 +#endif 728 945 @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a> 729 946 if( g.perm.Setup ){ 730 947 @ (%d(rid)) 731 948 } 732 949 modPending = moderation_pending(rid); 733 950 if( modPending ){ 951 +#ifdef LANG_RU 952 + @ <span class="modpending">*** Ожидает утверждения модератором ***</span> 953 +#elif LANG_EN 734 954 @ <span class="modpending">*** Awaiting Moderator Approval ***</span> 955 +#endif 735 956 } 736 957 @ </td></tr> 958 +#ifdef LANG_RU 959 + @ <tr><th>Имя страницы:</th><td>%h(pWiki->zWikiTitle)</td></tr> 960 + @ <tr><th>Дата:</th><td> 961 + hyperlink_to_date(zDate, "</td></tr>"); 962 + @ <tr><th>Создавший пользователь:</th><td> 963 +#elif LANG_EN 737 964 @ <tr><th>Page Name:</th><td>%h(pWiki->zWikiTitle)</td></tr> 738 965 @ <tr><th>Date:</th><td> 739 966 hyperlink_to_date(zDate, "</td></tr>"); 740 967 @ <tr><th>Original User:</th><td> 968 +#endif 741 969 hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>"); 742 970 if( pWiki->nParent>0 ){ 743 971 int i; 972 +#ifdef LANG_RU 973 + @ <tr><th>Родител%s(pWiki->nParent==1?"ь":"и"):</th><td> 974 +#elif LANG_EN 744 975 @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td> 976 +#endif 745 977 for(i=0; i<pWiki->nParent; i++){ 746 978 char *zParent = pWiki->azParent[i]; 747 979 @ %z(href("info/%S",zParent))%s(zParent)</a> 748 980 } 749 981 @ </td></tr> 750 982 } 751 983 @ </table> 752 984 753 985 if( g.perm.ModWiki && modPending ){ 986 +#ifdef LANG_RU 987 + @ <div class="section">Модерация</div> 988 +#elif LANG_EN 754 989 @ <div class="section">Moderation</div> 990 +#endif 755 991 @ <blockquote> 756 992 @ <form method="POST" action="%R/winfo/%s(zUuid)"> 757 993 @ <label><input type="radio" name="modaction" value="delete"> 994 +#ifdef LANG_RU 995 + @ Удалить это изменение</label><br /> 996 +#elif LANG_EN 758 997 @ Delete this change</label><br /> 998 +#endif 759 999 @ <label><input type="radio" name="modaction" value="approve"> 1000 +#ifdef LANG_RU 1001 + @ Утвердить это изменение</label><br /> 1002 +#elif LANG_EN 760 1003 @ Approve this change</label><br /> 1004 +#endif 1005 +#ifdef LANG_RU 1006 + @ <input type="submit" value="Ок"> 1007 +#elif LANG_EN 761 1008 @ <input type="submit" value="Submit"> 1009 +#endif 762 1010 @ </form> 763 1011 @ </blockquote> 764 1012 } 765 1013 766 1014 1015 +#ifdef LANG_RU 1016 + @ <div class="section">Содержимое</div> 1017 +#elif LANG_EN 767 1018 @ <div class="section">Content</div> 1019 +#endif 768 1020 blob_init(&wiki, pWiki->zWiki, -1); 769 1021 wiki_convert(&wiki, 0, 0); 770 1022 blob_reset(&wiki); 771 1023 manifest_destroy(pWiki); 772 1024 style_footer(); 773 1025 } 774 1026 ................................................................................ 777 1029 */ 778 1030 void webpage_error(const char *zFormat, ...){ 779 1031 va_list ap; 780 1032 const char *z; 781 1033 va_start(ap, zFormat); 782 1034 z = vmprintf(zFormat, ap); 783 1035 va_end(ap); 1036 +#ifdef LANG_RU 1037 + style_header("Ошибка URL"); 1038 + @ <h1>Ошибка</h1> 1039 +#elif LANG_EN 784 1040 style_header("URL Error"); 785 1041 @ <h1>Error</h1> 1042 +#endif 786 1043 @ <p>%h(z)</p> 787 1044 style_footer(); 788 1045 } 789 1046 790 1047 /* 791 1048 ** Find an checkin based on query parameter zParam and parse its 792 1049 ** manifest. Return the number of errors. 793 1050 */ 794 1051 static Manifest *vdiff_parse_manifest(const char *zParam, int *pRid){ 795 1052 int rid; 796 1053 797 1054 *pRid = rid = name_to_rid_www(zParam); 798 1055 if( rid==0 ){ 799 - const char *z = P(zParam); 800 - if( z==0 || z[0]==0 ){ 801 - webpage_error("Missing \"%s\" query parameter.", zParam); 802 - }else{ 803 - webpage_error("No such artifact: \"%s\"", z); 804 - } 805 - return 0; 1056 + const char *z = P(zParam); 1057 + if( z==0 || z[0]==0 ){ 1058 + webpage_error( 1059 +#ifdef LANG_RU 1060 + "Отсутствует параметр \"%s\" в запросе." 1061 +#elif LANG_EN 1062 + "Missing \"%s\" query parameter." 1063 +#endif 1064 + , zParam); 1065 + }else{ 1066 + webpage_error( 1067 +#ifdef LANG_RU 1068 + "Артефакт не найден: \"%s\"" 1069 +#elif LANG_EN 1070 + "No such artifact: \"%s\"" 1071 +#endif 1072 + , z); 1073 + } 1074 + return 0; 806 1075 } 807 1076 if( !is_a_version(rid) ){ 808 - webpage_error("Artifact %s is not a checkin.", P(zParam)); 1077 + webpage_error( 1078 +#ifdef LANG_RU 1079 + "Артефакт не Фиксация.", 1080 +#elif LANG_EN 1081 + "Artifact %s is not a checkin.", 1082 +#endif 1083 + P(zParam)); 809 1084 return 0; 810 1085 } 811 1086 return manifest_get(rid, CFTYPE_MANIFEST); 812 1087 } 813 1088 814 1089 /* 815 1090 ** Output a description of a check-in ................................................................................ 838 1113 wikiFlags |= WIKI_NOBLOCK; 839 1114 } 840 1115 hyperlink_to_uuid(zUuid); 841 1116 blob_zero(&comment); 842 1117 db_column_blob(&q, 2, &comment); 843 1118 wiki_convert(&comment, 0, wikiFlags); 844 1119 blob_reset(&comment); 1120 +#ifdef LANG_RU 1121 + @ (пользователь: 1122 +#elif LANG_EN 845 1123 @ (user: 1124 +#endif 846 1125 hyperlink_to_user(zUser,zDate,","); 847 1126 if( zTagList && zTagList[0] && g.perm.Hyperlink ){ 848 1127 int i; 849 1128 const char *z = zTagList; 850 1129 Blob links; 851 1130 blob_zero(&links); 852 1131 while( z && z[0] ){ ................................................................................ 854 1133 blob_appendf(&links, 855 1134 "%z%#h</a>%.2s", 856 1135 href("%R/timeline?r=%#t&nd&c=%t",i,z,zDate), i,z, &z[i] 857 1136 ); 858 1137 if( z[i]==0 ) break; 859 1138 z += i+2; 860 1139 } 1140 +#ifdef LANG_RU 1141 + @ метка: %s(blob_str(&links)), 1142 +#elif LANG_EN 861 1143 @ tags: %s(blob_str(&links)), 1144 +#endif 862 1145 blob_reset(&links); 863 1146 }else{ 864 - @ tags: %h(zTagList), 1147 +#ifdef LANG_RU 1148 + @ метка: %h(zTagList), 1149 +#elif LANG_EN 1150 + @ метка: %h(zTagList), 1151 +#endif 865 1152 } 1153 +#ifdef LANG_RU 1154 + @ дата: 1155 +#elif LANG_EN 866 1156 @ date: 1157 +#endif 867 1158 hyperlink_to_date(zDate, ")"); 868 1159 } 869 1160 db_finalize(&q); 870 1161 } 871 1162 872 1163 873 1164 /* ................................................................................ 915 1206 if( pFrom==0 ) return; 916 1207 sideBySide = atoi(PD("sbs","1")); 917 1208 showDetail = atoi(PD("detail","0")); 918 1209 if( !showDetail && sideBySide ) showDetail = 1; 919 1210 zFrom = P("from"); 920 1211 zTo = P("to"); 921 1212 if( !sideBySide ){ 922 - style_submenu_element("Side-by-side Diff", "sbsdiff", 1213 + style_submenu_element( 1214 +#ifdef LANG_RU 1215 + "Различия бок-о-бок", "sbsdiff", 1216 +#elif LANG_EN 1217 + "Side-by-side Diff", "sbsdiff", 1218 +#endif 923 1219 "%R/vdiff?from=%T&to=%T&detail=%d&sbs=1", 924 1220 zFrom, zTo, showDetail); 925 1221 }else{ 926 - style_submenu_element("Unified Diff", "udiff", 1222 + style_submenu_element( 1223 +#ifdef LANG_RU 1224 + "Различия разом", "udiff", 1225 +#elif LANG_EN 1226 + "Unified Diff", "udiff", 1227 +#endif 927 1228 "%R/vdiff?from=%T&to=%T&detail=%d&sbs=0", 928 1229 zFrom, zTo, showDetail); 929 1230 } 930 1231 style_submenu_element("Invert", "invert", 931 1232 "%R/vdiff?from=%T&to=%T&detail=%d&sbs=%d", 932 1233 zTo, zFrom, showDetail, sideBySide); 1234 +#ifdef LANG_RU 1235 + style_header("Различия в фиксации"); 1236 + @ <h2>Различия между:</h2><blockquote> 1237 + checkin_description(ridFrom); 1238 +#elif LANG_EN 933 1239 style_header("Check-in Differences"); 934 1240 @ <h2>Difference From:</h2><blockquote> 935 1241 checkin_description(ridFrom); 936 - @ </blockquote><h2>To:</h2><blockquote> 1242 +#endif 1243 + @ </blockquote><h2> 1244 +#ifdef LANG_RU 1245 + @ и: 1246 +#elif LANG_EN 1247 + @ To: 1248 +#endif 1249 + @ </h2><blockquote> 937 1250 checkin_description(ridTo); 938 1251 @ </blockquote> 939 1252 if( pRe ){ 940 1253 @ <p><b>Only differences that match regular expression "%h(zRe)" 941 1254 @ are shown.</b></p> 942 1255 } 943 1256 @<hr /><p> ................................................................................ 1271 1584 if( zRe ) re_compile(&pRe, zRe, 0); 1272 1585 content_get(v1, &c1); 1273 1586 content_get(v2, &c2); 1274 1587 text_diff(&c1, &c2, pOut, pRe, diffFlags); 1275 1588 blob_reset(&c1); 1276 1589 blob_reset(&c2); 1277 1590 if( !isPatch ){ 1591 +#ifdef LANG_RU 1592 + style_header("Различия"); 1593 +#elif LANG_EN 1278 1594 style_header("Diff"); 1279 - style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", 1595 +#endif 1596 + style_submenu_element( 1597 +#ifdef LANG_RU 1598 + "Патч", "Патч", 1599 +#elif LANG_EN 1600 + "Patch", "Patch", 1601 +#endif 1602 + "%s/fdiff?v1=%T&v2=%T&patch", 1280 1603 g.zTop, P("v1"), P("v2")); 1281 1604 if( !sideBySide ){ 1282 - style_submenu_element("Side-by-side Diff", "sbsdiff", 1605 + style_submenu_element( 1606 +#ifdef LANG_RU 1607 + "Различия бок-о-бок", "sbsdiff", 1608 +#elif LANG_EN 1609 + "Side-by-side Diff", "sbsdiff", 1610 +#endif 1283 1611 "%s/fdiff?v1=%T&v2=%T&sbs=1", 1284 1612 g.zTop, P("v1"), P("v2")); 1285 1613 }else{ 1286 - style_submenu_element("Unified Diff", "udiff", 1614 + style_submenu_element( 1615 +#ifdef LANG_RU 1616 + "Различия разом", "udiff", 1617 +#elif LANG_EN 1618 + "Unified Diff", "udiff", 1619 +#endif 1287 1620 "%s/fdiff?v1=%T&v2=%T&sbs=0", 1288 1621 g.zTop, P("v1"), P("v2")); 1289 1622 } 1290 1623 1291 1624 if( P("smhdr")!=0 ){ 1625 +#ifdef LANG_RU 1626 + @ <h2>Различия между артефактом 1627 +#elif LANG_EN 1292 1628 @ <h2>Differences From Artifact 1293 - @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To 1629 +#endif 1630 + @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> 1631 +#ifdef LANG_RU 1632 + @ и 1633 +#elif LANG_EN 1634 + @ To 1635 +#endif 1294 1636 @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2> 1295 1637 }else{ 1296 - @ <h2>Differences From 1297 - @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2> 1638 +#ifdef LANG_RU 1639 + @ <h2>Различия между артефактом 1640 +#elif LANG_EN 1641 + @ <h2>Differences From Artifact 1642 +#endif 1643 + @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2> 1298 1644 object_description(v1, 0, 0); 1299 - @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2> 1645 + @ <h2> 1646 +#ifdef LANG_RU 1647 + @ и артефактом 1648 +#elif LANG_EN 1649 + @ To Artifact 1650 +#endif 1651 + @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2> 1300 1652 object_description(v2, 0, 0); 1301 1653 } 1302 1654 if( pRe ){ 1303 1655 @ <b>Only differences that match regular expression "%h(zRe)" 1304 1656 @ are shown.</b> 1305 1657 } 1306 1658 @ <hr /> ................................................................................ 1414 1766 rid = name_to_rid_www("name"); 1415 1767 login_check_credentials(); 1416 1768 if( !g.perm.Read ){ login_needed(); return; } 1417 1769 if( rid==0 ) fossil_redirect_home(); 1418 1770 if( g.perm.Admin ){ 1419 1771 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 1420 1772 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1421 - style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1773 + style_submenu_element( 1774 +#ifdef LANG_RU 1775 + "Восстановить","Восстановить", 1776 +#elif LANG_EN 1777 + "Unshun","Unshun", 1778 +#endif 1779 + "%s/shun?uuid=%s&sub=1", 1422 1780 g.zTop, zUuid); 1423 1781 }else{ 1424 - style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1782 + style_submenu_element( 1783 +#ifdef LANG_RU 1784 + "Стереть","Стереть", 1785 +#elif LANG_EN 1786 + "Shun","Shun", 1787 +#endif 1788 + "%s/shun?shun=%s#addshun", 1425 1789 g.zTop, zUuid); 1426 1790 } 1427 1791 } 1428 - style_header("Hex Artifact Content"); 1792 + style_header( 1793 +#ifdef LANG_RU 1794 + "Содержимое бинарного артефакта" 1795 +#elif LANG_EN 1796 + "Hex Artifact Content" 1797 +#endif 1798 + ); 1429 1799 zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid); 1430 1800 if( g.perm.Setup ){ 1801 +#ifdef LANG_RU 1802 + @ <h2>Артефакт %s(zUuid) (%d(rid)):</h2> 1803 + }else{ 1804 + @ <h2>Artifact %s(zUuid):</h2> 1805 +#elif LANG_EN 1431 1806 @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> 1432 1807 }else{ 1433 1808 @ <h2>Artifact %s(zUuid):</h2> 1809 +#endif 1434 1810 } 1435 1811 blob_zero(&downloadName); 1436 1812 object_description(rid, 0, &downloadName); 1813 +#ifdef LANG_RU 1814 + style_submenu_element("Скачать", "Скачать", 1815 +#elif LANG_EN 1437 1816 style_submenu_element("Download", "Download", 1817 +#endif 1438 1818 "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); 1439 1819 @ <hr /> 1440 1820 content_get(rid, &content); 1441 1821 @ <blockquote><pre> 1442 1822 hexdump(&content); 1443 1823 @ </pre></blockquote> 1444 1824 style_footer(); ................................................................................ 1571 1951 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1572 1952 g.zTop, zUuid); 1573 1953 }else{ 1574 1954 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1575 1955 g.zTop, zUuid); 1576 1956 } 1577 1957 } 1958 +#ifdef LANG_RU 1959 + style_header("Содержимое артефакта"); 1960 +#elif LANG_EN 1578 1961 style_header("Artifact Content"); 1962 +#endif 1579 1963 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); 1580 1964 if( g.perm.Setup ){ 1965 +#ifdef LANG_RU 1966 + @ <h2>Артефакт %s(zUuid) (%d(rid)):</h2> 1967 + }else{ 1968 + @ <h2>Артефакт %s(zUuid):</h2> 1969 +#elif LANG_EN 1581 1970 @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> 1582 1971 }else{ 1583 1972 @ <h2>Artifact %s(zUuid):</h2> 1973 +#endif 1584 1974 } 1975 + @ <blockquote><p> 1585 1976 blob_zero(&downloadName); 1586 1977 objType = object_description(rid, 0, &downloadName); 1978 +#ifdef LANG_RU 1979 + style_submenu_element("Скачать", "Скачать", 1980 +#elif LANG_EN 1587 1981 style_submenu_element("Download", "Download", 1982 +#endif 1588 1983 "%R/raw/%T?name=%s", blob_str(&downloadName), zUuid); 1589 1984 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ 1985 +#ifdef LANG_RU 1986 + style_submenu_element("Используется в фиксациях", "Используется в фиксациях", 1987 +#elif LANG_EN 1590 1988 style_submenu_element("Checkins Using", "Checkins Using", 1989 +#endif 1591 1990 "%R/timeline?uf=%s&n=200",zUuid); 1592 1991 } 1593 1992 asText = P("txt")!=0; 1594 1993 zMime = mimetype_from_name(blob_str(&downloadName)); 1595 1994 if( zMime ){ 1596 1995 if( fossil_strcmp(zMime, "text/html")==0 ){ 1597 1996 if( asText ){ 1598 1997 style_submenu_element("Html", "Html", 1599 1998 "%s/artifact/%s", g.zTop, zUuid); 1600 1999 }else{ 1601 2000 renderAsHtml = 1; 1602 - style_submenu_element("Text", "Text", 2001 + style_submenu_element( 2002 +#ifdef LANG_RU 2003 + "Текст", "Показать как текст", 2004 +#elif LANG_EN 2005 + "Text", "Text", 2006 +#endif 1603 2007 "%s/artifact/%s?txt=1", g.zTop, zUuid); 1604 2008 } 1605 2009 }else if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){ 1606 2010 if( asText ){ 1607 - style_submenu_element("Wiki", "Wiki", 2011 + style_submenu_element( 2012 +#ifdef LANG_RU 2013 + "Вики", "Показать как вики", 2014 +#elif LANG_EN 2015 + "Wiki", "Wiki", 2016 +#endif 1608 2017 "%s/artifact/%s", g.zTop, zUuid); 1609 2018 }else{ 1610 2019 renderAsWiki = 1; 1611 - style_submenu_element("Text", "Text", 2020 + style_submenu_element( 2021 +#ifdef LANG_RU 2022 + "Текст", "Показать как текст", 2023 +#elif LANG_EN 2024 + "Text", "Text", 2025 +#endif 1612 2026 "%s/artifact/%s?txt=1", g.zTop, zUuid); 1613 2027 } 1614 2028 } 1615 2029 } 1616 2030 if( (objType & (OBJTYPE_WIKI|OBJTYPE_TICKET))!=0 ){ 1617 2031 style_submenu_element("Parsed", "Parsed", "%R/info/%s", zUuid); 1618 2032 } ................................................................................ 1642 2056 @ </pre> 1643 2057 } 1644 2058 }else if( strncmp(zMime, "image/", 6)==0 ){ 1645 2059 @ <img src="%R/raw/%S(zUuid)?m=%s(zMime)" /> 1646 2060 style_submenu_element("Image", "Image", 1647 2061 "%R/raw/%S?m=%s", zUuid, zMime); 1648 2062 }else{ 2063 +#ifdef LANG_RU 2064 + @ <i>(бинарный файл, байт: %d(blob_size(&content)))</i> 2065 +#elif LANG_EN 1649 2066 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> 2067 +#endif 1650 2068 } 1651 2069 @ </blockquote> 1652 2070 } 1653 2071 style_footer(); 1654 2072 } 1655 2073 1656 2074 /*
Changes to src/login.c.
491 491 zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); 492 492 if( db_int(1, "SELECT 0 FROM user" 493 493 " WHERE uid=%d" 494 494 " AND (constant_time_cmp(pw,%Q)=0" 495 495 " OR constant_time_cmp(pw,%Q)=0)", 496 496 g.userUid, zSha1Pw, zPasswd) ){ 497 497 sleep(1); 498 +#ifdef LANG_RU 499 + zErrMsg = 500 + @ <p><span class="loginError"> 501 + @ Вы ввели неверный старый пароль. 502 + @ Ваш пароль не изменен. 503 + @ </span></p> 504 +#elif LANG_EN 498 505 zErrMsg = 499 - @ <p><span class="loginError"> 500 - @ You entered an incorrect old password while attempting to change 501 - @ your password. Your password is unchanged. 502 - @ </span></p> 506 + @ <p><span class="loginError"> 507 + @ You entered an incorrect old password while attempting to change 508 + @ your password. Your password is unchanged. 509 + @ </span></p> 510 +#endif 503 511 ; 504 512 }else if( fossil_strcmp(zNew1,zNew2)!=0 ){ 513 +#ifdef LANG_RU 514 + zErrMsg = 515 + @ <p><span class="loginError"> 516 + @ Два введенных новых пароля не совпадают. 517 + @ Ваш пароль не изменен. 518 + @ </span></p> 519 +#elif LANG_EN 505 520 zErrMsg = 506 - @ <p><span class="loginError"> 507 - @ The two copies of your new passwords do not match. 508 - @ Your password is unchanged. 509 - @ </span></p> 521 + @ <p><span class="loginError"> 522 + @ The two copies of your new passwords do not match. 523 + @ Your password is unchanged. 524 + @ </span></p> 525 +#endif 510 526 ; 511 527 }else{ 512 528 char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0); 513 529 char *zChngPw; 514 530 char *zErr; 515 531 db_multi_exec( 516 532 "UPDATE user SET pw=%Q WHERE uid=%d", zNewPw, g.userUid ................................................................................ 541 557 } 542 558 if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ 543 559 /* Attempting to log in as a user other than anonymous. 544 560 */ 545 561 uid = login_search_uid(zUsername, zPasswd); 546 562 if( uid<=0 ){ 547 563 sleep(1); 564 +#ifdef LANG_RU 548 565 zErrMsg = 549 566 @ <p><span class="loginError"> 567 + @ Вы ввели неверный пароль или имя несущестующего пользователя. 568 + @ </span></p> 569 +#elif LANG_EN 570 + zErrMsg = 571 + @ <p><span class="loginError"> 550 572 @ You entered an unknown user or an incorrect password. 551 573 @ </span></p> 574 +#endif 552 575 ; 553 576 record_login_attempt(zUsername, zIpAddr, 0); 554 577 }else{ 555 578 /* Non-anonymous login is successful. Set a cookie of the form: 556 579 ** 557 580 ** HASH/PROJECT/LOGIN 558 581 ** ................................................................................ 559 582 ** where HASH is a random hex number, PROJECT is either project 560 583 ** code prefix, and LOGIN is the user name. 561 584 */ 562 585 login_set_user_cookie(zUsername, uid, NULL); 563 586 redirect_to_g(); 564 587 } 565 588 } 566 - style_header("Login/Logout"); 589 + style_header( 590 +#ifdef LANG_RU 591 + "Вход/Выход" 592 +#elif LANG_EN 593 + "Login/Logout" 594 +#endif 595 + ); 567 596 @ %s(zErrMsg) 568 597 if( zGoto && P("anon")==0 ){ 569 598 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p> 570 599 } 571 600 form_begin(0, "%R/login"); 572 601 if( zGoto ){ 573 602 @ <input type="hidden" name="g" value="%h(zGoto)" /> 574 603 } 575 604 @ <table class="login_out"> 576 605 @ <tr> 577 - @ <td class="login_out_label">User ID:</td> 606 + @ <td class="login_out_label"> 607 +#ifdef LANG_RU 608 + @ Пользователь: 609 +#elif LANG_EN 610 + @ User ID: 611 +#endif 612 + @ </td> 578 613 if( anonFlag ){ 579 614 @ <td><input type="text" id="u" name="u" value="anonymous" size="30" /></td> 580 615 }else{ 581 616 @ <td><input type="text" id="u" name="u" value="" size="30" /></td> 582 617 } 583 618 @ </tr> 584 619 @ <tr> 585 - @ <td class="login_out_label">Password:</td> 620 + @ <td class="login_out_label"> 621 +#ifdef LANG_RU 622 + @ Пароль: 623 +#elif LANG_EN 624 + @ Password: 625 +#endif 626 + @ </td> 586 627 @ <td><input type="password" id="p" name="p" value="" size="30" /></td> 587 628 @ </tr> 588 629 if( g.zLogin==0 ){ 589 630 zAnonPw = db_text(0, "SELECT pw FROM user" 590 631 " WHERE login='anonymous'" 591 632 " AND cap!=''"); 592 633 } 593 634 @ <tr> 594 635 @ <td></td> 636 +#ifdef LANG_RU 637 + @ <td><input type="submit" name="in" value="Вход" 638 +#elif LANG_EN 595 639 @ <td><input type="submit" name="in" value="Login" 640 +#endif 596 641 @ onClick="chngAction(this.form)" /></td> 597 642 @ </tr> 598 643 @ </table> 599 644 @ <script type="text/JavaScript"> 600 645 @ gebi('u').focus() 601 646 @ function chngAction(form){ 602 647 if( g.sslNotAvailable==0 ................................................................................ 606 651 char *zSSL = mprintf("https:%s", &g.zBaseURL[5]); 607 652 @ if( form.u.value!="anonymous" ){ 608 653 @ form.action = "%h(zSSL)/login"; 609 654 @ } 610 655 } 611 656 @ } 612 657 @ </script> 613 - if( g.zLogin==0 ){ 614 - @ <p>Enter 615 - }else{ 616 - @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p> 617 - @ <p>To change your login to a different user, enter 618 - } 619 - @ your user-id and password at the left and press the 620 - @ "Login" button. Your user name will be stored in a browser cookie. 621 - @ You must configure your web browser to accept cookies in order for 622 - @ the login to take.</p> 658 +#ifdef LANG_RU 659 + if( g.zLogin==0 ){ 660 + @ <p>Укажите 661 + }else{ 662 + @ <p>Вы вошли как <b>%h(g.zLogin)</b></p> 663 + @ <p>Чтобы войти под другим именем, укажите 664 + } 665 + @ имя пользователя и пароль, и нажмите кнопку "Вход". 666 + @ Введенное имя будет сохранено в куках браузера. 667 + @ Вы должны разрешить браузеру сохранять куки для возможности входа 668 + @ на сайт.</p> 669 +#elif LANG_EN 670 + if( g.zLogin==0 ){ 671 + @ <p>Enter 672 + }else{ 673 + @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p> 674 + @ <p>To change your login to a different user, enter 675 + } 676 + @ your user-id and password at the left and press the 677 + @ "Login" button. Your user name will be stored in a browser cookie. 678 + @ You must configure your web browser to accept cookies in order for 679 + @ the login to take.</p> 680 +#endif 681 + 623 682 if( db_get_boolean("self-register", 0) ){ 683 +#ifdef LANG_RU 684 + @ <p>Если у вас нет аккаунта, вы можете 685 + @ <a href="%s(g.zTop)/register?g=%T(P("G"))">зарегистрироваться</a>. 686 +#elif LANG_EN 624 687 @ <p>If you do not have an account, you can 625 688 @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>. 689 +#endif 626 690 } 691 + 627 692 if( zAnonPw ){ 628 693 unsigned int uSeed = captcha_seed(); 629 694 char const *zDecoded = captcha_decode(uSeed); 630 695 int bAutoCaptcha = db_get_boolean("auto-captcha", 0); 631 696 char *zCaptcha = captcha_render(zDecoded); 632 697 633 698 @ <p><input type="hidden" name="cs" value="%u(uSeed)" /> 699 +#ifdef LANG_RU 700 + @ Гости могут указать <b>anonymous</b> как имя пользователя 701 + @ и ввести 8-символьный пароль, указанный ниже:</p> 702 +#elif LANG_EN 634 703 @ Visitors may enter <b>anonymous</b> as the user-ID with 635 704 @ the 8-character hexadecimal password shown below:</p> 705 +#endif 636 706 @ <div class="captcha"><table class="captcha"><tr><td><pre> 637 707 @ %h(zCaptcha) 638 708 @ </pre></td></tr></table> 639 709 if( bAutoCaptcha ) { 640 - @ <input type="button" value="Fill out captcha" 710 +#ifdef LANG_RU 711 + @ <input type="button" value="Заполнить капчу" 712 +#elif LANG_EN 713 + @ <input type="button" value="Fill out captcha" 714 +#endif 641 715 @ onclick="gebi('u').value='anonymous'; gebi('p').value='%s(zDecoded)';" /> 642 716 } 643 717 @ </div> 644 718 free(zCaptcha); 645 719 } 646 720 if( g.zLogin ){ 647 721 @ <hr /> 722 +#ifdef LANG_RU 723 + @ <p>Для выхода 724 + @ нажмите эту кнопку:<br /> 725 + @ <input type="submit" name="out" value="Выход" /></p> 726 +#elif LANG_EN 648 727 @ <p>To log off the system (and delete your login cookie) 649 728 @ press the following button:<br /> 650 729 @ <input type="submit" name="out" value="Logout" /></p> 730 +#endif 651 731 } 652 732 @ </form> 653 733 if( g.perm.Password ){ 654 734 @ <hr /> 735 +#ifdef LANG_RU 736 + @ <p>Для смены своего пароля введите текущий пароль и два раза 737 + @ новый, после чего нажмите кнопку "Изменить пароль".</p> 738 + @ <form action="login" method="post"> 739 + @ <table> 740 + @ <tr><td class="login_out_label">Старый пароль:</td> 741 + @ <td><input type="password" name="p" size="30" /></td></tr> 742 + @ <tr><td class="login_out_label">Новый пароль:</td> 743 + @ <td><input type="password" name="n1" size="30" /></td></tr> 744 + @ <tr><td class="login_out_label">Повторите новый пароль:</td> 745 + @ <td><input type="password" name="n2" size="30" /></td></tr> 746 + @ <tr><td></td> 747 + @ <td><input type="submit" value="Изменить пароль" /></td></tr> 748 +#elif LANG_EN 655 749 @ <p>To change your password, enter your old password and your 656 750 @ new password twice below then press the "Change Password" 657 751 @ button.</p> 658 752 form_begin(0, "%R/login"); 659 753 @ <table> 660 754 @ <tr><td class="login_out_label">Old Password:</td> 661 755 @ <td><input type="password" name="p" size="30" /></td></tr> 662 756 @ <tr><td class="login_out_label">New Password:</td> 663 757 @ <td><input type="password" name="n1" size="30" /></td></tr> 664 758 @ <tr><td class="login_out_label">Repeat New Password:</td> 665 759 @ <td><input type="password" name="n2" size="30" /></td></tr> 666 760 @ <tr><td></td> 667 761 @ <td><input type="submit" value="Change Password" /></td></tr> 762 +#endif 668 763 @ </table> 669 764 @ </form> 670 765 } 671 766 style_footer(); 672 767 } 673 768 674 769 /* ................................................................................ 1143 1238 */ 1144 1239 void login_anonymous_available(void){ 1145 1240 if( !g.perm.Hyperlink && 1146 1241 db_exists("SELECT 1 FROM user" 1147 1242 " WHERE login='anonymous'" 1148 1243 " AND cap LIKE '%%h%%'") ){ 1149 1244 const char *zUrl = PD("REQUEST_URI", "index"); 1245 +#ifdef LANG_RU 1246 + @ <p>Многие <span class="disabled">ссылки отключены.</span><br /> 1247 + @ Используйте <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">анонимный вход</a> 1248 + @ для включения ссылок.</p> 1249 +#elif LANG_EN 1150 1250 @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br /> 1151 1251 @ Use <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">anonymous login</a> 1152 1252 @ to enable hyperlinks.</p> 1253 +#endif 1153 1254 } 1154 1255 } 1155 1256 1156 1257 /* 1157 1258 ** While rendering a form, call this routine to add the Anti-CSRF token 1158 1259 ** as a hidden element of the form. 1159 1260 */
Changes to src/main.mk.
6 6 # This file is automatically generated. Instead of editing this 7 7 # file, edit "makemake.tcl" then run "tclsh makemake.tcl" 8 8 # to regenerate this file. 9 9 # 10 10 # This file is included by primary Makefile. 11 11 # 12 12 13 -XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) -I$(OBJDIR) 13 +XTCC = $(TCC) $(CFLAGS) -DFOSSIL_ENABLE_JSON -DLANG_RU -I. -I$(SRCDIR) -I$(OBJDIR) 14 14 15 15 16 16 SRC = \ 17 17 $(SRCDIR)/add.c \ 18 18 $(SRCDIR)/allrepo.c \ 19 19 $(SRCDIR)/attach.c \ 20 20 $(SRCDIR)/bag.c \
Changes to src/manifest.c.
1550 1550 if( !isNew ){ 1551 1551 for(i=0; i<pManifest->nField; i++){ 1552 1552 if( fossil_strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){ 1553 1553 zNewStatus = pManifest->aField[i].zValue; 1554 1554 } 1555 1555 } 1556 1556 if( zNewStatus ){ 1557 +#ifdef LANG_RU 1558 + blob_appendf(&comment, "%h задача [%.10s]: <i>%h</i>", 1559 +#elif LANG_EN 1557 1560 blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>", 1561 +#endif 1558 1562 zNewStatus, pManifest->zTicketUuid, zTitle 1559 1563 ); 1560 1564 if( pManifest->nField>1 ){ 1565 +#ifdef LANG_RU 1566 + blob_appendf(&comment, " плюс еще изменений %d", 1567 +#elif LANG_EN 1561 1568 blob_appendf(&comment, " plus %d other change%s", 1569 +#endif 1562 1570 pManifest->nField-1, pManifest->nField==2 ? "" : "s"); 1563 1571 } 1572 +#ifdef LANG_RU 1573 + blob_appendf(&brief, "%h задача [%.10s].", 1574 +#elif LANG_EN 1564 1575 blob_appendf(&brief, "%h ticket [%.10s].", 1576 +#endif 1565 1577 zNewStatus, pManifest->zTicketUuid); 1566 1578 }else{ 1567 1579 zNewStatus = db_text("unknown", 1568 1580 "SELECT %s FROM ticket WHERE tkt_uuid='%s'", 1569 1581 zStatusColumn, pManifest->zTicketUuid 1570 1582 ); 1583 +#ifdef LANG_RU 1584 + blob_appendf(&comment, "Задача [%.10s] <i>%h</i> статус остался %h с " 1585 + "%d изменением", 1586 + pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField 1587 +#elif LANG_EN 1571 1588 blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with " 1572 1589 "%d other change%s", 1573 - pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField, 1574 - pManifest->nField==1 ? "" : "s" 1590 + pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField, 1591 + pManifest->nField==1 ? "" : "s" 1592 +#endif 1575 1593 ); 1576 1594 free(zNewStatus); 1595 +#ifdef LANG_RU 1596 + blob_appendf(&brief, "Задача [%.10s]: %d изменение", 1597 + pManifest->zTicketUuid, pManifest->nField 1598 +#elif LANG_EN 1577 1599 blob_appendf(&brief, "Ticket [%.10s]: %d change%s", 1578 1600 pManifest->zTicketUuid, pManifest->nField, 1579 1601 pManifest->nField==1 ? "" : "s" 1602 +#endif 1580 1603 ); 1581 1604 } 1582 1605 }else{ 1606 +#ifdef LANG_RU 1607 + blob_appendf(&comment, "Новая задача [%.10s] <i>%h</i>.", 1608 +#elif LANG_EN 1583 1609 blob_appendf(&comment, "New ticket [%.10s] <i>%h</i>.", 1610 +#endif 1584 1611 pManifest->zTicketUuid, zTitle 1585 1612 ); 1613 +#ifdef LANG_RU 1614 + blob_appendf(&brief, "Новая задача [%.10s].", pManifest->zTicketUuid); 1615 +#elif LANG_EN 1586 1616 blob_appendf(&brief, "New ticket [%.10s].", pManifest->zTicketUuid); 1617 +#endif 1587 1618 } 1588 1619 free(zTitle); 1589 1620 db_multi_exec( 1590 1621 "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)" 1591 1622 "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)", 1592 1623 tktTagId, pManifest->rDate, rid, pManifest->zUser, 1593 1624 blob_str(&comment), blob_str(&brief) ................................................................................ 1769 1800 " ORDER BY mtime DESC", 1770 1801 tagid, p->rDate 1771 1802 ); 1772 1803 if( prior ){ 1773 1804 content_deltify(prior, rid, 0); 1774 1805 } 1775 1806 if( nWiki>0 ){ 1807 +#ifdef LANG_RU 1808 + zComment = mprintf("Правка страницы [%h]", p->zWikiTitle); 1809 +#elif LANG_EN 1776 1810 zComment = mprintf("Changes to wiki page [%h]", p->zWikiTitle); 1811 +#endif 1777 1812 }else{ 1813 +#ifdef LANG_RU 1814 + zComment = mprintf("Удаление страницы [%h]", p->zWikiTitle); 1815 +#elif LANG_EN 1778 1816 zComment = mprintf("Deleted wiki page [%h]", p->zWikiTitle); 1817 +#endif 1779 1818 } 1780 1819 db_multi_exec( 1781 1820 "REPLACE INTO event(type,mtime,objid,user,comment," 1782 1821 " bgcolor,euser,ecomment)" 1783 1822 "VALUES('w',%.17g,%d,%Q,%Q," 1784 1823 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1)," 1785 1824 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," ................................................................................ 1867 1906 ); 1868 1907 if( strlen(p->zAttachTarget)!=UUID_SIZE 1869 1908 || !validate16(p->zAttachTarget, UUID_SIZE) 1870 1909 ){ 1871 1910 char *zComment; 1872 1911 if( p->zAttachSrc && p->zAttachSrc[0] ){ 1873 1912 zComment = mprintf( 1913 +#ifdef LANG_RU 1914 + "Добавить вложение [%R/artifact/%S|%h] к вики-странице [%h]", 1915 +#elif LANG_EN 1874 1916 "Add attachment [%R/artifact/%S|%h] to wiki page [%h]", 1917 +#endif 1875 1918 p->zAttachSrc, p->zAttachName, p->zAttachTarget); 1876 1919 }else{ 1877 - zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]", 1920 + zComment = mprintf( 1921 +#ifdef LANG_RU 1922 + "Удален файл \"%h\" из страницы[%h]", 1923 +#elif LANG_EN 1924 + "Delete attachment \"%h\" from wiki page [%h]", 1925 +#endif 1878 1926 p->zAttachName, p->zAttachTarget); 1879 1927 } 1880 1928 db_multi_exec( 1881 1929 "REPLACE INTO event(type,mtime,objid,user,comment)" 1882 1930 "VALUES('w',%.17g,%d,%Q,%Q)", 1883 1931 p->rDate, rid, p->zUser, zComment 1884 1932 ); 1885 1933 free(zComment); 1886 1934 }else{ 1887 1935 char *zComment; 1888 1936 if( p->zAttachSrc && p->zAttachSrc[0] ){ 1889 1937 zComment = mprintf( 1938 +#ifdef LANG_RU 1939 + "Добавить вложение [%R/artifact/%S|%h] к задаче [%S]", 1940 +#elif LANG_EN 1890 1941 "Add attachment [%R/artifact/%S|%h] to ticket [%S]", 1942 +#endif 1891 1943 p->zAttachSrc, p->zAttachName, p->zAttachTarget); 1892 1944 }else{ 1893 - zComment = mprintf("Delete attachment \"%h\" from ticket [%.10s]", 1945 + zComment = mprintf( 1946 +#ifdef LANG_RU 1947 + "Удален файл \"%h\" из задачи [%.10s]", 1948 +#elif LANG_EN 1949 + "Delete attachment \"%h\" from ticket [%.10s]", 1950 +#endif 1894 1951 p->zAttachName, p->zAttachTarget); 1895 1952 } 1896 1953 db_multi_exec( 1897 1954 "REPLACE INTO event(type,mtime,objid,user,comment)" 1898 1955 "VALUES('t',%.17g,%d,%Q,%Q)", 1899 1956 p->rDate, rid, p->zUser, zComment 1900 1957 );
Changes to src/report.c.
33 33 Blob ril; /* Report Item List */ 34 34 Stmt q; 35 35 int rn = 0; 36 36 int cnt = 0; 37 37 38 38 login_check_credentials(); 39 39 if( !g.perm.RdTkt && !g.perm.NewTkt ){ login_needed(); return; } 40 - style_header("Ticket Main Menu"); 40 + style_header( 41 +#ifdef LANG_RU 42 + "Задачи: основное меню" 43 +#elif LANG_EN 44 + "Ticket Main Menu" 45 +#endif 46 + ); 41 47 if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST<br />\n", -1); 42 48 zScript = ticket_reportlist_code(); 43 49 if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST_SCRIPT<br />\n", -1); 44 50 45 51 blob_zero(&ril); 46 52 ticket_init(); 47 53 ................................................................................ 994 1000 char *zTitle; 995 1001 char *zOwner; 996 1002 char *zClrKey; 997 1003 int tabs; 998 1004 Stmt q; 999 1005 char *zErr1 = 0; 1000 1006 char *zErr2 = 0; 1007 + Blob bSql = empty_blob; 1001 1008 1002 1009 login_check_credentials(); 1003 1010 if( !g.perm.RdTkt ){ login_needed(); return; } 1004 1011 rn = atoi(PD("rn","0")); 1005 1012 if( rn==0 ){ 1006 1013 cgi_redirect("reportlist"); 1007 1014 return; ................................................................................ 1015 1022 return; 1016 1023 } 1017 1024 zTitle = db_column_malloc(&q, 0); 1018 1025 zSql = db_column_malloc(&q, 1); 1019 1026 zOwner = db_column_malloc(&q, 2); 1020 1027 zClrKey = db_column_malloc(&q, 3); 1021 1028 db_finalize(&q); 1029 + 1030 + 1022 1031 1023 1032 if( P("order_by") ){ 1024 1033 /* 1025 1034 ** If the user wants to do a column sort, wrap the query into a sub 1026 1035 ** query and then sort the results. This is a whole lot easier than 1027 1036 ** trying to insert an ORDER BY into the query itself, especially 1028 1037 ** if the query is already ordered. ................................................................................ 1030 1039 int nField = atoi(P("order_by")); 1031 1040 if( nField > 0 ){ 1032 1041 const char* zDir = PD("order_dir",""); 1033 1042 zDir = !strcmp("ASC",zDir) ? "ASC" : "DESC"; 1034 1043 zSql = mprintf("SELECT * FROM (%s) ORDER BY %d %s", zSql, nField, zDir); 1035 1044 } 1036 1045 } 1046 + Th_FossilInit(0, 0); 1047 + Th_Store("login", g.zLogin); 1048 + Th_Store("date", db_text(0, "SELECT datetime('now')")); 1049 + Th_RenderToBlob(zSql, &bSql); 1050 + zSql = bSql.aData; 1037 1051 1038 1052 count = 0; 1039 1053 if( !tabs ){ 1040 1054 struct GenerateHTML sState; 1041 1055 1042 1056 db_multi_exec("PRAGMA empty_result_callbacks=ON"); 1043 - style_submenu_element("Raw", "Raw", 1057 + style_submenu_element( 1058 +#ifdef LANG_RU 1059 + "Текстом", "Текстом", 1060 +#elif LANG_EN 1061 + "Raw", "Raw", 1062 +#endif 1044 1063 "rptview?tablist=1&%h", PD("QUERY_STRING","")); 1045 1064 if( g.perm.Admin 1046 1065 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ 1047 - style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn); 1066 + style_submenu_element( 1067 +#ifdef LANG_RU 1068 + "Изменить", "Изменить", 1069 +#elif LANG_EN 1070 + "Edit", "Edit", 1071 +#endif 1072 + "rptedit?rn=%d", rn); 1048 1073 } 1049 1074 if( g.perm.TktFmt ){ 1050 1075 style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn); 1051 1076 } 1052 1077 if( g.perm.NewTkt ){ 1053 - style_submenu_element("New Ticket", "Create a new ticket", 1078 + style_submenu_element( 1079 +#ifdef LANG_RU 1080 + "Новая задача", "Создать новую задачу", 1081 +#elif LANG_EN 1082 + "New Ticket", "Create a new ticket", 1083 +#endif 1054 1084 "%s/tktnew", g.zTop); 1055 1085 } 1056 1086 style_header(zTitle); 1057 1087 output_color_key(zClrKey, 1, 1058 1088 "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\""); 1059 1089 @ <table border="1" cellpadding="2" cellspacing="0" class="report" 1060 1090 @ id="reportTable">
Changes to src/sqlite3.c.
14081 14081 14082 14082 if( zDate[0]=='-' ){ 14083 14083 zDate++; 14084 14084 neg = 1; 14085 14085 }else{ 14086 14086 neg = 0; 14087 14087 } 14088 - if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){ 14089 - return 1; 14088 + if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 && 14089 + getDigits(zDate,2,1,31,'.',&D,2,1,12,'.',&M,4,0,9999,0,&Y)!=3 ){ 14090 + return 1; 14090 14091 } 14091 14092 zDate += 10; 14092 14093 while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; } 14093 14094 if( parseHhMmSs(zDate, p)==0 ){ 14094 14095 /* We got the time */ 14095 14096 }else if( *zDate==0 ){ 14096 14097 p->validHMS = 0; ................................................................................ 14629 14630 int argc, 14630 14631 sqlite3_value **argv 14631 14632 ){ 14632 14633 DateTime x; 14633 14634 if( isDate(context, argc, argv, &x)==0 ){ 14634 14635 char zBuf[100]; 14635 14636 computeYMD_HMS(&x); 14636 - sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", 14637 - x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); 14637 + sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d.%02d.%04d %02d:%02d:%02d", 14638 + x.D, x.M, x.Y, x.h, x.m, (int)(x.s)); 14638 14639 sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); 14639 14640 } 14640 14641 } 14641 14642 14642 14643 /* 14643 14644 ** time( TIMESTRING, MOD, MOD, ...) 14644 14645 **
Changes to src/th_main.c.
100 100 default: { 101 101 sqlite3_snprintf(sizeof(zRc),zRc,"return code %d",rc); 102 102 } 103 103 } 104 104 return zRc; 105 105 } 106 106 107 +static Blob* pOutBlob = NULL; 108 + 107 109 /* 108 110 ** Send text to the appropriate output: Either to the console 109 111 ** or to the CGI reply buffer. Escape all characters with special 110 112 ** meaning to HTML if the encode parameter is true. 111 113 */ 112 114 static void sendText(const char *z, int n, int encode){ 113 115 if( enableOutput && n ){ 114 116 if( n<0 ) n = strlen(z); 115 117 if( encode ){ 116 118 z = htmlize(z, n); 117 119 n = strlen(z); 118 120 } 119 - if( g.cgiOutput ){ 121 + if(pOutBlob) 122 + blob_append(pOutBlob, z, n); 123 + else if( g.cgiOutput ){ 120 124 cgi_append_content(z, n); 121 125 }else{ 122 126 fwrite(z, 1, n, stdout); 123 127 fflush(stdout); 124 128 } 125 129 if( encode ) free((char*)z); 126 130 } ................................................................................ 916 920 zResult = (char*)Th_GetResult(g.interp, &n); 917 921 sendError(zResult, n, 1); 918 922 }else{ 919 923 sendText(z, i, 0); 920 924 } 921 925 return rc; 922 926 } 927 + 928 +int Th_RenderToBlob(const char *z, Blob *pBlob){ 929 + int result; 930 + pOutBlob = pBlob; 931 + result = Th_Render(z); 932 + pOutBlob = NULL; 933 + return result; 934 +} 923 935 924 936 /* 925 937 ** COMMAND: test-th-render 926 938 */ 927 939 void test_th_render(void){ 928 940 Blob in; 929 941 if( g.argc<3 ){
Changes to src/timeline.c.
818 818 */ 819 819 const char *timeline_query_for_www(void){ 820 820 static char *zBase = 0; 821 821 static const char zBaseSql[] = 822 822 @ SELECT 823 823 @ blob.rid AS blobRid, 824 824 @ uuid AS uuid, 825 - @ datetime(event.mtime,'localtime') AS timestamp, 825 + @ datetime(event.mtime, 'localtime') AS timestamp, 826 826 @ coalesce(ecomment, comment) AS comment, 827 827 @ coalesce(euser, user) AS user, 828 828 @ blob.rid IN leaf AS leaf, 829 829 @ bgcolor AS bgColor, 830 830 @ event.type AS eventType, 831 831 @ (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref 832 832 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid ................................................................................ 919 919 zUuid 920 920 ); 921 921 blob_zero(&out); 922 922 while( db_step(&q)==SQLITE_ROW ){ 923 923 const char *zFN = db_column_text(&q, 0); 924 924 blob_appendf(&out, "%s%z%h</a>", zSep, 925 925 href("%R/finfo?name=%t", zFN), zFN); 926 +#ifdef LANG_RU 927 + zSep = " или "; 928 +#elif LANG_EN 926 929 zSep = " or "; 930 +#endif 927 931 } 928 932 db_finalize(&q); 929 933 return blob_str(&out); 930 934 } 931 935 936 +#ifdef LANG_RU 937 +const char* numberSuffix(int number, const char* s1, const char* s24, const char* s590){ 938 + int lastDigit = number % 10; 939 + if(lastDigit == 1 && number != 11) 940 + return s1; 941 + if(lastDigit >= 2 && lastDigit <= 4 && (number < 12 || number > 14)) 942 + return s24; 943 + return s590; 944 +} 945 +#elif LANG_EN 946 +#define numberSuffix(n) (n==1?"":"s") 947 +#endif 932 948 933 949 /* 934 950 ** WEBPAGE: timeline 935 951 ** 936 952 ** Query parameters: 937 953 ** 938 954 ** a=TIMEORTAG after this event ................................................................................ 1043 1059 compute_uses_file("usesfile", ufid, 0); 1044 1060 zType = "ci"; 1045 1061 }else{ 1046 1062 zUses = 0; 1047 1063 } 1048 1064 } 1049 1065 1050 - style_header("Timeline"); 1066 + style_header( 1067 +#ifdef LANG_RU 1068 + "События" 1069 +#elif LANG_EN 1070 + "Timeline" 1071 +#endif 1072 + ); 1051 1073 login_anonymous_available(); 1052 1074 timeline_temp_table(); 1053 1075 blob_zero(&sql); 1054 1076 blob_zero(&desc); 1055 1077 blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1); 1056 1078 blob_append(&sql, timeline_query_for_www(), -1); 1057 1079 if( P("fc")!=0 || P("detail")!=0 ){ ................................................................................ 1080 1102 blob_append(&sql, " AND event.objid IN (0", -1); 1081 1103 while( p ){ 1082 1104 blob_appendf(&sql, ",%d", p->rid); 1083 1105 p = p->u.pTo; 1084 1106 } 1085 1107 blob_append(&sql, ")", -1); 1086 1108 path_reset(); 1087 - blob_append(&desc, "All nodes on the path from ", -1); 1109 + blob_append(&desc, 1110 +#ifdef LANG_RU 1111 + "Все узлы с путём от ", 1112 +#elif LANG_EN 1113 + "All nodes on the path from ", 1114 +#endif 1115 + -1); 1088 1116 blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom); 1089 - blob_append(&desc, " and ", -1); 1117 + blob_append(&desc, 1118 +#ifdef LANG_RU 1119 + " до " 1120 +#elif LANG_EN 1121 + " and " 1122 +#endif 1123 + , -1); 1090 1124 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo); 1091 1125 tmFlags |= TIMELINE_DISJOINT; 1092 1126 db_multi_exec("%s", blob_str(&sql)); 1093 1127 }else if( (p_rid || d_rid) && g.perm.Read ){ 1094 1128 /* If p= or d= is present, ignore all other parameters other than n= */ 1095 1129 char *zUuid; 1096 1130 int np, nd; ................................................................................ 1106 1140 p_rid ? p_rid : d_rid); 1107 1141 blob_appendf(&sql, " AND event.objid IN ok"); 1108 1142 nd = 0; 1109 1143 if( d_rid ){ 1110 1144 compute_descendants(d_rid, nEntry+1); 1111 1145 nd = db_int(0, "SELECT count(*)-1 FROM ok"); 1112 1146 if( nd>=0 ) db_multi_exec("%s", blob_str(&sql)); 1113 - if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); 1147 + if( nd>0 ) 1148 + blob_appendf(&desc, 1149 +#ifdef LANG_RU 1150 + "%d потом%s", nd, numberSuffix(nd, "ок", "ка", "ков")); 1151 +#elif LANG_EN 1152 + "%d descendant%s", nd, numberSuffix(nd)); 1153 +#endif 1114 1154 if( useDividers ) timeline_add_dividers(0, d_rid); 1115 1155 db_multi_exec("DELETE FROM ok"); 1116 1156 } 1117 1157 if( p_rid ){ 1118 1158 compute_ancestors(p_rid, nEntry+1, 0); 1119 1159 np = db_int(0, "SELECT count(*)-1 FROM ok"); 1120 1160 if( np>0 ){ 1121 - if( nd>0 ) blob_appendf(&desc, " and "); 1122 - blob_appendf(&desc, "%d ancestors", np); 1161 + if( nd>0 ) blob_appendf(&desc, 1162 +#ifdef LANG_RU 1163 + " и " 1164 +#elif LANG_EN 1165 + " and " 1166 +#endif 1167 + ); 1168 + blob_appendf(&desc, 1169 +#ifdef LANG_RU 1170 + "%d пред%s", np, numberSuffix(np, "ок", "ка", "ков")); 1171 +#elif LANG_EN 1172 + "%d ancestor%s", numberSuffix(np)); 1173 +#endif 1123 1174 db_multi_exec("%s", blob_str(&sql)); 1124 1175 } 1125 1176 if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid); 1126 1177 } 1127 - blob_appendf(&desc, " of %z[%.10s]</a>", 1128 - href("%R/info/%s", zUuid), zUuid); 1178 + blob_appendf(&desc, 1179 +#ifdef LANG_RU 1180 + " %z[%.10s]</a>", 1181 +#elif LANG_EN 1182 + " of %z[%.10s]</a>", 1183 +#endif 1184 + href("%R/info/%s", zUuid), zUuid); 1129 1185 }else if( f_rid && g.perm.Read ){ 1130 1186 /* If f= is present, ignore all other parameters other than n= */ 1131 1187 char *zUuid; 1132 1188 db_multi_exec( 1133 1189 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" 1134 1190 "INSERT INTO ok VALUES(%d);" 1135 1191 "INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;" 1136 1192 "INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;", 1137 1193 f_rid, f_rid, f_rid 1138 1194 ); 1139 1195 blob_appendf(&sql, " AND event.objid IN ok"); 1140 1196 db_multi_exec("%s", blob_str(&sql)); 1141 1197 if( useDividers ) timeline_add_dividers(0, f_rid); 1142 - blob_appendf(&desc, "Parents and children of check-in "); 1198 + blob_appendf(&desc, 1199 +#ifdef LANG_RU 1200 + "Предки и потомки фиксации " 1201 +#elif LANG_EN 1202 + "Parents and children of check-in " 1203 +#endif 1204 + ); 1143 1205 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); 1144 1206 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid); 1145 1207 tmFlags |= TIMELINE_DISJOINT; 1146 1208 }else{ 1147 1209 /* Otherwise, a timeline based on a span of time */ 1148 1210 int n; 1149 - const char *zEType = "timeline item"; 1211 + const char *zEType = 1212 +#ifdef LANG_RU 1213 + "событие"; 1214 +#elif LANG_EN 1215 + "timeline item"; 1216 +#endif 1150 1217 char *zDate; 1151 1218 char *zNEntry = mprintf("%d", nEntry); 1152 1219 url_add_parameter(&url, "n", zNEntry); 1153 1220 if( zUses ){ 1154 1221 blob_appendf(&sql, " AND event.objid IN usesfile "); 1155 1222 } 1156 1223 if( tagid>0 ){ ................................................................................ 1279 1346 }else{ 1280 1347 blob_appendf(&sql, " ORDER BY event.mtime DESC"); 1281 1348 } 1282 1349 blob_appendf(&sql, " LIMIT %d", nEntry); 1283 1350 db_multi_exec("%s", blob_str(&sql)); 1284 1351 1285 1352 n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/"); 1286 - if( zAfter==0 && zBefore==0 && zCirca==0 ){ 1287 - blob_appendf(&desc, "%d most recent %ss", n, zEType); 1288 - }else{ 1289 - blob_appendf(&desc, "%d %ss", n, zEType); 1353 + { 1354 +#ifdef LANG_RU 1355 + const char* rZEtype; 1356 + const char* rSuffix; 1357 + const char* rLastTitleSuffix = numberSuffix(n, "яя", "ие", "их"); 1358 + switch(zEType[0]){ 1359 + case 'c': /*check-in*/ 1360 + rZEtype = "фиксаци"; 1361 + rSuffix = numberSuffix(n, "я", "и", "й"); 1362 + break; 1363 + case 'w': /*wiki-edit*/ 1364 + rZEtype = "вики-прав"; 1365 + rSuffix = numberSuffix(n, "ка", "ки", "ок"); 1366 + break; 1367 + case 't': /*tiket-change*/ 1368 + rZEtype = "задач"; 1369 + rSuffix = numberSuffix(n, "а", "и", ""); 1370 + break; 1371 + case 'e': /*events*/ 1372 + rZEtype = "новост"; 1373 + rSuffix = numberSuffix(n, "ь", "и", "ей"); 1374 + break; 1375 + default: 1376 + rZEtype = "событи"; 1377 + rSuffix = numberSuffix(n, "е", "я", "й"); 1378 + rLastTitleSuffix = numberSuffix(n, "ее", "их", "их"); 1379 + } 1380 +#endif 1381 + if( zAfter==0 && zBefore==0 && zCirca==0 ){ 1382 + #ifdef LANG_RU 1383 + blob_appendf(&desc, "%d последн%s %s%s", n, rLastTitleSuffix, rZEtype, rSuffix); 1384 +#elif LANG_EN 1385 + blob_appendf(&desc, "%d most recent %ss", n, zEType); 1386 +#endif 1387 + }else{ 1388 +#ifdef LANG_RU 1389 + blob_appendf(&desc, "%d %s%s", n, rZEtype, rSuffix); 1390 +#elif LANG_EN 1391 + blob_appendf(&desc, "%d %ss", n, zEType); 1392 +#endif 1393 + } 1290 1394 } 1291 1395 if( zUses ){ 1292 1396 char *zFilenames = names_of_file(zUses); 1293 1397 blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames, 1294 1398 href("%R/artifact/%S",zUses), zUses); 1295 1399 tmFlags |= TIMELINE_DISJOINT; 1296 1400 } 1297 1401 if( zUser ){ 1402 +#ifdef LANG_RU 1403 + blob_appendf(&desc, " пользователя %h", zUser); 1404 +#elif LANG_EN 1298 1405 blob_appendf(&desc, " by user %h", zUser); 1406 +#endif 1299 1407 tmFlags |= TIMELINE_DISJOINT; 1300 1408 } 1301 1409 if( zTagName ){ 1410 +#ifdef LANG_RU 1411 + blob_appendf(&desc, " с тэгом \"%h\"", zTagName); 1412 +#elif LANG_EN 1302 1413 blob_appendf(&desc, " tagged with \"%h\"", zTagName); 1414 +#endif 1303 1415 tmFlags |= TIMELINE_DISJOINT; 1304 1416 }else if( zBrName ){ 1417 +#ifdef LANG_RU 1418 + blob_appendf(&desc, " ветки \"%h\"", zBrName); 1419 +#elif LANG_EN 1305 1420 blob_appendf(&desc, " related to \"%h\"", zBrName); 1421 +#endif 1306 1422 tmFlags |= TIMELINE_DISJOINT; 1307 1423 } 1308 1424 if( rAfter>0.0 ){ 1309 1425 if( rBefore>0.0 ){ 1310 - blob_appendf(&desc, " occurring between %h and %h.<br>", 1311 - zAfter, zBefore); 1426 + blob_appendf(&desc, 1427 +#ifdef LANG_RU 1428 + " между %h and %h.<br>" 1429 +#elif LANG_EN 1430 + " occurring between %h and %h.<br>" 1431 +#endif 1432 + , zAfter, zBefore); 1312 1433 }else{ 1313 - blob_appendf(&desc, " occurring on or after %h.<br />", zAfter); 1434 + blob_appendf(&desc, 1435 +#ifdef LANG_RU 1436 + " после %h.<br />" 1437 +#elif LANG_EN 1438 + " occurring on or after %h.<br />" 1439 +#endif 1440 + , zAfter); 1314 1441 } 1315 1442 }else if( rBefore>0.0 ){ 1443 +#ifdef LANG_RU 1444 + blob_appendf(&desc, " до %h.<br />", zBefore); 1445 +#elif LANG_EN 1316 1446 blob_appendf(&desc, " occurring on or before %h.<br />", zBefore); 1447 +#endif 1317 1448 }else if( rCirca>0.0 ){ 1449 +#ifdef LANG_RU 1450 + blob_appendf(&desc, " около %h.<br />", zCirca); 1451 +#elif LANG_EN 1318 1452 blob_appendf(&desc, " occurring around %h.<br />", zCirca); 1453 +#endif 1319 1454 } 1320 1455 if( zSearch ){ 1456 +#ifdef LANG_RU 1457 + blob_appendf(&desc, " похожие на \"%h\"", zSearch); 1458 +#elif LANG_EN 1321 1459 blob_appendf(&desc, " matching \"%h\"", zSearch); 1460 +#endif 1322 1461 } 1323 1462 if( g.perm.Hyperlink ){ 1324 1463 if( zAfter || n==nEntry ){ 1325 1464 zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); 1465 +#ifdef LANG_RU 1466 + timeline_submenu(&url, "Ранее", "b", zDate, "a"); 1467 +#elif LANG_EN 1326 1468 timeline_submenu(&url, "Older", "b", zDate, "a"); 1469 +#endif 1327 1470 free(zDate); 1328 1471 } 1329 1472 if( zBefore || (zAfter && n==nEntry) ){ 1330 1473 zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); 1474 +#ifdef LANG_RU 1475 + timeline_submenu(&url, "Новее", "a", zDate, "b"); 1476 +#elif LANG_EN 1331 1477 timeline_submenu(&url, "Newer", "a", zDate, "b"); 1478 +#endif 1332 1479 free(zDate); 1333 1480 }else if( tagid==0 ){ 1334 1481 if( zType[0]!='a' ){ 1482 +#ifdef LANG_RU 1483 + timeline_submenu(&url, "Все типы", "y", "all", 0); 1484 +#elif LANG_EN 1335 1485 timeline_submenu(&url, "All Types", "y", "all", 0); 1486 +#endif 1336 1487 } 1337 1488 if( zType[0]!='w' && g.perm.RdWiki ){ 1489 +#ifdef LANG_RU 1490 + timeline_submenu(&url, "Только вики-правки", "y", "w", 0); 1491 +#elif LANG_EN 1338 1492 timeline_submenu(&url, "Wiki Only", "y", "w", 0); 1493 +#endif 1339 1494 } 1340 1495 if( zType[0]!='c' && g.perm.Read ){ 1496 +#ifdef LANG_RU 1497 + timeline_submenu(&url, "Только фиксации", "y", "ci", 0); 1498 +#elif LANG_EN 1341 1499 timeline_submenu(&url, "Checkins Only", "y", "ci", 0); 1500 +#endif 1342 1501 } 1343 1502 if( zType[0]!='t' && g.perm.RdTkt ){ 1503 +#ifdef LANG_RU 1504 + timeline_submenu(&url, "Только задачи", "y", "t", 0); 1505 +#elif LANG_EN 1344 1506 timeline_submenu(&url, "Tickets Only", "y", "t", 0); 1507 +#endif 1345 1508 } 1346 1509 if( zType[0]!='e' && g.perm.RdWiki ){ 1510 +#ifdef LANG_RU 1511 + timeline_submenu(&url, "Только новости", "y", "e", 0); 1512 +#elif LANG_EN 1347 1513 timeline_submenu(&url, "Events Only", "y", "e", 0); 1514 +#endif 1348 1515 } 1349 1516 if( zType[0]!='g' && g.perm.Read ){ 1350 1517 timeline_submenu(&url, "Tags Only", "y", "g", 0); 1351 1518 } 1352 1519 } 1353 1520 if( nEntry>20 ){ 1521 +#ifdef LANG_RU 1522 + timeline_submenu(&url, "20 событий", "n", "20", 0); 1523 +#elif LANG_EN 1354 1524 timeline_submenu(&url, "20 Entries", "n", "20", 0); 1525 +#endif 1355 1526 } 1356 1527 if( nEntry<200 ){ 1528 +#ifdef LANG_RU 1529 + timeline_submenu(&url, "200 событий", "n", "200", 0); 1530 +#elif LANG_EN 1357 1531 timeline_submenu(&url, "200 Entries", "n", "200", 0); 1532 +#endif 1358 1533 } 1359 1534 if( zType[0]=='a' || zType[0]=='c' ){ 1360 1535 if( tmFlags & TIMELINE_FCHANGES ){ 1536 +#ifdef LANG_RU 1537 + timeline_submenu(&url, "Не показывать файлы", "fc", 0, 0); 1538 +#elif LANG_EN 1361 1539 timeline_submenu(&url, "Hide Files", "fc", 0, 0); 1540 +#endif 1362 1541 }else{ 1542 +#ifdef LANG_RU 1543 + timeline_submenu(&url, "Показывать файлы", "fc", "", 0); 1544 +#elif LANG_EN 1363 1545 timeline_submenu(&url, "Show Files", "fc", "", 0); 1546 +#endif 1364 1547 } 1365 1548 } 1366 1549 } 1367 1550 } 1368 1551 if( P("showsql") ){ 1369 1552 @ <blockquote>%h(blob_str(&sql))</blockquote> 1370 1553 }
Changes to src/tkt.c.
420 420 const char *zScript; 421 421 char *zFullName; 422 422 const char *zUuid = PD("name",""); 423 423 424 424 login_check_credentials(); 425 425 if( !g.perm.RdTkt ){ login_needed(); return; } 426 426 if( g.perm.WrTkt || g.perm.ApndTkt ){ 427 - style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", 427 + style_submenu_element( 428 +#ifdef LANG_RU 429 + "Правка", "Изменить задачу", 430 +#elif LANG_EN 431 + "Edit", "Edit The Ticket", 432 +#endif 433 + "%s/tktedit?name=%T", 428 434 g.zTop, PD("name","")); 429 435 } 430 436 if( g.perm.Hyperlink ){ 431 - style_submenu_element("History", "History Of This Ticket", 437 + style_submenu_element( 438 +#ifdef LANG_RU 439 + "История", "Исория задачи", 440 +#elif LANG_EN 441 + "History", "History Of This Ticket", 442 +#endif 432 443 "%s/tkthistory/%T", g.zTop, zUuid); 433 - style_submenu_element("Timeline", "Timeline Of This Ticket", 444 + style_submenu_element( 445 +#ifdef LANG_RU 446 + "События", "События по этой задаче", 447 +#elif LANG_EN 448 + "Timeline", "Timeline Of This Ticket", 449 +#endif 434 450 "%s/tkttimeline/%T", g.zTop, zUuid); 435 - style_submenu_element("Check-ins", "Check-ins Of This Ticket", 451 + style_submenu_element( 452 +#ifdef LANG_RU 453 + "Фиксации", "Фиксации по этой задаче", 454 +#elif LANG_EN 455 + "Check-ins", "Check-ins Of This Ticket", 456 +#endif 436 457 "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); 437 458 } 438 459 if( g.perm.NewTkt ){ 439 - style_submenu_element("New Ticket", "Create a new ticket", 460 + style_submenu_element( 461 +#ifdef LANG_RU 462 + "Новая задача", "Создать новую задачу", 463 +#elif LANG_EN 464 + "New Ticket", "Create a new ticket", 465 +#endif 440 466 "%s/tktnew", g.zTop); 441 467 } 442 468 if( g.perm.ApndTkt && g.perm.Attach ){ 443 - style_submenu_element("Attach", "Add An Attachment", 469 + style_submenu_element( 470 +#ifdef LANG_RU 471 + "Добавить файл", "Добавить файл к задаче", 472 +#elif LANG_EN 473 + "Attach", "Add An Attachment", 474 +#endif 444 475 "%s/attachadd?tkt=%T&from=%s/tktview/%t", 445 476 g.zTop, zUuid, g.zTop, zUuid); 446 477 } 447 478 if( P("plaintext") ){ 479 +#ifdef LANG_RU 480 + style_submenu_element("Форматировано", "Форматировано", "%R/tktview/%S", zUuid); 481 +#elif LANG_EN 448 482 style_submenu_element("Formatted", "Formatted", "%R/tktview/%S", zUuid); 483 +#endif 449 484 }else{ 485 +#ifdef LANG_RU 486 + style_submenu_element("Текстом", "Текстом", 487 +#elif LANG_EN 450 488 style_submenu_element("Plaintext", "Plaintext", 489 +#endif 451 490 "%R/tktview/%S?plaintext", zUuid); 452 491 } 453 - style_header("View Ticket"); 492 + style_header( 493 +#ifdef LANG_RU 494 + "Просмотр задачи" 495 +#elif LANG_EN 496 + "View Ticket" 497 +#endif 498 + ); 454 499 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 455 500 ticket_init(); 456 501 initializeVariablesFromCGI(); 457 502 getAllTicketFields(); 458 503 initializeVariablesFromDb(); 459 504 zScript = ticket_viewpage_code(); 460 505 if( P("showfields")!=0 ) showAllFields(); ................................................................................ 462 507 Th_Render(zScript); 463 508 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); 464 509 465 510 zFullName = db_text(0, 466 511 "SELECT tkt_uuid FROM ticket" 467 512 " WHERE tkt_uuid GLOB '%q*'", zUuid); 468 513 if( zFullName ){ 514 +#ifdef LANG_RU 515 + attachment_list(zFullName, "<hr /><h2>Вложения:</h2><ul>"); 516 +#elif LANG_EN 469 517 attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>"); 518 +#endif 470 519 } 471 520 472 521 style_footer(); 473 522 } 474 523 475 524 /* 476 525 ** TH command: append_field FIELD STRING ................................................................................ 558 607 const char *zUuid; 559 608 int i; 560 609 int nJ = 0; 561 610 Blob tktchng, cksum; 562 611 563 612 login_verify_csrf_secret(); 564 613 if( !captcha_is_correct() ){ 614 +#ifdef LANG_RU 615 + @ <p class="generalError">Ошибка: неверный код.</p> 616 +#elif LANG_EN 565 617 @ <p class="generalError">Error: Incorrect security code.</p> 618 +#endif 566 619 return TH_OK; 567 620 } 568 621 zUuid = (const char *)pUuid; 569 622 blob_zero(&tktchng); 570 623 zDate = date_in_standard_format("now"); 571 624 blob_appendf(&tktchng, "D %s\n", zDate); 572 625 free(zDate); ................................................................................ 579 632 } 580 633 for(i=0; i<nField; i++){ 581 634 const char *zValue; 582 635 int nValue; 583 636 if( aField[i].zAppend ) continue; 584 637 zValue = Th_Fetch(aField[i].zName, &nValue); 585 638 if( zValue ){ 639 + const char* zTemp = wiki_sanify(zValue); 640 + if(zTemp != zValue) 641 + { 642 + zValue = zTemp; 643 + nValue = strlen(zValue); 644 + } 586 645 while( nValue>0 && fossil_isspace(zValue[nValue-1]) ){ nValue--; } 587 646 if( ((aField[i].mUsed & USEDBY_TICKETCHNG)!=0 && nValue>0) 588 647 || memcmp(zValue, aField[i].zValue, nValue)!=0 589 648 || strlen(aField[i].zValue)!=nValue 590 649 ){ 591 650 if( memcmp(aField[i].zName, "private_", 8)==0 ){ 592 651 zValue = db_conceal(zValue, nValue); ................................................................................ 650 709 char *zNewUuid = 0; 651 710 652 711 login_check_credentials(); 653 712 if( !g.perm.NewTkt ){ login_needed(); return; } 654 713 if( P("cancel") ){ 655 714 cgi_redirect("home"); 656 715 } 657 - style_header("New Ticket"); 716 + style_header( 717 +#ifdef LANG_RU 718 + "Новая задача" 719 +#elif LANG_EN 720 + "New Ticket" 721 +#endif 722 + ); 658 723 if( g.thTrace ) Th_Trace("BEGIN_TKTNEW<br />\n", -1); 659 724 ticket_init(); 660 725 initializeVariablesFromCGI(); 661 726 getAllTicketFields(); 662 727 initializeVariablesFromDb(); 663 728 if( g.zPath[0]=='d' ) showAllFields(); 664 729 form_begin(0, "%R/%s", g.zPath); ................................................................................ 701 766 702 767 login_check_credentials(); 703 768 if( !g.perm.ApndTkt && !g.perm.WrTkt ){ login_needed(); return; } 704 769 zName = P("name"); 705 770 if( P("cancel") ){ 706 771 cgi_redirectf("tktview?name=%T", zName); 707 772 } 708 - style_header("Edit Ticket"); 773 + style_header( 774 +#ifdef LANG_RU 775 + "Изменение задачи" 776 +#elif LANG_EN 777 + "Edit Ticket" 778 +#endif 779 + ); 709 780 if( zName==0 || (nName = strlen(zName))<4 || nName>UUID_SIZE 710 781 || !validate16(zName,nName) ){ 711 - @ <span class="tktError">Not a valid ticket id: \"%h(zName)\"</span> 782 +#ifdef LANG_RU 783 + @ <span class="tktError">Неверный ID задачи: \"%h(zName)\"</span> 784 +#elif LANG_EN 785 + @ <span class="tktError">Not a valid ticket id: \"%h(zName)\"</span> 786 +#endif 712 787 style_footer(); 713 788 return; 714 789 } 715 790 nRec = db_int(0, "SELECT count(*) FROM ticket WHERE tkt_uuid GLOB '%q*'", 716 791 zName); 717 792 if( nRec==0 ){ 793 +#ifdef LANG_RU 794 + @ <span class="tktError">Не найдена задача: \"%h(zName)\"</span> 795 +#elif LANG_EN 718 796 @ <span class="tktError">No such ticket: \"%h(zName)\"</span> 797 +#endif 719 798 style_footer(); 720 799 return; 721 800 } 722 801 if( nRec>1 ){ 802 +#ifdef LANG_RU 803 + @ <span class="tktError">Несколько задач (%d(nRec)) начинаются с: 804 +#elif LANG_EN 723 805 @ <span class="tktError">%d(nRec) tickets begin with: 806 +#endif 724 807 @ \"%h(zName)\"</span> 725 808 style_footer(); 726 809 return; 727 810 } 728 811 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1); 729 812 ticket_init(); 730 813 getAllTicketFields(); ................................................................................ 801 884 const char *zType; 802 885 803 886 login_check_credentials(); 804 887 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; } 805 888 zUuid = PD("name",""); 806 889 zType = PD("y","a"); 807 890 if( zType[0]!='c' ){ 808 - style_submenu_element("Check-ins", "Check-ins", 891 + style_submenu_element( 892 +#ifdef LANG_RU 893 + "Фиксации", "Фиксации", 894 +#elif LANG_EN 895 + "Check-ins", "Check-ins", 896 +#endif 809 897 "%s/tkttimeline?name=%T&y=ci", g.zTop, zUuid); 810 898 }else{ 811 - style_submenu_element("Timeline", "Timeline", 899 + style_submenu_element( 900 +#ifdef LANG_RU 901 + "События", "События", 902 +#elif LANG_EN 903 + "Timeline", "Timeline", 904 +#endif 812 905 "%s/tkttimeline?name=%T", g.zTop, zUuid); 813 906 } 814 - style_submenu_element("History", "History", 907 + style_submenu_element( 908 +#ifdef LANG_RU 909 + "История", "История", 910 +#elif LANG_EN 911 + "History", "History", 912 +#endif 815 913 "%s/tkthistory/%s", g.zTop, zUuid); 816 - style_submenu_element("Status", "Status", 914 + style_submenu_element( 915 +#ifdef LANG_RU 916 + "Статус", "Статус", 917 +#elif LANG_EN 918 + "Status", "Status", 919 +#endif 817 920 "%s/info/%s", g.zTop, zUuid); 818 921 if( zType[0]=='c' ){ 819 - zTitle = mprintf("Check-Ins Associated With Ticket %h", zUuid); 922 + zTitle = mprintf( 923 +#ifdef LANG_RU 924 + "Фиксации, связанные с задачей %h", 925 +#elif LANG_EN 926 + "Check-Ins Associated With Ticket %h", 927 +#endif 928 + zUuid); 820 929 }else{ 821 - zTitle = mprintf("Timeline Of Ticket %h", zUuid); 930 + zTitle = mprintf( 931 +#ifdef LANG_RU 932 + "События, связанные с задачей %h", 933 +#elif LANG_EN 934 + "Timeline Of Ticket %h", 935 +#endif 936 + zUuid); 822 937 } 823 938 style_header(zTitle); 824 939 free(zTitle); 825 940 826 941 sqlite3_snprintf(6, zGlobPattern, "%s", zUuid); 827 942 canonical16(zGlobPattern, strlen(zGlobPattern)); 828 943 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); 829 944 if( tagid==0 ){ 945 +#ifdef LANG_RU 946 + @ Задача %h(zUuid) не найдена. 947 +#elif LANG_EN 830 948 @ No such ticket: %h(zUuid) 949 +#endif 831 950 style_footer(); 832 951 return; 833 952 } 834 953 zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d", 835 954 tagid); 836 955 if( zType[0]=='c' ){ 837 956 zSQL = mprintf( ................................................................................ 874 993 const char *zUuid; 875 994 int tagid; 876 995 int nChng = 0; 877 996 878 997 login_check_credentials(); 879 998 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; } 880 999 zUuid = PD("name",""); 881 - zTitle = mprintf("History Of Ticket %h", zUuid); 882 - style_submenu_element("Status", "Status", 1000 + zTitle = mprintf( 1001 +#ifdef LANG_RU 1002 + "История задачи %h", 1003 +#elif LANG_EN 1004 + "History Of Ticket %h", 1005 +#endif 1006 + zUuid); 1007 + style_submenu_element( 1008 +#ifdef LANG_RU 1009 + "Статус", "Статус", 1010 +#elif LANG_EN 1011 + "Status", "Status", 1012 +#endif 883 1013 "%s/info/%s", g.zTop, zUuid); 884 - style_submenu_element("Check-ins", "Check-ins", 1014 +#ifdef LANG_RU 1015 + style_submenu_element("Фиксации", "Фиксации", 1016 +#elif LANG_EN 1017 + style_submenu_element("Check-ins", "Check-ins", 1018 +#endif 885 1019 "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid); 886 - style_submenu_element("Timeline", "Timeline", 1020 +#ifdef LANG_RU 1021 + style_submenu_element("События", "События", 1022 +#elif LANG_EN 1023 + style_submenu_element("Timeline", "Timeline", 1024 +#endif 887 1025 "%s/tkttimeline?name=%s", g.zTop, zUuid); 888 1026 if( P("plaintext")!=0 ){ 889 1027 style_submenu_element("Formatted", "Formatted", 890 1028 "%R/tkthistory/%S", zUuid); 891 1029 }else{ 892 1030 style_submenu_element("Plaintext", "Plaintext", 893 1031 "%R/tkthistory/%S?plaintext", zUuid); 894 1032 } 895 1033 style_header(zTitle); 896 1034 free(zTitle); 897 1035 898 1036 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); 899 1037 if( tagid==0 ){ 1038 +#ifdef LANG_RU 1039 + @ Задача %h(zUuid) не найдена 1040 +#elif LANG_EN 900 1041 @ No such ticket: %h(zUuid) 1042 +#endif 901 1043 style_footer(); 902 1044 return; 903 1045 } 904 1046 db_prepare(&q, 905 1047 "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" 906 1048 " FROM event, blob" 907 1049 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" ................................................................................ 928 1070 } 929 1071 nChng++; 930 1072 if( zFile!=0 ){ 931 1073 const char *zSrc = db_column_text(&q, 3); 932 1074 const char *zUser = db_column_text(&q, 5); 933 1075 if( zSrc==0 || zSrc[0]==0 ){ 934 1076 @ 1077 +#ifdef LANG_RU 1078 + @ <li>Удалено вложение "%h(zFile)" 1079 +#elif LANG_EN 935 1080 @ <li><p>Delete attachment "%h(zFile)" 1081 +#endif 936 1082 }else{ 937 1083 @ 1084 +#ifdef LANG_RU 1085 + @ <li><p>Добавлено вложение 1086 +#elif LANG_EN 938 1087 @ <li><p>Add attachment 939 - @ "%z(href("%R/artifact/%S",zSrc))%h(zFile)</a>" 1088 +#endif 1089 + @ "%z(href("%R/artifact/%S",zSrc))%h(zFile)</a>" 940 1090 } 941 1091 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>] 1092 +#ifdef LANG_RU 1093 + @ (rid %d(rid)) пользователем 1094 + hyperlink_to_user(zUser,zDate," "); 1095 +#elif LANG_EN 942 1096 @ (rid %d(rid)) by 943 1097 hyperlink_to_user(zUser,zDate," on"); 1098 +#endif 944 1099 hyperlink_to_date(zDate, ".</p>"); 945 1100 }else{ 946 1101 pTicket = manifest_get(rid, CFTYPE_TICKET); 947 1102 if( pTicket ){ 948 1103 @ 1104 +#ifdef LANG_RU 1105 + @ <li>Задача изменена 1106 + @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>] 1107 + @ (rid %d(rid)) пользователем 1108 + hyperlink_to_user(pTicket->zUser,zDate," "); 1109 +#elif LANG_EN 949 1110 @ <li><p>Ticket change 950 1111 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>] 951 1112 @ (rid %d(rid)) by 952 1113 hyperlink_to_user(pTicket->zUser,zDate," on"); 1114 +#endif 953 1115 hyperlink_to_date(zDate, ":"); 954 1116 @ </p> 955 1117 ticket_output_change_artifact(pTicket, "a"); 956 1118 } 957 1119 manifest_destroy(pTicket); 958 1120 } 959 1121 }
Changes to src/url.c.
378 378 379 379 /* 380 380 ** Prompt the user for the password for g.urlUser. Store the result 381 381 ** in g.urlPasswd. 382 382 */ 383 383 void url_prompt_for_password(void){ 384 384 if( isatty(fileno(stdin)) ){ 385 - char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser); 385 + char *zPrompt = mprintf( 386 +#ifdef LANG_RU 387 + "\rПароль для %s: ", 388 +#elif LANG_EN 389 + "\rpassword for %s: ", 390 +#endif 391 + g.urlUser); 386 392 Blob x; 387 393 prompt_for_password(zPrompt, &x, 0); 388 394 free(zPrompt); 389 395 g.urlPasswd = mprintf("%b", &x); 390 396 blob_reset(&x); 391 397 }else{ 392 - fossil_fatal("missing or incorrect password for user \"%s\"", 398 + fossil_fatal( 399 +#ifdef LANG_RU 400 + "Отсутствует или неверен пароль для пользователя \"%s\"", 401 +#elif LANG_EN 402 + "missing or incorrect password for user \"%s\"", 403 +#endif 393 404 g.urlUser); 394 405 } 395 406 } 396 407 397 408 /* Preemptively prompt for a password if a username is given in the 398 409 ** URL but no password. 399 410 */
Changes to src/user.c.
47 47 #endif 48 48 /* 49 49 ** getpass for Windows 50 50 */ 51 51 static char *getpass(const char *prompt){ 52 52 static char pwd[64]; 53 53 size_t i; 54 - 55 - fputs(prompt,stderr); 54 + fossil_puts(prompt,1); 56 55 fflush(stderr); 57 56 for(i=0; i<sizeof(pwd)-1; ++i){ 58 57 pwd[i] = _getch(); 59 58 if(pwd[i]=='\r' || pwd[i]=='\n'){ 60 59 break; 61 60 } 62 61 /* BS or DEL */ ................................................................................ 113 112 Blob secondTry; 114 113 blob_zero(pPassphrase); 115 114 blob_zero(&secondTry); 116 115 while(1){ 117 116 prompt_for_passphrase(zPrompt, pPassphrase); 118 117 if( verify==0 ) break; 119 118 if( verify==1 && blob_size(pPassphrase)==0 ) break; 120 - prompt_for_passphrase("Retype new password: ", &secondTry); 119 + prompt_for_passphrase( 120 +#ifdef LANG_RU 121 + "��������� ����� ������: ", 122 +#elif LANG_EN 123 + "Retype new password: ", 124 +#endif 125 + &secondTry); 121 126 if( blob_compare(pPassphrase, &secondTry) ){ 122 - fossil_print("Passphrases do not match. Try again...\n"); 127 + fossil_print( 128 +#ifdef LANG_RU 129 + "������ �� ���������. ���������� ��� ���...\n" 130 +#elif LANG_EN 131 + "Passphrases do not match. Try again...\n" 132 +#endif 133 + ); 123 134 }else{ 124 135 break; 125 136 } 126 137 } 127 138 blob_reset(&secondTry); 128 139 } 129 140
Changes to src/wiki.c.
45 45 return 1; 46 46 } 47 47 48 48 /* 49 49 ** Output rules for well-formed wiki pages 50 50 */ 51 51 static void well_formed_wiki_name_rules(void){ 52 +#ifdef LANG_RU 53 + @ <ul> 54 + @ <li>Не должно начинаться или заканчиваться пробелом.</li> 55 + @ <li> Не должно содержать управляющих символов, включая табуляцию 56 + @ и перевод строки.</li> 57 + @ <li> Не должно быть двух и более пробелов подряд.</li> 58 + @ <li> Длина от 3 до 100 символов.</li> 59 + @ </ul> 60 +#elif LANG_EN 52 61 @ <ul> 53 62 @ <li> Must not begin or end with a space.</li> 54 63 @ <li> Must not contain any control characters, including tab or 55 64 @ newline.</li> 56 65 @ <li> Must not have two or more spaces in a row internally.</li> 57 66 @ <li> Must be between 3 and 100 characters in length.</li> 58 67 @ </ul> 68 +#endif 59 69 } 60 70 61 71 /* 62 72 ** Check a wiki name. If it is not well-formed, then issue an error 63 73 ** and return true. If it is well-formed, return false. 64 74 */ 65 75 static int check_name(const char *z){ 66 76 if( !wiki_name_is_wellformed((const unsigned char *)z) ){ 77 +#ifdef LANG_RU 78 + style_header("Ошибка в названии страницы"); 79 + @ "<span class="wikiError">%h(z)</span>" не может быть названием страницы. 80 + @ Правила для названий страниц: 81 +#elif LANG_EN 67 82 style_header("Wiki Page Name Error"); 68 83 @ The wiki name "<span class="wikiError">%h(z)</span>" is not well-formed. 69 84 @ Rules for wiki page names: 85 +#endif 70 86 well_formed_wiki_name_rules(); 71 87 style_footer(); 72 88 return 1; 73 89 } 74 90 return 0; 75 91 } 76 92 ................................................................................ 99 115 login_check_credentials(); 100 116 g.zExtra = zPageName; 101 117 cgi_set_parameter_nocopy("name", g.zExtra); 102 118 g.isHome = 1; 103 119 wiki_page(); 104 120 return; 105 121 } 122 +#ifdef LANG_RU 123 + style_header("Домашняя страница"); 124 + @ <p>Это фиктивная домашняя страница проекта. 125 + @ Для заполнения этой страницы сначала перейдите в 126 + @ <a href="%s(g.zTop)/setup_config">setup/config</a> 127 + @ и задайте имя проекта. Затем создайте страницу с 128 + @ таким же названием. Содержимое созданной страницы 129 + @ будет отображаться вместо этого сообщения.</p> 130 +#elif LANG_EN 106 131 style_header("Home"); 107 132 @ <p>This is a stub home-page for the project. 108 133 @ To fill in this page, first go to 109 134 @ %z(href("%R/setup_config"))setup/config</a> 110 135 @ and establish a "Project Name". Then create a 111 136 @ wiki page with that name. The content of that wiki page 112 137 @ will be displayed in place of this message.</p> 138 +#endif 113 139 style_footer(); 114 140 } 115 141 116 142 /* 117 143 ** Return true if the given pagename is the name of the sandbox 118 144 */ 119 145 static int is_sandbox(const char *zPagename){ ................................................................................ 129 155 char *zTag; 130 156 int rid = 0; 131 157 int isSandbox; 132 158 char *zUuid; 133 159 Blob wiki; 134 160 Manifest *pWiki = 0; 135 161 const char *zPageName; 162 +#ifdef LANG_RU 163 + char *zBody = mprintf("%s","<i>Пустая страница</i>"); 164 +#elif LANG_EN 136 165 char *zBody = mprintf("%s","<i>Empty Page</i>"); 137 - 166 +#endif 138 167 login_check_credentials(); 139 168 if( !g.perm.RdWiki ){ login_needed(); return; } 140 169 zPageName = P("name"); 141 170 if( zPageName==0 ){ 171 +#ifdef LANG_RU 172 + style_header("Вики"); 173 + @ <ul> 174 +#elif LANG_EN 142 175 style_header("Wiki"); 143 176 @ <ul> 177 +#endif 144 178 { char *zHomePageName = db_get("project-name",0); 145 179 if( zHomePageName ){ 146 180 @ <li> %z(href("%R/wiki?name=%t",zHomePageName)) 181 +#ifdef LANG_RU 182 + @ %h(zHomePageName)</a> - домашняя страница.</li> 183 +#elif LANG_EN 147 184 @ %h(zHomePageName)</a> wiki home page.</li> 185 +#endif 148 186 } 149 187 } 188 +#ifdef LANG_RU 189 + @ <li> %z(href("%R/timeline?y=w"))Последние правки</a></li> 190 + @ <li> %z(href("%R/wiki_rules"))Правила форматирования</a></li> 191 + @ <li> Используйте %z(href("%R/wiki?name=Sandbox"))песочницу</a> для экспериментов.</li> 192 +#elif LANG_EN 150 193 @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li> 151 194 @ <li> %z(href("%R/wiki_rules"))Formatting rules</a> for wiki.</li> 152 195 @ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a> 153 196 @ to experiment.</li> 197 +#endif 154 198 if( g.perm.NewWiki ){ 199 +#ifdef LANG_RU 200 + @ <li> Создать %z(href("%R/wikinew"))новую страницу</a>.</li> 201 +#elif LANG_EN 155 202 @ <li> Create a %z(href("%R/wikinew"))new wiki page</a>.</li> 203 +#endif 156 204 if( g.perm.Write ){ 205 +#ifdef LANG_RU 206 + @ <li> Создать %z(href("%R/eventedit"))новое событие</a>.</li> 207 +#elif LANG_EN 157 208 @ <li> Create a %z(href("%R/eventedit"))new event</a>.</li> 209 +#endif 158 210 } 159 211 } 212 +#ifdef LANG_RU 213 + @ <li> %z(href("%R/wcontent"))Все страницы</a> 214 + @ на сервере.</li> 215 + @ <li> <form method="get" action="%s(g.zTop)/wfind"><div> 216 + @ Поиск по названиям: <input type="text" name="title"/> 217 + @ <input type="submit" value = "Искать" /></div></form> 218 +#elif LANG_EN 160 219 @ <li> %z(href("%R/wcontent"))List of All Wiki Pages</a> 161 220 @ available on this server.</li> 162 221 if( g.perm.ModWiki ){ 163 222 @ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li> 164 223 } 165 224 @ <li> 166 225 form_begin(0, "%R/wfind"); 167 226 @ <div>Search wiki titles: <input type="text" name="title"/> 168 227 @ <input type="submit" /></div></form> 228 +#endif 169 229 @ </li> 170 230 @ </ul> 171 231 style_footer(); 172 232 return; 173 233 } 174 234 if( check_name(zPageName) ) return; 175 235 isSandbox = is_sandbox(zPageName); ................................................................................ 195 255 "%R/wdiff?name=%T&a=%d", zPageName, rid); 196 256 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); 197 257 style_submenu_element("Details", "Details", 198 258 "%R/info/%S", zUuid); 199 259 } 200 260 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){ 201 261 if( db_get_boolean("wysiwyg-wiki", 0) ){ 202 - style_submenu_element("Edit", "Edit Wiki Page", 203 - "%s/wikiedit?name=%T&wysiwyg=1", 262 + style_submenu_element( 263 +#ifdef LANG_RU 264 + "Правка", "Редактировать вики-страницу" 265 +#elif LANG_EN 266 + "Edit", "Edit Wiki Page" 267 +#endif 268 + , "%s/wikiedit?name=%T&wysiwyg=1", 204 269 g.zTop, zPageName); 205 270 }else{ 206 - style_submenu_element("Edit", "Edit Wiki Page", 207 - "%s/wikiedit?name=%T", 271 + style_submenu_element( 272 +#ifdef LANG_RU 273 + "Правка", "Редактировать вики-страницу" 274 +#elif LANG_EN 275 + "Edit", "Edit Wiki Page" 276 +#endif 277 + , "%s/wikiedit?name=%T", 208 278 g.zTop, zPageName); 209 279 } 210 280 } 211 281 if( rid && g.perm.ApndWiki && g.perm.Attach ){ 212 - style_submenu_element("Attach", "Add An Attachment", 282 + style_submenu_element( 283 +#ifdef LANG_RU 284 + "Добавить файл", "Добавить файл к странице", 285 +#elif LANG_EN 286 + "Attach", "Add An Attachment", 287 +#endif 213 288 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", 214 289 g.zTop, zPageName, g.zTop, zPageName); 215 290 } 216 291 if( rid && g.perm.ApndWiki ){ 217 - style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 292 + style_submenu_element( 293 +#ifdef LANG_RU 294 + "Комментировать", "Добавить комментарий к странице", 295 +#elif LANG_EN 296 + "Append", "Add A Comment", 297 +#endif 298 + "%s/wikiappend?name=%T", 218 299 g.zTop, zPageName); 219 300 } 220 301 if( g.perm.Hyperlink ){ 221 - style_submenu_element("History", "History", "%s/whistory?name=%T", 302 + style_submenu_element( 303 +#ifdef LANG_RU 304 + "История", "Показать историю правок", 305 +#elif LANG_EN 306 + "History", "History", 307 +#endif 308 + "%s/whistory?name=%T", 222 309 g.zTop, zPageName); 223 310 } 224 311 } 225 312 style_set_current_page("%s?name=%T", g.zPath, zPageName); 226 313 style_header(zPageName); 227 314 blob_init(&wiki, zBody, -1); 228 315 wiki_convert(&wiki, 0, 0); ................................................................................ 451 538 char *zDate; 452 539 const char *zUser; 453 540 const char *zRemark; 454 541 char *zId; 455 542 456 543 zDate = db_text(0, "SELECT datetime('now')"); 457 544 zId = db_text(0, "SELECT lower(hex(randomblob(8)))"); 458 - blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h", 545 + blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>%s %h", 459 546 zId, zDate, g.zLogin); 460 547 free(zDate); 461 548 zUser = PD("u",g.zLogin); 462 549 if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){ 463 - blob_appendf(p, " (claiming to be %h)", zUser); 550 + blob_appendf(p, ", представившись как %h,", zUser); 464 551 } 465 - zRemark = PD("r",""); 466 - blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId); 552 + zRemark = wiki_sanify(PD("r","")); 553 + blob_appendf(p, " добавил:</i><br />\n%s</div id=\"%s\">", zRemark, zId); 467 554 } 468 555 469 556 /* 470 557 ** WEBPAGE: wikiappend 471 558 ** URL: /wikiappend?name=PAGENAME 472 559 */ 473 560 void wikiappend_page(void){ ................................................................................ 704 791 */ 705 792 void wcontent_page(void){ 706 793 Stmt q; 707 794 int showAll = P("all")!=0; 708 795 709 796 login_check_credentials(); 710 797 if( !g.perm.RdWiki ){ login_needed(); return; } 798 +#ifdef LANG_RU 799 + style_header("Доступные вики-стариницы"); 800 +#elif LANG_EN 711 801 style_header("Available Wiki Pages"); 802 +#endif 803 + 712 804 if( showAll ){ 805 +#ifdef LANG_RU 806 + style_submenu_element("Активные", "Только активные страницы", "%s/wcontent", g.zTop); 807 +#elif LANG_EN 713 808 style_submenu_element("Active", "Only Active Pages", "%s/wcontent", g.zTop); 809 +#endif 714 810 }else{ 811 +#ifdef LANG_RU 812 + style_submenu_element("Все", "Все страницы", "%s/wcontent?all=1", g.zTop); 813 +#elif LANG_EN 715 814 style_submenu_element("All", "All", "%s/wcontent?all=1", g.zTop); 815 +#endif 716 816 } 817 + 717 818 @ <ul> 718 819 wiki_prepare_page_list(&q); 719 820 while( db_step(&q)==SQLITE_ROW ){ 720 821 const char *zName = db_column_text(&q, 0); 721 822 int size = db_column_int(&q, 1); 722 823 if( size>0 ){ 723 824 @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
Changes to src/wikiformat.c.
232 232 #define MUTYPE_TD 0x0100 /* <td> or <th> */ 233 233 #define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */ 234 234 #define MUTYPE_HYPERLINK 0x0400 /* <a> */ 235 235 236 236 /* 237 237 ** These markup types must have an end tag. 238 238 */ 239 -#define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE) 239 +#define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_LIST | MUTYPE_TABLE) 240 240 241 241 /* 242 242 ** This markup types are allowed for "inline" text. 243 243 */ 244 244 #define MUTYPE_INLINE (MUTYPE_FONT | MUTYPE_HYPERLINK) 245 245 246 246 static const struct AllowedMarkup { ................................................................................ 379 379 #define TOKEN_NEWLINE 5 /* A single "\n" */ 380 380 #define TOKEN_BUL_LI 6 /* " * " */ 381 381 #define TOKEN_NUM_LI 7 /* " # " */ 382 382 #define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */ 383 383 #define TOKEN_INDENT 9 /* " " */ 384 384 #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ 385 385 #define TOKEN_TEXT 11 /* None of the above */ 386 +#define TOKEN_SWHTML 12 /* switch use html */ 386 387 387 388 /* 388 389 ** State flags. Save the lower 16 bits for the WIKI_* flags. 389 390 */ 390 391 #define AT_NEWLINE 0x0010000 /* At start of a line */ 391 392 #define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */ 392 393 #define ALLOW_WIKI 0x0040000 /* Allow wiki markup */ ................................................................................ 630 631 ** characters in that token. Write the token type into *pTokenType. 631 632 */ 632 633 static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){ 633 634 int n; 634 635 if( z[0]=='<' ){ 635 636 n = markupLength(z); 636 637 if( n>0 ){ 637 - *pTokenType = TOKEN_MARKUP; 638 + if(n == 3 && z[1] == 'x') 639 + *pTokenType = TOKEN_SWHTML; 640 + else 641 + *pTokenType = TOKEN_MARKUP; 638 642 return n; 639 - }else{ 643 + } else { 640 644 *pTokenType = TOKEN_CHARACTER; 641 645 return 1; 642 646 } 643 647 } 648 + 644 649 if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){ 645 650 *pTokenType = TOKEN_CHARACTER; 646 651 return 1; 647 652 } 648 653 if( (p->state & ALLOW_WIKI)!=0 ){ 649 654 if( z[0]=='\n' ){ 650 655 n = paragraphBreakLength(z); ................................................................................ 699 704 ** characters in that token. Write the token type into *pTokenType. 700 705 */ 701 706 static int nextRawToken(const char *z, Renderer *p, int *pTokenType){ 702 707 int n; 703 708 if( z[0]=='[' && (n = linkLength(z))>0 ){ 704 709 *pTokenType = TOKEN_LINK; 705 710 return n; 711 + } 712 + if( z[0]=='<' && z[1]=='x' && z[2] == '>') { 713 + *pTokenType = TOKEN_SWHTML; 714 + return 3; 706 715 } 707 716 *pTokenType = TOKEN_RAW; 708 717 return 1 + textLength(z+1, p->state); 709 718 } 710 719 711 720 /* 712 721 ** A single markup is parsed into an instance of the following ................................................................................ 819 828 static void renderMarkup(Blob *pOut, ParsedMarkup *p){ 820 829 int i; 821 830 if( p->endTag ){ 822 831 blob_appendf(pOut, "</%s>", aMarkup[p->iCode].zName); 823 832 }else{ 824 833 blob_appendf(pOut, "<%s", aMarkup[p->iCode].zName); 825 834 for(i=0; i<p->nAttr; i++){ 835 + if(p->aAttr[i].iACode==ATTR_HREF && 0 == fossil_strnicmp(p->aAttr[i].zValue, "JavaScript:", sizeof("JavaScript:") - 1)) 836 + continue; 826 837 blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iACode].zName); 827 838 if( p->aAttr[i].zValue ){ 828 839 const char *zVal = p->aAttr[i].zValue; 829 840 if( p->aAttr[i].iACode==ATTR_SRC && zVal[0]=='/' ){ 830 841 blob_appendf(pOut, "=\"%s%s\"", g.zTop, zVal); 831 842 }else{ 832 843 blob_appendf(pOut, "=\"%s\"", zVal); ................................................................................ 924 935 ** output its end tag if it is not a </div> tag. 925 936 */ 926 937 static void popStack(Renderer *p){ 927 938 if( p->nStack ){ 928 939 int iCode; 929 940 p->nStack--; 930 941 iCode = p->aStack[p->nStack].iCode; 931 - if( iCode!=MARKUP_DIV && p->pOut ){ 942 + if( /*iCode!=MARKUP_DIV &&*/ p->pOut ){ 932 943 blob_appendf(p->pOut, "</%s>", aMarkup[iCode].zName); 933 944 } 934 945 } 935 946 } 936 947 937 948 /* 938 949 ** Push a new markup value onto the stack. Enlarge the stack ................................................................................ 1271 1282 int tokenType; 1272 1283 ParsedMarkup markup; 1273 1284 int n; 1274 1285 int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0; 1275 1286 int wikiHtmlOnly = (p->state & (WIKI_HTMLONLY | WIKI_LINKSONLY))!=0; 1276 1287 int linksOnly = (p->state & WIKI_LINKSONLY)!=0; 1277 1288 char *zOrig = z; 1289 + int forceUseHtml = 0; 1278 1290 1279 1291 /* Make sure the attribute constants and names still align 1280 1292 ** following changes in the attribute list. */ 1281 1293 assert( fossil_strcmp(aAttribute[ATTR_WIDTH].zName, "width")==0 ); 1282 1294 1283 1295 while( z[0] ){ 1284 - if( wikiHtmlOnly ){ 1296 + if( wikiHtmlOnly || forceUseHtml){ 1285 1297 n = nextRawToken(z, p, &tokenType); 1286 1298 }else{ 1287 1299 n = nextWikiToken(z, p, &tokenType); 1288 1300 } 1289 1301 p->state &= ~(AT_NEWLINE|AT_PARAGRAPH); 1290 1302 switch( tokenType ){ 1303 + case TOKEN_SWHTML: { 1304 + forceUseHtml = !forceUseHtml; 1305 + break; 1306 + } 1291 1307 case TOKEN_PARAGRAPH: { 1292 1308 if( inlineOnly ){ 1293 1309 /* blob_append(p->pOut, " ¶ ", -1); */ 1294 1310 blob_append(p->pOut, " ", -1); 1295 1311 }else{ 1296 1312 if( p->wikiList ){ 1297 1313 popStackToTag(p, p->wikiList); ................................................................................ 1519 1535 */ 1520 1536 if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){ 1521 1537 /* Do nothing */ 1522 1538 }else 1523 1539 1524 1540 /* Generate end-tags */ 1525 1541 if( markup.endTag ){ 1526 - popStackToTag(p, markup.iCode); 1542 + if(markup.iType==MUTYPE_FONT) 1543 + renderMarkup(p->pOut, &markup); 1544 + else 1545 + popStackToTag(p, markup.iCode); 1527 1546 }else 1528 1547 1529 1548 /* Push <div> markup onto the stack together with the id=ID attribute. 1530 1549 */ 1531 1550 if( markup.iCode==MARKUP_DIV ){ 1532 1551 pushStackWithId(p, markup.iCode, markupId(&markup), 1533 1552 (p->state & ALLOW_WIKI)!=0); 1553 + renderMarkup(p->pOut, &markup); 1534 1554 }else 1535 1555 1536 1556 /* Enter <verbatim> processing. With verbatim enabled, all other 1537 1557 ** markup other than the corresponding end-tag with the same ID is 1538 1558 ** ignored. 1539 1559 */ 1540 1560 if( markup.iCode==MARKUP_VERBATIM ){ ................................................................................ 1591 1611 popStackToTag(p, markup.iCode); 1592 1612 startAutoParagraph(p); 1593 1613 renderMarkup(p->pOut, &markup); 1594 1614 pushStack(p, markup.iCode); 1595 1615 } 1596 1616 }else 1597 1617 { 1598 - if( markup.iType==MUTYPE_FONT ){ 1618 + /*if( markup.iType==MUTYPE_FONT ){ 1599 1619 startAutoParagraph(p); 1600 - }else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){ 1620 + }else*/ 1621 + if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){ 1601 1622 p->wantAutoParagraph = 0; 1602 1623 } 1603 1624 if( markup.iCode==MARKUP_HR 1604 1625 || markup.iCode==MARKUP_H1 1605 1626 || markup.iCode==MARKUP_H2 1606 1627 || markup.iCode==MARKUP_H3 1607 1628 || markup.iCode==MARKUP_H4 ................................................................................ 1905 1926 break; 1906 1927 } 1907 1928 } 1908 1929 z += n; 1909 1930 } 1910 1931 free(renderer.aStack); 1911 1932 } 1933 +/* 1934 +** Test text before it add to wiki. Allow use of <x> only for developers or wikieditors. 1935 +*/ 1936 +const char* wiki_sanify(const char *pSrc){ 1937 + static Blob tempStore = BLOB_INITIALIZER; 1938 + int hasReplaces = 0; 1939 + const char* z = pSrc; 1940 + Renderer r; 1941 + 1942 + blob_reset(&tempStore); 1943 + 1944 + if(g.perm.Admin || g.perm.NewWiki || g.perm.Write || g.perm.WrWiki || g.perm.Setup) 1945 + return pSrc; 1946 + r.state = 1; 1947 + while(*z) 1948 + { 1949 + int tokenType; 1950 + int n = nextRawToken(z, &r, &tokenType); 1951 + if(tokenType == TOKEN_SWHTML) { 1952 + if(!hasReplaces) { 1953 + blob_append(&tempStore, pSrc, z - pSrc); 1954 + hasReplaces = 1; 1955 + } 1956 + blob_append(&tempStore, "<x>", 9); 1957 + } 1958 + else if(hasReplaces) 1959 + blob_append(&tempStore, z, n); 1960 + z+=n; 1961 + } 1962 + return hasReplaces ? blob_str(&tempStore) : pSrc; 1963 +} 1912 1964 1913 1965 /* 1914 1966 ** Get the next HTML token. 1915 1967 ** 1916 1968 ** z points to the start of a token. Return the number of 1917 1969 ** characters in that token. 1918 1970 */