4 번째 수정본
-
- 1. 버그 또는 문제점 해결
-
-
- 1.1. fullsearch 와 titlesearch 매크로의 출력 형식 변경
-
- 1.2. pre 태그 안에서 부등호 표기 문제 해결
-
- 1.3. 사이트 로고 표시 문제 해결
-
- 1.4. 동일한 영어단어로 끝나는 헤드라인들이 있을 경우 <toc> 가 제대로 동작하지 않는 문제 해결
-
- 1.5. 한글이 포함된 인터위키 문제 해결
-
- 1.6. history 매크로 문제 해결
-
- 1.7. user 디렉토리를 생성하지 못하는 문제 해결
-
- 1.8. 잠겨 있는 페이지를 삭제 또는 이름을 변경할 때 lock 도 같이 처리
-
- 1.9. 사용자 아이디의 첫글자를 무조건 대문자로 만듦
-
- 1.10. 다른 사용자의 암호를 변경할 수 있는 문제 해결
-
- 1.11. 페이지를 삭제 또는 이름을 변경할 때 cache 화일도 같이 처리
-
- 1.12. REDIRECT 되는 페이지의 캐쉬 화일 문제 해결
-
- 1.13. 미리보기 화면에서 <toc> 가 제대로 동작하지 않는 문제 해결
-
- 1.14. ==== 충돌문제 해결
-
- 1.15. 상대경로로 적은 URL 처리
-
- 1.16. 사용자 암호를 암호화하여 저장
-
- 1.17. 환경설정에서 사용할 수 없는 아이디를 넣었을 때의 처리 문제 해결
-
- 1.18. 로그아웃 직후에 상단메뉴에 여전히 로그아웃 링크가 남아있는 문제 해결
-
- 1.19. 로그인 실패시 상단 메뉴의 잘못된 출력 해결
-
- 1.20. 이모티콘 패턴 수정
-
- 1.21. Full Link List 버그 수정
-
- 1.22. GetFullLinkList() 함수의 버그 수정
-
- 1.23. goto 매크로 문제 해결
-
1. 버그 또는 문제점 해결
1.1. fullsearch 와 titlesearch 매크로의 출력 형식 변경
- fullsearch 와 titlesearch 매크로를 사용했을 때, 출력되는 페이지 제목들의 목록이 가로로 나열되는 것을 세로로 나열되도록 변경
- 부작용:
- html 을 보기 좋으라고 "<br>\n" 을 출력시켰더니만 "공백으로 시작하는 줄 pre 치환" 때문에 이상하게 된다. "\n" 출력을 제거했음
-
sub MacroTitleSearch {
...
$txt .= &GetPageLink($name) . "<br>"; # 원래는 " " 인데, "<br>" 로 수정했음.
...
$txt .= &GetPageLink($name) . "<br>";
}
-
sub MacroFullSearch()
{
...
$txt .= &GetPageLink($pagename) . "<br>";
...
}
1.2. pre 태그 안에서 부등호 표기 문제 해결
- 좌우 부등호로 둘러쌓인 부분을 태그로 처리해 버리고, & lt; 와 & gt; 를 사용해도 다음 번 수정시에 다시 부등호로 바꾸어 버리는 문제를 해결
- [jof4002님의 패치]를 적용함
- 부작용 : 알려진 것 없음
-
sub GetTextArea {
my ($name, $text, $rows, $cols) = @_;
$text =~ s/(\&)/\&/g; # 이 줄을 추가해 준다.
...
}
1.3. 사이트 로고 표시 문제 해결
-
sub GetHeader {
...
if ($id ne '') {
# $result .= $q->h1(&GetSearchLink($id)); 이 부분을
$result .= $q->h1($header . &GetSearchLink($id)); # 이렇게 고쳐줄 것
} else {
$result .= $q->h1($header . $title);
}
...
}
1.4. 동일한 영어단어로 끝나는 헤드라인들이 있을 경우 <toc> 가 제대로 동작하지 않는 문제 해결
- toc 매크로를 사용할 때, == 사이에 둘러쌓인 제목들이 같은 영단어로 끝날 경우 제대로 toc 가 만들어지지 않는 문제 해결
- [Jay's Wiki의 패치]를 적용함
- 부작용 : 알려진 것 없음
-
sub WikiHeadingNumber {
...
# Cook anchor by canonicalizing $text.
# 아래 여섯 줄은 불필요. 주석처리
# $anchor = $text;
# $anchor =~ s/\<.*?\>//g;
# $anchor =~ s/\W/_/g;
# $anchor =~ s/__+/_/g;
# $anchor =~ s/^_//;
# $anchor =~ s/_$//;
# $anchor = '_' . (join '_', @HeadingNumbers) unless $anchor; # Last ditch effort 이 줄을
$anchor = 'H_' . (join '_', @HeadingNumbers); # unless 뒤를 잘라서 이렇게 고친다
...
}
- 인터위키를 사용할 때 페이지 제목에 한글이 포함되어 있으면 제대로 인식을 하지 못하는 문제가 있었다.
- [Jof4002님의 패치]를 적용
- 부작용 : 알려진 것 없음
-
sub SplitUrlPunct {
....
$punct = "";
# 아래 두 줄의 xc0 을 x80 으로 바꿈
# ($punct) = ($url =~ /([^a-zA-Z0-9\/\xc0-\xff]+)$/);
# $url =~ s/([^a-zA-Z0-9\/\xc0-\xff]+)$//;
($punct) = ($url =~ /([^a-zA-Z0-9\/\x80-\xff]+)$/);
$url =~ s/([^a-zA-Z0-9\/\x80-\xff]+)$//;
return ($url, $punct);
}
1.6. history 매크로 문제 해결
- <history(5)> 라는 매크로가 있다면, 본문 내용에 최근 5번의 revision 목록을 출력하는데 (History 를 클릭했을 때와 동일한 출력), 실제로 다섯개의 최근 revision 이 각각의 revision 을 링크하고 있는 것이 아니라 죄다 현재 버전을 링크하고 있다. (Revision 3 을 클릭해도 3번째 수정본이 아닌 마지막 수정본이 출력된다)
- 왼쪽에 있는 radio button 들도, History 를 클릭했을 때와는 다르게 엉뚱한 위치가 디폴트로 지정되어 있다. (디폴트 위치가 문제가 있을 뿐 동작은 제대로 한다)
- MacroHistory 에서 GetHistoryLine 을 부를 때 row parameter 의 값을 수정하여 해결
- 부작용: 알려진 것 없음
- MacroHistory의 내용만 변경했으므로, 부작용이 있더라도 history 매크로를 사용한 곳에서만 발생할 것으로 생각됨
-
sub MacroHistory {
...
$html .= "<table border='0' cellpadding=0 cellspacing=0 width='90%'><tr>";
# $html .= &GetHistoryLine($DocID, $Page{'text_default'}, 0, 1); 이 줄을 다음 줄로 변경
$html .= &GetHistoryLine($DocID, $Page{'text_default'}, 0, 0);
&OpenKeptRevisions('text_default');
...
next if ($_ eq ""); # (needed?)
# $html .= &GetHistoryLine($DocID, $KeptRevisions{$_}, 0, 0); 이 줄을 다음 줄로 변경
$html .= &GetHistoryLine($DocID, $KeptRevisions{$_}, 0, $i);
}
$html .= "<tr><td align='center'><input type='submit' value='변경 비교'/> </td><td> </td></table></form>\n";
return $html;
}
1.7. user 디렉토리를 생성하지 못하는 문제 해결
- 설치 후 처음으로 사용자 이름을 등록할 때, 사용자 정보를 저장하지 못한다는 에러가 발생할 수 있다.
- $DataDir/user 디렉토리를 생성하는 루틴이 없어서 발생
- 생성 루틴 추가
- 참고로, 설치 후 처음 실행 시에 data 디렉토리를 생성하지 못해서 에러가 발생할 수도 있다. 이것은 위키가 설치된 디렉토리의 퍼미션 문제이다.
- 위키가 설치된 디렉토리에 타인의 write 권한이 허용되어 있으면 (ex: 777, 773 등) 이 에러가 발생하지 않는다.
- 또는, 사용자가 수동으로 data 디렉토리를 만들어 주어도 된다. 이 때는 data 디렉토리를 777 퍼미션으로 해 주어야 한다.
- Unix의Permission 참조
- 부작용: 알려진 것 없음
- 사용자 환경설정에서 저장버튼을 누를 때마다 함수 호출 한 번, if 문 한 번이 실행되니, 퍼포먼스 저하가 부작용이라면 부작용일 듯. :-)
-
sub SaveUserData {
my ($userFile, $data);
# 다음 줄 추가
&CreateDir($UserDir);
$userFile = &UserDataFilename($UserID);
$data = join($FS1, %UserData);
&WriteStringToFile($userFile, $data);
}
1.8. 잠겨 있는 페이지를 삭제 또는 이름을 변경할 때 lock 도 같이 처리
- lock 이 걸려 있는 페이지를 관리자가 삭제할 때, lock 화일은 삭제되지 않고 그대로 남아 있는 문제가 있었다.
- 마찬가지로, lock 이 걸려 있는 페이지의 이름을 변경할 경우, lock 화일이 그대로 남아서, 옛 이름의 페이지는 lock 만 남아있고, 새 이름의 페이지는 반대로 lock 이 걸려 있지 않게 되는 문제가 있었다.
- wiki.pl 의 페이지삭제와 페이지이름변경 루틴에 lock 에 대한 처리를 삽입하여 해결
- 부작용: 알려진 것 없음
-
sub DeletePage {
...
$fname = $KeepDir . "/" . &GetPageDirectory($page) . "/$page.kp";
unlink($fname) if (-f $fname);
### 아래 두 줄 추가
$fname = &GetLockedPageFile($page);
unlink($fname) if (-f $fname);
### 여기까지
unlink($IndexFile) if ($UseIndex);
...
}
-
sub RenamePage {
...
rename($oldkeep, $newkeep);
unlink($IndexFile) if ($UseIndex);
### 다음 코드를 삽입
my ($oldlock, $newlock);
$oldlock = &GetLockedPageFile($old);
if (-f $oldlock) {
$newlock = &GetLockedPageFile($new);
rename($oldlock, $newlock) || die "error while renaming lock";
}
### 여기까지
&EditRecentChanges(2, $old, $new) if ($doRC);
if ($doText) {
...
}
1.9. 사용자 아이디의 첫글자를 무조건 대문자로 만듦
- 페이지 이름은 대문자로만 시작하면서 아이디는 대소문자를 구분하기 때문에 생기는 혼란의 여지를 막고자 함
- 새소식및공지에는 대소문자 구분을 하지 않게 했다고 썼지만... 사실은 거짓말이다. :-) UseModWiki 는 여전히 대소문자를 구분한다. 그렇지만, 사용자가 새로 아이디를 만들거나 환경설정에 들어갔을때, 아이디란에 첫글자를 소문자로 적었다 하더라도 그게 처리되기 전에 먼저 대문자로 바꿔치기 하는 루틴을 넣었다.
- 로긴하는 부분, 환경설정 하는 부분의 루틴을 수정
- 부작용: 알려진 것 없음
- 주인장이 이런저런 테스트를 거쳐 제대로 동작한다고 결론을 내렸으나, 확실한 것은 아니다. 전혀 뜻밖의 문제가 생길지도 모른다..
-
sub DoUpdatePrefs {
...
print '<br>';
### 다음 두 줄을 수정한다.
# $UserID = &GetParam("p_username", "");
# $username = &GetParam("p_username", "");
$UserID = &FreeToNormal(&GetParam("p_username", ""));
$username = &FreeToNormal(&GetParam("p_username", ""));
###
if ($FreeLinks) {
...
}
-
sub DoLogin {
my ($uid, $password, $success);
$success = 0;
### 다음 한 줄을 수정한다
# $uid = &GetParam("p_userid", "");
$uid = &FreeToNormal(&GetParam("p_userid", ""));
###
$password = &GetParam("p_password", "");
...
}
1.10. 다른 사용자의 암호를 변경할 수 있는 문제 해결
- 환경설정에 들어가서, 아이디란에 다른 사람의 아이디를 넣으면 그 아이디의 환경설정을 변경해 버릴 수 있는 문제가 있었다.
- 소스를 수정하여, 환경설정에 넣은 아이디가 이미 존재하는 아이디일 경우는, 그 아이디로 로긴한 사람만이 설정 변경을 할 수 있도록 하였다.
-
프로그래밍팁/Wiki 의 패치를 적용
- 이 경우, 암호를 잊어버리면 대책이 없다
- 따라서, 관리자 권한을 가지고 있는 사람은 타인의 암호를 변경할 수 있도록 수정하였다.
- 관리자가 자신의 아이디로 로긴한 후, 환경설정에 들어가서, ID 란에 타인의 아이디를 입력하고, 암호를 지정해 준 후 저장을 하면 된다.
- 주의!!! 이 때 반드시 "관리자암호" 란에 있는 "*" 마크를 지우고 공란으로 두어야 한다. 그렇지 않고 그냥 저장해버리면 관리자의 관리자암호가 그대로 적용되면서 타인에게 관리자권한을 주게 된다!!!
- 이런 위험에도 불구하고 굳이 관리자에게 변경 권한을 남기는 이유는,
- 패치 적용 이전에도 이미 존재하던 위험이고
- 어쨌거나 user 디렉토리에 들어가서 암호를 까먹은 유저의 *.db 화일을 삭제하고 새로 만들도록 하는 것보다는 이 방법이 뽀대가 나기 때문이다. -_-; 게다가, root 권한이 없으면 유저 화일을 삭제하기도 쉽지 않다.
-
sub DoUpdatePrefs {
...
# 아래의 두 줄은 "사용자 아이디의 첫글자를 무조건 대문자로 만듦"에서 패치된 부분이다
# 원래코드에는 FreeToNormal( ) 로 둘러싸여 있지 않다.
$UserID = &FreeToNormal(&GetParam("p_username", ""));
$username = &FreeToNormal(&GetParam("p_username", ""));
### 다음 부분을 추가한다
my ($status, $data) = &ReadFile(&UserDataFilename($UserID));
if ($status) {
if ((!(&UserIsAdmin)) && ($UserData{'id'} ne $UserID)) {
print T('Error: Can not update prefs. That ID already exists and does not match your ID.'). '<br>';
print &GetCommonFooter();
return;
}
}
### 여기까지
if ($FreeLinks) {
$username =~ s/^\[\[(.+)\]\]/$1/; # Remove [[ and ]] if added
...
}
1.11. 페이지를 삭제 또는 이름을 변경할 때 cache 화일도 같이 처리
- UseCache 옵션을 켰을 때의 동작과 관련된 부분
- 위에서 언급한 *.lck 화일과 마찬가지로, 관리 메뉴에서 페이지를 삭제하거나 이름을 바꿀 때, html 디렉토리에 있는 *.htm 화일을 삭제하지 않는 문제가 있다. 이렇게 미아가 된 화일은 관리 메뉴를 통과해도 여전히 삭제되지 않고 영원히 남아 있게 된다.
- DeletePage 와 RenamePage 함수를 수정
- 부작용: 알려진 것 없음
-
sub DeletePage {
...
$fname = $KeepDir . "/" . &GetPageDirectory($page) . "/$page.kp";
unlink($fname) if (-f $fname);
### 예전에 lock 화일 관련 패치한 부분
$fname = &GetLockedPageFile($page);
unlink($fname) if (-f $fname);
### 다음 라인을 추가로 삽입
&UnlinkHtmlCache($page);
###
unlink($IndexFile) if ($UseIndex);
&EditRecentChanges(1, $page, "") if ($doRC); # Delete page
# Currently don't do anything with page text
}
}}}
: RenamePage 에서는, lck 화일과 달리 cache 화일은 그냥 삭제한다.
{{{perl
sub RenamePage {
...
### 이전 패치에서 추가한 lck 화일 관련 부분
my ($oldlock, $newlock);
$oldlock = &GetLockedPageFile($old);
if (-f $oldlock) {
$newlock = &GetLockedPageFile($new);
rename($oldlock, $newlock) || die "error while renaming lock";
}
### 아래 라인을 추가로 삽입
&UnlinkHtmlCache($old);
###
&EditRecentChanges(2, $old, $new) if ($doRC);
if ($doText) {
&BuildLinkIndexPage($new); # Keep index up-to-date
&RenameTextLinks($old, $new);
}
}
1.12. REDIRECT 되는 페이지의 캐쉬 화일 문제 해결
- a 라는 페이지가 있고, b 라는 페이지가 a 로 redirect 되는 페이지이며, 현재 a 페이지의 캐쉬화일이 없을 경우, b 를 클릭하면 a 페이지가 출력되면서 상단에 "b 로부터 자동으로 이동" 되었다는 헤드라인이 표시된다. 그런데 이 헤드라인이 같이 캐쉬 화일에 저장되기 때문에, 그 이후부터는 a 를 직접 열람할 때도 상단에 여전히 헤드라인이 나타난다. 올바르지 않은 출력이 나타난다는 것은 주인장같은 공돌이들에게는 참을 수 없는 일..
- redirect 로 이동한 경우에는 캐쉬 화일을 갱신하지 않도록 수정했다.
- "아니 그러면, b 를 클릭할 때는 평생이 가도 a 를 캐쉬를 통해서는 볼 수 없게 된다는 말이 아니오?" 라고 반문할 수 있겠다. 그렇다. 하지만 걱정할 것 없다. 주인장이 워낙 훌륭하게 고쳤기 때문...이 아니라, 사실은 원래부터 그런 거였다. 즉, 더 나빠진 것은 아니라는 말이다. :-) b 페이지처럼 다른 페이지로 redirect 되는 페이지들은 죽었다 깨어나도 캐쉬 화일이 만들어지지 않는다. 캐쉬 화일 갱신 루틴을 만나기 전에 a 페이지로 이동해 버리기 때문이다. 이 때 a 페이지의 캐쉬화일이 존재한다 하더라도, 역시 죽었다 깨어나도 a 의 캐쉬화일을 사용할 수는 없다. 왜냐하면 b 의 캐쉬화일을 검사하는 루틴이 지나가 버린 (물론, 그 검사는 실패했겠지) 이후에는, 더 이상 캐쉬화일을 검사하는 루틴은 없기 때문이다. 따라서, 사용자가 b 를 클릭할 때는 UseCache 옵션에 관계없이 a 의 페이지 데이타를 매번 변환하여 출력하게 된다.
- 부작용: 알려진 것 없음
- 굳이 단점을 찾아본다면, a 페이지에 대한 cache miss 가 딱 한 번 더 발생한다는 것이다. a 의 캐쉬화일이 없는 상태에서, 사용자가 b, b, a, b, a 의 순으로 페이지를 열람했다고 한다면, 기존 코드에서는 첫번째 b 를 열람한 시점에서 a 의 캐쉬가 생성되고, 세번째와 다섯번째에 a 를 열람할 때는 그 캐쉬된 데이타를 볼 수 있다. (문제는 그 캐쉬 데이타가 올바르지 않다는 점이다. 즉 상단에 대문짝만하게 "b 로부터 이동했음" 이라고 나올 것이다. 설령 a, b, a 의 순으로 열람했다 하더라도, 첫번째 a 열람시에는 제대로 나오고 캐쉬도 제대로 생성이 되지만, 두번째 b 를 열람할 때 캐쉬가 갱신되기 때문에 세번째 이후에는 잘못된 출력이 나온다.)
- 아래 패치를 적용할 경우, b b a b a 의 경우, 캐쉬 데이타는 세 번째에 a 를 열람할 때가 되어야 생성된다. 즉 세번째 a 는 좀 느리게 출력된다. 하지만 다섯번째를 비롯해서 그 이후 a 페이지를 열람할 때는 제대로 된 캐쉬 화일을 사용할 수 있다.
- 서론이 매우 길었는데, 정작 수정할 부분은 너무도 간단하다.
sub DoBrowseRequest {
...
return if ($showDiff || ($revision ne '')); # Don't cache special version
### 다음 라인의 if 구문에 조건 하나만 더 추가해주면 된다.
# &UpdateHtmlCache($id, $fullHtml) if $UseCache;
&UpdateHtmlCache($id, $fullHtml) if ($UseCache && ($oldId eq ''));
###
}
- 단 한 줄 고치는 것 가지고 이리도 길게 설명한 이유는, 지금까지 했던 패치들 중에 가장 적은 노력으로 아주 훌륭한 성과를 내는 것이 뿌듯해서인지도 모르겠다. 이해해달라. :-)
1.13. 미리보기 화면에서 <toc> 가 제대로 동작하지 않는 문제 해결
- 페이지 편집 중에 미리보기 창에서 toc 로 생성한 목차가 제대로 링크가 걸리지 않는 문제 해결
-
프로그래밍팁/Wiki 를 적용
- 부작용: 알려진 것 없음
-
sub WikiHeadingNumber {
...
### 다음 라인을 수정
# $TableOfContents .= $number . &ScriptLink("$OpenPageName#$anchor",$text) . "</dd>\n<dt> </dt><dd>";
$TableOfContents .= $number . "<a href=\"#$anchor\">" . $text . "</a></dd>\n<dt> </dt><dd>";
###
return &StoreHref(" name=\"$anchor\"") . $number;
}
1.14. ==== 충돌문제 해결
- ==== 가, 헤드라인을 만들 때도 사용되고 $ThinLine 옵션이 켜져 있을 경우 굵은 hr 라인을 만들 때도 사용된다. 따라서 헤드라인이 제대로 생성되지 않는다.
- hr 로 변환되는 패턴을 변경하여, ---- 부터 -------- 까지가 각각 size=1 에서 size=5 까지의 hr 을 나타내도록 함
-
ThinLine 의 패치 적용
- /TestThinLine 에서 확인할 수 있다
- 부작용:
- 기존에 ==== 를 사용했던 페이지와 호환되지 않는다. 점검할 것 - 한 줄에 ==== 만 들어있는 것을 hr 로 변경하게 함으로써 어느 정도 호환성을 유지할 수는 있는데, 이 경우 들여쓰기 등을 할 수 없기에 적용하지 않았다.
-
sub CommonMarkup {
...
$_ = &MacroSubst($_); # luke added
### 다음을 교체
# if ($ThinLine) {
# s/----+/<hr noshade size=1>/g;
# s/====+/<hr noshade size=2>/g;
# } else {
# s/----+/<hr>/g;
# }
if ($ThinLine) {
s/--------+/<hr noshade style="height:5px">/g;
s/-------+/<hr noshade style="height:4px">/g;
s/------+/<hr noshade style="height:3px">/g;
s/-----+/<hr noshade style="height:2px">/g;
s/----+/<hr noshade style="height:1px">/g;
} else {
s/----+/<hr>/g;
}
### 여기까지
}
if ($doLines) { # 0 = no line-oriented, 1 or 2 = do line-oriented
...
1.15. 상대경로로 적은 URL 처리
- 페이지에 http:/temp/test.html 또는 http:../../temp/test.html 이라고 적은 경우, <a href="http:/temp/test.html">http:/temp/test.html</a> 와 같이 링크가 생성되는데, 웹브라우저에 따라서 이렇게 적힌 URL 을 제대로 처리하지 못하는 경우가 있다. (주인장이 테스트한 바로는, IE 와 KDE의 K브라우저는 제대로 처리를 했고, Moziila 는 제대로 처리하지 못했다)
- URL 패턴을 링크로 변환할 때, 상대경로일 경우 앞에 http: 를 빼어 버리고 링크를 만들도록 한다. 즉 위의 경우 링크는 <a href="/temp/test.html"> 또는 <a href="../../temp/test.html"> 가 되도록 한다.
-
WikiPatches/PartialUrlFix 의 패치를 적용하려고 했는데, 이미 되어 있었다. (오리지널, Luke님의 K3, PalmWiki 버전 중 어느 시점에서 적용된 것인지는 모르겠음) 그런데 현재 상태에서는, 이미지 링크와 [URL label] 형식의 링크는 제대로 처리하지만 URL 만을 그냥 적는 경우는 처리하지 못한다. 해당 부분만 다시 수정했다.
- 부작용:
- 딱히 동작에 문제가 되지는 않는데, "눈에 보이는 것" 과 실제 링크가 걸린 방식이 달라지게 된다. 즉 화면에는 "http:../../temp/test.html" 라고 적혀 있지만 실제 링크는 "../../temp/test.html" 이라고 걸려 있다. 어쩔 수 없는 듯.
- 정 맘에 안 들 경우는, 아래 소스코드에서 return 문에 추가된 $protocol 을 제거하면 된다. 이 경우는 화면에도 http 가 빠진 채로 "../../test/test.html" 이라고만 나올 것이다. 아마도, 더 맘에 안 들 거다. :-)
- /TestPartialUrlFix 참조
- 다른 패치 (새창으로 열기 아이콘, 그림 주소 보이기) 를 이미 적용했을 경우 소스코드가 아래와는 다르게 나올 것이다. 알아서 잘 처리하라. ;-)
sub UrlLink {
...
return ("<img $ImageTag src=\"$name\">", $punct);
}
### 여기를 추가해 준다.
my $protocol;
($protocol, $name) = ($1, $2) if ($name =~ /^(https?:)(.*)/ && $2 !~ /^\/\//);
###
### return 문에 $protocol 을 추가
# return ("<a href=\"$name\">$name</a>", $punct);
return ("<a href=\"$name\">$protocol$name</a>", $punct);
}
1.16. 사용자 암호를 암호화하여 저장
- 사용자가 UseModWiki환경설정에서 입력한 자신의 암호와 관리자 암호가 *.db 화일에 고스란히 평문으로 저장되는 문제를 해결
- perl 에서 제공하는 crypt 함수를 사용하여, 간단한 변환을 거친 후에 저장하도록 한다.
- Bab2님이 작성한 패치를 변형시켜 적용
- 부작용:
- crypt 함수의 안정성에 의존하게 됨
- crypt 함수의 호출로 인한 퍼포먼스 저하. crypt 는 암호화 함수라기보다는 단방향 해쉬 함수에 가깝기 때문에 크게 저하될 것이라 생각되지는 않으나...
- 기존에 사용하던 사용자 데이타와 호환되지 않는다. (호환되게 할수도 있겠으나 귀찮아서..) 굳이 호환되게 하고 싶다면, 아래에 나오는 각종 if 문에서, 기존에 사용되던 조건문과 새로 변경된 조건문을 둘 다 검사하게 OR 로 연결해 주면 될 것이다.
-
...
package UseModWiki;
use strict;
### 다음 두 줄 추가
use vars qw($HashKey);
$HashKey = "salt"; # 2-character string
###
- 위에 있는 $HashKey 변수는 crypt 에서 사용되는 키 값이다. salt 가 아닌 다른 문자열을 사용하도록 하고, 가끔 생각날때 한번씩 바꿔주면 좋을 것이다. 키를 바꾸더라도 기존에 사용하던 사용자 데이터는 그대로 사용할 수 있다. (키 값은 처음 두 글자만 의미가 있다. 세번째 이후는 바꾸나마나이니 주의)
-
sub UserIsAdmin {
...
foreach (split(/\s+/, $AdminPass)) {
next if ($_ eq "");
### 다음 라인 교체
# return 1 if ($userPassword eq $_);
return 1 if (crypt($_, $userPassword) eq $userPassword);
###
}
return 0;
}
-
sub UserIsEditor {
...
foreach (split(/\s+/, $EditPass)) {
next if ($_ eq "");
### 다음 라인 교체
# return 1 if ($userPassword eq $_);
return 1 if (crypt($_, $userPassword) eq $userPassword);
###
}
return 0;
}
-
sub DoUpdatePrefs {
my ($username, $password);
### 다음 라인 추가
my $hashpass = "";
###
...
$password = &GetParam("p_password", "");
### 다음 라인 추가
$hashpass = crypt($password, $HashKey);
###
if ($password eq "") {
print T('Password removed.'), '<br>';
undef $UserData{'password'};
} elsif ($password ne "*") {
print T('Password changed.'), '<br>';
### 다음 라인 교체
# $UserData{'password'} = $password;
$UserData{'password'} = $hashpass;
###
}
if ($AdminPass ne "") {
$password = &GetParam("p_adminpw", "");
### 다음 라인 추가
$hashpass = crypt($password, $HashKey);
###
if ($password eq "") {
print T('Administrator password removed.'), '<br>';
undef $UserData{'adminpw'};
} elsif ($password ne "*") {
print T('Administrator password changed.'), '<br>';
### 다음 라인 교체
# $UserData{'adminpw'} = $password;
$UserData{'adminpw'} = $hashpass;
###
if (&UserIsAdmin()) {
print T('User has administrative abilities.'), '<br>';
...
}
-
sub DoLogin {
...
&LoadUserData();
### 다음 라인 교체
# if (defined($UserData{'password'}) &&
# ($UserData{'password'} eq $password)) {
if (defined($UserData{'password'}) &&
(crypt($password, $UserData{'password'}) eq $UserData{'password'})) {
###
$SetCookie{'id'} = $uid;
...
1.17. 환경설정에서 사용할 수 없는 아이디를 넣었을 때의 처리 문제 해결
- 새로 아이디를 만들 경우, 환경설정에서 아이디란을 공란으로 남겨 두면 ".db" 라는 사용자 화일이 생겨서 잘못된 동작을 유발한다.
- 그 외에도, 사용할 수 없는 아이디 (특수문자가 섞인 것 등) 를 넣었을 때도, 잘못된 아이디라서 저장할 수 없다는 메세지 다음에 "저장이 완료되었습니다"라고 나오는, 비정상적인 동작을 보인다.
- 다음과 같이 수정했다.
- 아이디가 영문 4 자보다 짧으면 거부하며, 더 이상의 진행을 하지 않고 바로 실행을 끝낸다.
- 기존에 있던 제한 (잘못된 패턴, 아이디가 50자 이상) 에서도 마찬가지로, 더 이상 진행하지 않고 바로 실행을 끝낸다.
- Bab2 님의 패치를 변형하여 적용
- 부작용: 아직은 모름. -_-;
- 오리지날 UseModWiki 에서는, 사용자 id 는 시스템이 임의로 부여하는 숫자로만 구성된다. 이 홈페이지에서 사용하는 id 는 사실은 오리지날에서 단지 특정한 숫자아이디에 딸린 필명일 뿐이다. Luke님 버전에서 필명을 사용자를 구별하는 id 로 사용하도록 수정한 것이라, 함부로 건드리기 힘든 부분이다. 예기치 않은 부작용이 발생할 수 있다.
-
sub DoUpdatePrefs {
...
if ($FreeLinks) {
$username =~ s/^\[\[(.+)\]\]/$1/; # Remove [[ and ]] if added
$username = &FreeToNormal($username);
$username =~ s/_/ /g;
}
### 아래 if 문의 처음 네 블럭을 수정한다.
# if ($username eq "") {
# print T('UserName removed.'), '<br>';
# undef $UserData{'username'};
# } elsif ((!$FreeLinks) && (!($username =~ /^$LinkPattern$/))) {
# print Ts('Invalid UserName %s: not saved.', $username), "<br>\n";
# } elsif ($FreeLinks && (!($username =~ /^$FreeLinkPattern$/))) {
# print Ts('Invalid UserName %s: not saved.', $username), "<br>\n";
# } elsif (length($username) > 50) { # Too long
# print T('UserName must be 50 characters or less. (not saved)'), "<br>\n";
if (length($username) < 4) {
print T('UserName must be 4 characters or more. (not saved)'), "<br>\n";
$UserID = 0;
print &ScriptLink("action=editprefs", T('Try Again'));
print &GetCommonFooter();
return;
} elsif ((!$FreeLinks) && (!($username =~ /^$LinkPattern$/))) {
print Ts('Invalid UserName %s: not saved.', $username), "<br>\n";
$UserID = 0;
print &ScriptLink("action=editprefs", T('Try Again'));
print &GetCommonFooter();
return;
} elsif ($FreeLinks && (!($username =~ /^$FreeLinkPattern$/))) {
print Ts('Invalid UserName %s: not saved.', $username), "<br>\n";
$UserID = 0;
print &ScriptLink("action=editprefs", T('Try Again'));
print &GetCommonFooter();
return;
} elsif (length($username) > 50) { # Too long
print T('UserName must be 50 characters or less. (not saved)'), "<br>\n";
$UserID = 0;
print &ScriptLink("action=editprefs", T('Try Again'));
print &GetCommonFooter();
return;
### 여기까지
} else {
print Ts('UserName %s saved.', $username), '<br>';
$UserData{'username'} = $username;
}
...
}
1.18. 로그아웃 직후에 상단메뉴에 여전히 로그아웃 링크가 남아있는 문제 해결
- 로그인한 상태에서 로그아웃 링크를 클릭했을 경우, 로그아웃이 되었다는 말은 나오는데 상단 메뉴에는 여전히 "로그아웃"으로 링크가 존재한다. 이 상태에서 다시 다른 페이지로 가거나 로그아웃 링크를 한 번 더 눌러야만 "로그인"으로 바뀐다.
- 이 문제에 대해 Bab2 님이 /사용자의견 란에 패치를 작성해 주셨는데, 주인장은 사용자ID 에 관한 부분은 될 수 있는 한 건드리지 않으려 한다. 그 이유는 환경설정에서 사용할 수 없는 아이디를 넣었을 때의 처리 문제 해결 섹션에서 언급한 것처럼 사용자ID 의 개념이 오리지널 UseModWiki 와 다르기 때문이다. 따라서, 여기서는 최소한 영향을 덜 미치면서 문제를 해결하는 꽁수를 택했다.
- 부작용: 아직 모름 -_-;
- 문제의 원인은, 처음에 로그아웃 버튼을 클릭하면 logout result 화면이 출력되는데, "메뉴바를 출력하는 시점 이후"에 실제로 로그아웃 동작을 수행한다는 것이다. 즉 메뉴바가 출력되는 순간에는 아직 로그아웃되지 않은 상태이고, 따라서 여전히 로그아웃 버튼이 출력된다. 그렇다고 해서 실제 로그아웃 동작 부분을 메뉴바 출력보다 앞서서 할 경우, 이번에는 본문창의 메세지가 제대로 출력되지 않는다.
- 메뉴바를 출력할 때는, UserID 가 113 또는 112 면 "login" 을, 그렇지 않으면 "logout" 을 출력하게 되어 있다. 따라서 이 패치에서는, logout result 화면에서 상단 메뉴를 출력하기 전에 UserID 를 임시로 113 으로 만들고, 상단 메뉴를 출력한 후에 다시 UserID 값을 복원한 이후 나머지 로그아웃 과정을 수행하도록 한다.
- GetHeader() 함수와 그 안에서 호출되는 모든 함수 안에서 UserID 가 얼마나 사용되느냐에 따라서 부작용의 규모가 달라질 것이다.
- 현재로서는 상단 메뉴 말고는 UserID 에 민감한 동작을 하는 루틴을 찾지 못했다. 특별한 문제는 없을 것이라 희망한다.
-
sub DoLogout {
...
$SetCookie{'rev'} = 1;
### print 문의 앞뒤로 추가한다.
my $tempUserID = $UserID; # 추가
$UserID = "113"; # 추가
print &GetHeader('', T('Logout Results'), '');
$UserID = $tempUserID; # 추가
###
if (($UserID ne "113") && ($UserID ne "112")) {
print Ts('Logout for user ID %s complete.', $UserID);
}
...
}
1.19. 로그인 실패시 상단 메뉴의 잘못된 출력 해결
- 암호를 잘못 넣는 등의 이유로 로그인에 실패했을 경우, 상단 메뉴에 "로그인"이 "로그아웃"으로 바뀌는 문제가 있었다.
- 또 로그인에 실패한 아이디가 관리자 권한을 가지고 있는 아이디일 경우, 상단 메뉴에 "관리" 메뉴가 나타나 버리는 문제가 있었다. (실제로 클릭을 해도 동작하지는 않는다)
- Bab2님의 패치를 적용
- 겸사겸사, 로그인 성공과 실패시에 서로 다른 타이틀이 출력되게 하였다.
-
sub DoLogin {
...
else {
$SetCookie{'id'} = "";
### 다음 두 라인 추가
$UserID = "";
&LoadUserData();
###
}
}
### 다음 print 문과 if 문을 통채로 바꾼다.
# print &GetHeader('', T('Login Results'), '');
#
# if ($success) {
# print Ts('Login for user ID %s complete.', $uid);
# %UserCookie = %SetCookie;
# } else {
# print Ts('Login for user ID %s failed.', $uid);
# %UserCookie = %SetCookie;
# $UserID = "";
# }
if ($success) {
print &GetHeader('', T('Login completed'), '');
print Ts('Login for user ID %s complete.', $uid);
%UserCookie = %SetCookie;
} else {
print &GetHeader('', T('Login failed'), '');
print Ts('Login for user ID %s failed.', $uid);
%UserCookie = %SetCookie;
$UserID = "";
print "<br>" . &ScriptLink("action=login", T('Try Again'));
}
###
...
}
1.20. 이모티콘 패턴 수정
- :Palm 등과 같이 적었을때 ":P" 부분이 이모티콘으로 바뀌어버리는 등의 문제가 있었다.
- PalmWiki 의 jmjeong 님의 패치를 적용
-
sub EmoticonSubst {
...
# 몇몇 곳에 [^A-z] 를 추가한다.
$txt =~ s/\s\^[oO_\-]*\^[;]*/$e2/g;
$txt =~ s/\s-[_]+-[;]*/$e7/g;
$txt =~ s/\so\.O[^A-z]/$e5/g;
$txt =~ s/\s\*\.\*/$e5/g;
$txt =~ s/\s\=\.\=[;]*/$e7/g;
$txt =~ s/\s\:-[sS][^A-z]/$e7/g;
$txt =~ s/\s\:[-]*D[^A-z]/$e2/g;
$txt =~ s/\s\:[-]*\([^A-z]/$e3/g;
$txt =~ s/\s\:[-]*\)[^A-z]/$e4/g;
$txt =~ s/\s\:[-]*[oO][^A-z]/$e5/g;
$txt =~ s/\s\:[-]*[pP][^A-z]/$e6/g;
$txt =~ s/\s\;[-]*\)[^A-z]/$e8/g;
}
return $txt;
}
1.21. Full Link List 버그 수정
- 상단 메뉴의 "링크"를 클릭하면 전체 페이지들의 링크 관계를 볼 수 있는데, 상위페이지 이름이 명시되지 않은 하위페이지들 ("/페이지이름"의 형태) 의 경우 해당 하위페이지가 존재함에도 불구하고 링크 리스트 화면에는 페이지가 없는 것처럼 나오는 문제를 해결
-
sub PrintLinkList {
...
foreach $pagelines (@_) {
@links = ();
### 다음 라인을 교체
# foreach $page (split(' ', $pagelines)) {
my @pages = split(' ', $pagelines);
foreach $page (@pages) {
###
if ($page =~ /\:/) { # URL or InterWiki form
...
} else {
if ($pgExists{$page}) {
$link = &GetPageLink($page);
### 다음 라인 추가
} elsif ($page =~ /^\// && $pgExists{(split ('/',$pages[0]))[0].$page}) {
($link, $extra) = &GetPageLinkText((split ('/',$pages[0]))[0].$page, $page);
###
} else {
$link = $page;
...
}
1.22. GetFullLinkList() 함수의 버그 수정
- 위의 "Full Link List 버그 수정"과 동일한 문제
- "/하위페이지" 형식의 링크의 경우, 페이지가 존재함에도 불구하고 존재하지 않는 것처럼 인식되는 문제 해결
-
sub GetFullLinkList {
...
foreach $link (@links) {
$seen{$link}++;
if (($unique > 0) && ($seen{$link} != 1)) {
next;
}
### 다음 단락을 수정
# if (($exists == 0) && ($pgExists{$link} == 1)) {
# next;
# }
# if (($exists == 1) && ($pgExists{$link} != 1)) {
# next;
# }
my $link2 = $link;
$link2 = (split ('/',$name))[0]."$link" if ($link =~ /^\//);
if (($exists == 0) && ($pgExists{$link2} == 1)) {
next;
}
if (($exists == 1) && ($pgExists{$link2} != 1)) {
next;
}
### 여기까지
if (($search ne "") && !($link =~ /$search/)) {
next;
}
...
}
1.23. goto 매크로 문제 해결
- goto 매크로를 사용할 때, 텍스트 필드를 빈 칸으로 두었을 때 에러가 난다. 또한 Go 버튼을 누르지 않고 엔터를 입력할 경우 제대로 동작하지 않는다
- Bab2님의 패치를 적용
- 빈 칸을 입력하거나, 존재하지 않는 페이지를 입력했을 경우는, $NotFoundPg 환경변수에 지정되어 있는 페이지를 찾아가고, 그 변수가 지정되지 않았다면, $HomePage, 즉 첫화면으로 가게 된다.
-
sub DoBrowseRequest {
...
if ($action eq 'browse') {
if ($FreeLinks && (!-f &GetPageFile($id))) {
$id = &FreeToNormal($id);
}
if (($NotFoundPg ne '') && (!-f &GetPageFile($id))) {
$id = $NotFoundPg;
}
### 추가
if ($id eq '') {
$id = $HomePage;
}
###
&BrowsePage($id) if &ValidIdOrDie($id);
return 1;
...
}
-
sub MacroGoto {
my ($string) = @_;
return
### 아래 단락을 수정
# "<form name=goto><input name=wkl type=text size=10 value=$string>" .
# "<input type=button value=\"" . T('Go') . "\" onclick='javascript:document.location.href=\"$ScriptName?\"+document.goto.wkl.value'>" .
# "</form>";
"<form name=goto><input type=\"hidden\" name=\"action\" value=\"browse\" id=\"hidden-box\">".
"<input name='id' type\text size=10 value=$string>" . " " .
"<input type=submit value=\"". T('Go') . "\">".
"</form>";
###
###############
}