Fossil

Check-in [d57de287]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The "h" capability is now used to enable hyperlinks to non-wiki pages. When "h" is missing, many pages give a hyperlink to the login page and automatically fill in "anonymous" as the user name. The login page jumps back to the target page after a successful login.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d57de28756ddf7716d08a04ebfe1f5f2fd8c7687
User & Date: drh 2008-05-05 23:15:29.000
Context
2008-05-06
12:24
Add the --proxy command-line option that can be used to enable or disable an http proxy on a case by case basis. ... (check-in: f6525990 user: drh tags: trunk)
2008-05-05
23:15
The "h" capability is now used to enable hyperlinks to non-wiki pages. When "h" is missing, many pages give a hyperlink to the login page and automatically fill in "anonymous" as the user name. The login page jumps back to the target page after a successful login. ... (check-in: d57de287 user: drh tags: trunk)
20:18
Work toward making the "h" permission mean "hyperlink". Without "h", many pages will display, but there are few hyperlinks. A message invites users to login as anonymous. ... (check-in: 2b0d4519 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/browse.c.
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
*/
void hyperlinked_path(const char *zPath, Blob *pOut){
  int i, j;
  char *zSep = "";

  for(i=0; zPath[i]; i=j){
    for(j=i; zPath[j] && zPath[j]!='/'; j++){}
    if( zPath[j] ){
      blob_appendf(pOut, "%s<a href=\"%s/dir?name=%#T\">%#h</a>", 
                   zSep, g.zBaseURL, j, zPath, j-i, &zPath[i]);
    }else{
      blob_appendf(pOut, "%s%h", zSep, &zPath[i]);
    }
    zSep = "/";
    while( zPath[j]=='/' ){ j++; }
  }
}









|



|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
*/
void hyperlinked_path(const char *zPath, Blob *pOut){
  int i, j;
  char *zSep = "";

  for(i=0; zPath[i]; i=j){
    for(j=i; zPath[j] && zPath[j]!='/'; j++){}
    if( zPath[j] && g.okHistory ){
      blob_appendf(pOut, "%s<a href=\"%s/dir?name=%#T\">%#h</a>", 
                   zSep, g.zBaseURL, j, zPath, j-i, &zPath[i]);
    }else{
      blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
    }
    zSep = "/";
    while( zPath[j]=='/' ){ j++; }
  }
}


Changes to src/db.c.
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160


1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176

1177
1178



1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194

1195
1196



1197
1198
1199
1200
1201
1202
1203
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  const char *zUuid;         /* The UUID to render */
  char *z;                   /* Rendered HTML text */

  zUuid = (const char*)sqlite3_value_text(argv[0]);
  if( zUuid && strlen(zUuid)>=10 ){
    z = mprintf("<tt><a href='%s/vinfo/%t'><span style='font-size:1.5em'>"
                "%#h</span>%h</a></tt>",
                g.zBaseURL, zUuid, 10, zUuid, &zUuid[10]);
    sqlite3_result_text(pCxt, z, -1, free);


  }
}

/*
** SQL function to render a TAGID as a hyperlink to a page describing
** that tag.
*/
static void hyperlinkTagidFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  int tagid;                 /* The tagid to render */
  char *z;                   /* rendered html text */

  tagid = sqlite3_value_int(argv[0]);

  z = mprintf("<a href='%s/tagview?tagid=%d'>%d</a>", 
                g.zBaseURL, tagid, tagid);



  sqlite3_result_text(pCxt, z, -1, free);
}

/*
** SQL function to render a TAGNAME as a hyperlink to a page describing
** that tag.
*/
static void hyperlinkTagnameFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  const char *zTag;          /* The tag to render */
  char *z;                   /* rendered html text */

  zTag = (const char*)sqlite3_value_text(argv[0]);

  z = mprintf("<a href='%s/tagview?name=%T'>%h</a>", 
                g.zBaseURL, zTag, zTag);



  sqlite3_result_text(pCxt, z, -1, free);
}

/*
** SQL function to escape all characters in a string that have special
** meaning to HTML.
*/







|




>
>
















>
|
|
>
>
>
















>
|
|
>
>
>







1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  const char *zUuid;         /* The UUID to render */
  char *z;                   /* Rendered HTML text */

  zUuid = (const char*)sqlite3_value_text(argv[0]);
  if( g.okHistory && zUuid && strlen(zUuid)>=10 ){
    z = mprintf("<tt><a href='%s/vinfo/%t'><span style='font-size:1.5em'>"
                "%#h</span>%h</a></tt>",
                g.zBaseURL, zUuid, 10, zUuid, &zUuid[10]);
    sqlite3_result_text(pCxt, z, -1, free);
  }else{
    sqlite3_result_text(pCxt, zUuid, -1, SQLITE_TRANSIENT);
  }
}

/*
** SQL function to render a TAGID as a hyperlink to a page describing
** that tag.
*/
static void hyperlinkTagidFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  int tagid;                 /* The tagid to render */
  char *z;                   /* rendered html text */

  tagid = sqlite3_value_int(argv[0]);
  if( g.okHistory ){
    z = mprintf("<a href='%s/tagview?tagid=%d'>%d</a>", 
                  g.zBaseURL, tagid, tagid);
  }else{
    z = mprintf("%d", tagid);
  }
  sqlite3_result_text(pCxt, z, -1, free);
}

/*
** SQL function to render a TAGNAME as a hyperlink to a page describing
** that tag.
*/
static void hyperlinkTagnameFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  const char *zTag;          /* The tag to render */
  char *z;                   /* rendered html text */

  zTag = (const char*)sqlite3_value_text(argv[0]);
  if( g.okHistory ){
    z = mprintf("<a href='%s/tagview?name=%T'>%h</a>", 
                  g.zBaseURL, zTag, zTag);
  }else{
    z = mprintf("%h", zTag);
  }
  sqlite3_result_text(pCxt, z, -1, free);
}

/*
** SQL function to escape all characters in a string that have special
** meaning to HTML.
*/
Changes to src/descendents.c.
187
188
189
190
191
192
193

194
195
196
197
198
199
200
void leaves_page(void){
  Stmt q;

  login_check_credentials();
  if( !g.okRead ){ login_needed(); return; }

  style_header("Leaves");

  db_prepare(&q,
    "%s"
    "   AND blob.rid IN"
    "       (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)"
    " ORDER BY event.mtime DESC",
    timeline_query_for_www()
  );







>







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
void leaves_page(void){
  Stmt q;

  login_check_credentials();
  if( !g.okRead ){ login_needed(); return; }

  style_header("Leaves");
  login_anonymous_available();
  db_prepare(&q,
    "%s"
    "   AND blob.rid IN"
    "       (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)"
    " ORDER BY event.mtime DESC",
    timeline_query_for_www()
  );
Changes to src/login.c.
72
73
74
75
76
77
78
79

80
81
82
83
84
85

86
87
88
89
90
91
92
** WEBPAGE: /logout
**
** Generate the login page
*/
void login_page(void){
  const char *zUsername, *zPasswd, *zGoto;
  const char *zNew1, *zNew2;
  const char *zAnonPw;

  char *zErrMsg = "";

  login_check_credentials();
  zUsername = P("u");
  zPasswd = P("p");
  zGoto = PD("g","index");

  if( P("out")!=0 ){
    const char *zCookieName = login_cookie_name();
    cgi_set_cookie(zCookieName, "", 0, -86400);
    cgi_redirect(zGoto);
  }
  if( g.okPassword && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
    if( db_int(1, "SELECT 0 FROM user"







|
>






>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
** WEBPAGE: /logout
**
** Generate the login page
*/
void login_page(void){
  const char *zUsername, *zPasswd, *zGoto;
  const char *zNew1, *zNew2;
  const char *zAnonPw = 0;
  int anonFlag;
  char *zErrMsg = "";

  login_check_credentials();
  zUsername = P("u");
  zPasswd = P("p");
  zGoto = PD("g","index");
  anonFlag = P("anon")!=0;
  if( P("out")!=0 ){
    const char *zCookieName = login_cookie_name();
    cgi_set_cookie(zCookieName, "", 0, -86400);
    cgi_redirect(zGoto);
  }
  if( g.okPassword && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
    if( db_int(1, "SELECT 0 FROM user"
145
146
147
148
149
150
151
152
153
154
155
156



157

158
159
160
161
162










163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193
194
      cgi_redirect(zGoto);
    }
  }
  style_header("Login/Logout");
  @ %s(zErrMsg)
  @ <form action="login" method="POST">
  if( P("g") ){
    @ <input type="hidden" name="nxp" value="%h(P("g"))">
  }
  @ <table align="left" hspace="10">
  @ <tr>
  @   <td align="right">User ID:</td>



  @   <td><input type="text" name="u" value="" size=30></td>

  @ </tr>
  @ <tr>
  @  <td align="right">Password:</td>
  @   <td><input type="password" name="p" value="" size=30></td>
  @ </tr>










  @ <tr>
  @   <td></td>
  @   <td><input type="submit" name="in" value="Login"></td>
  @ </tr>
  @ </table>
  if( g.zLogin==0 ){
    @ <p>To login
  }else{
    @ <p>You are current logged in as <b>%h(g.zLogin)</b></p>
    @ <p>To change your login to a different user
  }
  @ enter the user-id and password at the left and press the
  @ "Login" button.  Your user name will be stored in a browser cookie.
  @ You must configure your web browser to accept cookies in order for
  @ the login to take.</p>
  if( g.zLogin==0 ){
    zAnonPw = db_text(0, "SELECT pw FROM user"
                         " WHERE login='anonymous'"
                         "   AND cap!=''");
    if( zAnonPw ){
      @ <p>If you do not have a user-id, enter "<b>anonymous</b>" with a
      @ password of "<b>%h(zAnonPw)</b>".</p>

    }else{
      @ <p>A valid user-id and password is required.  Anonymous access
      @ is not allowed on this installation.</p>
    }
  }
  if( g.zLogin ){
    @ <br clear="both"><hr>
    @ <p>To log off the system (and delete your login cookie)
    @  press the following button:<br>
    @ <input type="submit" name="out" value="Logout"></p>







|




>
>
>
|
>





>
>
>
>
>
>
>
>
>
>
















<
<
<
|
<
|
>

|
<







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194



195

196
197
198
199

200
201
202
203
204
205
206
      cgi_redirect(zGoto);
    }
  }
  style_header("Login/Logout");
  @ %s(zErrMsg)
  @ <form action="login" method="POST">
  if( P("g") ){
    @ <input type="hidden" name="g" value="%h(P("g"))">
  }
  @ <table align="left" hspace="10">
  @ <tr>
  @   <td align="right">User ID:</td>
  if( anonFlag ){
    @   <td><input type="text" name="u" value="anonymous" size=30></td>
  }else{
    @   <td><input type="text" name="u" value="" size=30></td>
  }
  @ </tr>
  @ <tr>
  @  <td align="right">Password:</td>
  @   <td><input type="password" name="p" value="" size=30></td>
  @ </tr>
  if( g.zLogin==0 ){
    zAnonPw = db_text(0, "SELECT pw FROM user"
                         " WHERE login='anonymous'"
                         "   AND cap!=''");
    if( zAnonPw && anonFlag ){
      @ <tr><td></td>
      @ <td>The anonymous password is "<b>%h(zAnonPw)</b>".</td>
      @ </tr>
    }
  }
  @ <tr>
  @   <td></td>
  @   <td><input type="submit" name="in" value="Login"></td>
  @ </tr>
  @ </table>
  if( g.zLogin==0 ){
    @ <p>To login
  }else{
    @ <p>You are current logged in as <b>%h(g.zLogin)</b></p>
    @ <p>To change your login to a different user
  }
  @ enter the user-id and password at the left and press the
  @ "Login" button.  Your user name will be stored in a browser cookie.
  @ You must configure your web browser to accept cookies in order for
  @ the login to take.</p>
  if( g.zLogin==0 ){



    if( zAnonPw && !anonFlag ){

      @ <p>The password for user "anonymous" is "<b>%h(zAnonPw)</b>".</p>
      @ <p>&nbsp;</p>
    }else{
      @ <p>&nbsp;</p><p>&nbsp;</p>

    }
  }
  if( g.zLogin ){
    @ <br clear="both"><hr>
    @ <p>To log off the system (and delete your login cookie)
    @  press the following button:<br>
    @ <input type="submit" name="out" value="Logout"></p>
379
380
381
382
383
384
385

386
387
388
389

390
391
** logging in as anonymous.
*/
void login_anonymous_available(void){
  if( !g.okHistory &&
      db_exists("SELECT 1 FROM user"
                " WHERE login='anonymous'"
                "   AND cap LIKE '%%h%%'") ){

    @ <p><b>Note:</b> Many hyperlinks are omitted from this page to discourage
    @ <a href="http://en.wikipedia.org/wiki/Web_crawler">spiders</a>.
    @ You will be able to access information more easily if you
    @ <a href="%s(g.zTop)/login">login</a> as user "anonymous".</p>

  }
}







>
|
<
<
|
>


391
392
393
394
395
396
397
398
399


400
401
402
403
** logging in as anonymous.
*/
void login_anonymous_available(void){
  if( !g.okHistory &&
      db_exists("SELECT 1 FROM user"
                " WHERE login='anonymous'"
                "   AND cap LIKE '%%h%%'") ){
    const char *zUrl = PD("REQUEST_URI", "index");
    @ <p>Many <font color="red">hyperlinks are disabled.</font><br />


    @ Use <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">anonymous login</a>
    @ to enable hyperlinks.</p>
  }
}
Changes to src/tagview.c.
142
143
144
145
146
147
148

149
150
151
152
153
154
155
*/
void tagview_page(void){
  login_check_credentials();
  if( !g.okRdWiki ){
    login_needed();
  }
  style_header("Tags");

  tagview_page_search_miniform();
  @ <hr/>
  char const * check = 0;
  if( 0 != (check = P("tagid")) ){
    tagview_page_tag_by_id( atoi(check) );
  }else if( 0 != (check = P("like")) ){
    tagview_page_list_tags( check );







>







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
*/
void tagview_page(void){
  login_check_credentials();
  if( !g.okRdWiki ){
    login_needed();
  }
  style_header("Tags");
  login_anonymous_available();
  tagview_page_search_miniform();
  @ <hr/>
  char const * check = 0;
  if( 0 != (check = P("tagid")) ){
    tagview_page_tag_by_id( atoi(check) );
  }else if( 0 != (check = P("like")) ){
    tagview_page_list_tags( check );
Changes to src/wikiformat.c.
783
784
785
786
787
788
789


















790
791
792
793
794
795
796
*/
static int is_valid_uuid(const char *z){
  int n = strlen(z);
  if( n<4 || n>UUID_SIZE ) return 0;
  if( !validate16(z, n) ) return 0;
  return 1;
}



















/*
** Resolve a hyperlink.  The argument is the content of the [...]
** in the wiki.  Append the URL to the output of the Renderer.
*/
static void resolveHyperlink(const char *zTarget, Renderer *p){
  if( strncmp(zTarget, "http:", 5)==0 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
*/
static int is_valid_uuid(const char *z){
  int n = strlen(z);
  if( n<4 || n>UUID_SIZE ) return 0;
  if( !validate16(z, n) ) return 0;
  return 1;
}

/*
** Return true if the given hyperlink should be implemented for
** the current login.
*/
static int okToHyperlink(const char *zTarget){
  if( g.okHistory ) return 1;
  if( strncmp(zTarget, "http:", 5)==0 
   || strncmp(zTarget, "https:", 6)==0
   || strncmp(zTarget, "ftp:", 4)==0 
   || strncmp(zTarget, "mailto:", 7)==0
  ){
    return 1;
  }
  if( zTarget[0]=='/' || is_valid_uuid(zTarget) ) return 0;
  if( wiki_name_is_wellformed(zTarget) ) return 1;
  return 0;
}

/*
** Resolve a hyperlink.  The argument is the content of the [...]
** in the wiki.  Append the URL to the output of the Renderer.
*/
static void resolveHyperlink(const char *zTarget, Renderer *p){
  if( strncmp(zTarget, "http:", 5)==0 
928
929
930
931
932
933
934

935
936
937
938
939
940
941
942
943
944
945
946
947
948
949


950
951
952

953
954
955
956
957
958
959
960
961
962
963
964
965
        break;
      }
      case TOKEN_LINK: {
        char *zTarget;
        char *zDisplay = 0;
        int i, j;
        int savedState;

        startAutoParagraph(p);
        zTarget = &z[1];
        for(i=1; z[i] && z[i]!=']'; i++){
          if( z[i]=='|' && zDisplay==0 ){
            zDisplay = &z[i+1];
            z[i] = 0;
            for(j=i-1; j>0 && isspace(z[j]); j--){ z[j] = 0; }
          }
        }
        z[i] = 0;
        if( zDisplay==0 ){
          zDisplay = zTarget;
        }else{
          while( isspace(*zDisplay) ) zDisplay++;
        }


        blob_append(p->pOut, "<a href=\"", -1);
        resolveHyperlink(zTarget, p);
        blob_append(p->pOut, "\">", -1);

        savedState = p->state;
        p->state &= ~ALLOW_WIKI;
        p->state |= FONT_MARKUP_ONLY;
        wiki_render(p, zDisplay);
        p->state = savedState;
        blob_append(p->pOut, "</a>", 4);
        break;
      }
      case TOKEN_TEXT: {
        startAutoParagraph(p);
        blob_append(p->pOut, z, n);
        break;
      }







>















>
>
|
|
|
>





|







946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
        break;
      }
      case TOKEN_LINK: {
        char *zTarget;
        char *zDisplay = 0;
        int i, j;
        int savedState;
        int ok;
        startAutoParagraph(p);
        zTarget = &z[1];
        for(i=1; z[i] && z[i]!=']'; i++){
          if( z[i]=='|' && zDisplay==0 ){
            zDisplay = &z[i+1];
            z[i] = 0;
            for(j=i-1; j>0 && isspace(z[j]); j--){ z[j] = 0; }
          }
        }
        z[i] = 0;
        if( zDisplay==0 ){
          zDisplay = zTarget;
        }else{
          while( isspace(*zDisplay) ) zDisplay++;
        }
        ok = okToHyperlink(zTarget);
        if( ok ){
          blob_append(p->pOut, "<a href=\"", -1);
          resolveHyperlink(zTarget, p);
          blob_append(p->pOut, "\">", -1);
        }
        savedState = p->state;
        p->state &= ~ALLOW_WIKI;
        p->state |= FONT_MARKUP_ONLY;
        wiki_render(p, zDisplay);
        p->state = savedState;
        if( ok ) blob_append(p->pOut, "</a>", 4);
        break;
      }
      case TOKEN_TEXT: {
        startAutoParagraph(p);
        blob_append(p->pOut, z, n);
        break;
      }