<?_code
{
    use strict;
    use vars qw(%POST %GET $title $body);

    LJ::set_active_crumb('utf8convert');

    $title = "UTF-8 Conversion Page";
    $body = "";

    my @areanames = ('personal','interests','keywords','memories','polls','styles');

    my %areas = (
                 'personal'=>{
                     'des'=>'Personal Information: name, biography, friend groups\' names',
                     'browse'=>\&browse_personals,
                     'save'=>\&save_personals,
                 },

                 'interests'=>{
                     'des'=>'Personal information: interests',
                     'browse'=>\&browse_interests,
                     'save'=>\&save_interests,
                 },

                 'keywords'=>{
                     'des'=>'Picture keywords',
                     'browse'=>\&browse_pickwd,
                     'save'=>\&save_pickwd,
                 },

                 'memories'=>{
                     'des'=>'Text of memory descriptions',
                     'browse'=>\&browse_memories,
                     'save'=>\&save_memories,
                 },

                 'polls'=>{
                     'des'=>'Text of questions/answers for polls you created',
                     'browse'=>\&browse_polls,
                     'save'=>\&save_polls,
                 },

                 'styles'=>{
                     'des'=>'Text of styles and overrides belonging to you',
                     'browse'=>\&browse_styles,
                     'save'=>\&save_styles,
                 },
                 );


    unless ($LJ::UNICODE) {
        $body .= "<?h1 Not Supported h1?><?p This installation of LiveJournal does not support Unicode and therefore visiting this page is useless. p?>";
        return;
    }

    my $remote = LJ::get_remote();
    unless ($remote) {
        $body .= "<?h1 Login first h1?><?p To convert existing information to UTF-8 you must first <a href=\"/login.bml?ret=1\">login</a>. p?>";
        return;
    }

    my $authas = $GET{'authas'} || $remote->{'user'};
    my $u = LJ::get_authas_user($authas);
    unless ($u) {
        $body .= LJ::bad_input($ML{'error.invalidauth'});
        return;
    }

    # extra arguments for get requests
    my $getextra = $authas ne $remote->{'user'} ? "?authas=$authas" : '';
    my $getextra_amp = $getextra ? "&amp;authas=$authas" : '';

    my $dbcm = LJ::get_cluster_master($u);
    my $dbh = LJ::get_db_writer();
    my $sth;

    # avva, kinda improper usage of load_codes, but works i guess -brad
    LJ::load_codes({ "encname" => \%LJ::CACHE_ENCNAMES } )
        unless %LJ::CACHE_ENCNAMES;
    LJ::load_codes({ "encoding" => \%LJ::CACHE_ENCODINGS } )
        unless %LJ::CACHE_ENCODINGS;

    # check arguments. There are three: mode, area, encid
    my $mode = $POST{'mode'} || $GET{'mode'};
    my $area = $POST{'area'} || $GET{'area'};
    my $encid = ($POST{'encid'} || $GET{'encid'}) + 0;

    # authas switcher form
    $body .= "<form method='get' action='utf8convert.bml'>\n";
    $body .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n";
    $body .= "</form>\n\n";

    $mode = 'overview' unless defined $mode;
    if ( ($mode =~ m/^save.*/) && !$encid) {
        $body .= "<?h1 Encoding not defined h1?><?p Cannot save converted data without encoding information. p?>";
        return;
    }

    if ($mode eq 'overview') {
        $body .= "<?h1 What is this page for? h1?><?p This page is useful to those users who have maintained their journals since before LiveJournal switched to Unicode. LiveJournal's switch to Unicode means that all information that users submit to LiveJournal, including their entries, comments, bios, interests, etc. - all of this is stored internally in the UTF-8 encoding of the Unicode standard, which allows multiple languages and scripts to coexist within the same text. p?>";
        $body .= "<?p However, the switch to Unicode also means that all prior information already stored in the database that is not in pure ASCII form must be augmented with information about the encoding it was submitted in. This information is known to the user who wrote that data - you - but not LiveJournal. p?>";
        $body .= "<?p Entries and comments, which form the bulk of information stored inside LiveJournal's databases, are converted to UTF-8 on-the-fly using encoding information that you specify on the <a href=\"editinfo.bml\"><b>Personal Info</b></a> page. However, various types of miscellaneous information, such as picture keywords, your name, names of your friend groups, your interests, etc. must be explicitly converted. And this is the purpose of this page. p?>";
        $body .= "<?p <b>If your journal is written in English, you always use English for communication in LiveJournal and never use even accent symbols of other West European languages, you do not need to use this page.</b> p?>";

        $body .= "<?hr?>";
        if ($u->{'oldenc'}) {
            $body .= "<?h1 Mass Conversion h1?><?p We detect that you have defined the \"old encoding\" value of <b>$LJ::CACHE_ENCNAMES{$u->{'oldenc'}}</b> on your personal info page. You can choose to mass-convert all your miscellaneous information to UTF-8 under the assumption that it is all stored in this encoding. <b>Do not</b> choose this option if you might have used some other encoding in the past (anywhere besides your entries and comments) while using LiveJournal. If you are not sure, use the <b>Conversion by Area</b> option below. p?>";

            $body .= "<?p <form method='post' action='utf8convert.bml$getextra'>\n";
            $body .= "<input type=hidden name=mode value='saveall'>\n";
            $body .= "<input type=hidden name=encid value='" . $u->{'oldenc'} . "'>\n";
            $body .= "<input type=submit value='Yes, mass-convert all my information!'>";
            $body .= "</form> p?><?hr?>";
        }

        $body .= "<?h1 Conversion by Area h1?><?p We have defined several areas of information that you might have stored in the past in non-ASCII encodings, and which therefore needs to be converted. You may visit each area in turn and see how the information you stored looks in various encodings, then choose the correct one and convert it to UTF-8. p?>";
        $body .= "<?p Available areas are: p?>";
    
        unless ($encid) { 
            $encid = ($u->{'oldenc'} ? $u->{'oldenc'} : '1'); 
        };

        foreach (@areanames) {
            $body .= "<?p <b><a href=\"utf8convert.bml?mode=browse&amp;encid=$encid&amp;area=$_$getextra_amp\">$areas{$_}->{'des'}</a></b> p?>";
        }

    }

    if ($mode eq 'browse') {
        # need to display the data in given encoding, if it is not UTF-8
        $body .= "<?h1 Browse h1?><?p You are browsing the area <br /><b>$areas{$area}->{'des'}</b>: p?>";
        my $browse = $areas{$area}->{'browse'};
        my ($valid, $disp) = $browse->($u, $encid);
        if ($valid && !defined($GET{'forceview'})) {
            $body .= "<?h1 No unconverted information h1?><?p There is no information in this area that is not valid UTF-8. Nothing needs to be done here. p?>";
            $body .= "<?p You can <b><a href=\"utf8convert.bml$getextra\">return to the area list</a></b> or <b><a href=\"utf8convert.bml?mode=browse&area=$area&encid=$encid&forceview=1$getextra_amp\">force the information to be shown anyway</a></b>. p?>";
        } else {
            $body .= "<?h1 Information needs to be converted h1?>";
            $body .= "<?p Below your information is shown in the encoding <b>$LJ::CACHE_ENCNAMES{$encid}</b>. If it appears correct, press Save to convert and store it in the database. If some or all characters are displayed corrupted, you probably should choose another encoding from the list below and press Browse to see it displayed in that encoding. p?>";
            $body .= "<?hr?>";
            $body .= $disp;
            $body .= "<?hr?>";

            $body .= "<?h1 Save h1?><?p <form method='post' action='utf8convert.bml$getextra'>\n";
            $body .= "<input type=hidden name=mode value='save'>\n";
            $body .= "<input type=hidden name=area value=$area>\n";
            $body .= "<input type=hidden name=encid value='$encid'>\n";
            $body .= "<input type=submit value='Yes, save this text as in this encoding.'>";
            $body .= "</form> p?>";

            $body .= "<?h1 Choose Another h1?><?p <form method='post' action='utf8convert.bml$getextra'>\n";
            $body .= "<input type=hidden name=mode value='browse'>\n";
            $body .= "<input type=hidden name=area value=$area>\n";
            $body .= LJ::html_select({'name'=>'encid', 'selected'=>$encid}, %LJ::CACHE_ENCNAMES);
            $body .= "<input type=submit value='Browse in different encoding.'>";
            $body .= "</form> p?>";

            $body .= "<?p You can also <b><a href=\"utf8convert.bml$getextra\">go back to the area list</a></b>. p?>";
        };
    }

    if ($mode eq 'save') {
        $body .= "<?h1 Save h1?><?p You chose to save the area p?><p align=center><b>$areas{$area}->{'des'}</b></p><?p with the encoding value <b>$LJ::CACHE_ENCNAMES{$encid}</b>. p?>";
        $body .= "<?p What this means, precisely, is that all text in that area which is not already in the UTF-8 format will be converted to UTF-8 under the assumption that currently it is stored in the encoding <b>$LJ::CACHE_ENCNAMES{$encid}</b> (the technical name of which is <b>$LJ::CACHE_ENCODINGS{$encid}</b>). If you chose a wrong encoding, the text will display incorrectly after the conversion. p?>";
        $body .= "<?p Are you sure you want to proceed with this operation? p?>";
        
        $body .= "<?p <form method='post' action='utf8convert.bml$getextra'>\n";
        $body .= "<input type=hidden name=mode value='save_do'>\n";
        $body .= "<input type=hidden name=area value=$area>\n";
        $body .= "<input type=hidden name=encid value='$encid'>\n";
        $body .= "<input type=submit value='Yes, proceed to save.'>";
        $body .= "</form>";
        $body .= "<form method='post' action='utf8convert.bml$getextra'>\n";
        $body .= "<input type=submit value='No, go back to the area list.'>";
        $body .= "</form> p?>";
    }

    if ($mode eq 'saveall') {
        $body .= "<?h1 Save All h1?><?p You chose to save all the miscellaneous information available with the encoding value <b>$LJ::CACHE_ENCNAMES{$encid}</b>. p?>";
        $body .= "<?p What this means, precisely, is that all text you have ever submitted to LiveJournal, except actual entries and comments, that is not already in the UTF-8 format will be converted to UTF-8 under the assumption that currently it is stored in the encoding <b>$LJ::CACHE_ENCNAMES{$encid}</b> (the technical name of which is <b>$LJ::CACHE_ENCODINGS{$encid}</b>). If you chose a wrong encoding, the text will display incorrectly after the conversion. p?>";
        $body .= "<?p Are you sure you want to proceed with this operation? p?>";
        $body .= "<?p <form method='post' action='utf8convert.bml$getextra'>\n";
        $body .= "<input type=hidden name=mode value='saveall_do'>\n";
        $body .= "<input type=hidden name=area value=$area>\n";
        $body .= "<input type=hidden name=encid value='$encid'>\n";
        $body .= "<input type=submit value='Yes, proceed to save.'>";
        $body .= "</form>";
        $body .= "<form method='post' action='utf8convert.bml$getextra'>\n";
        $body .= "<input type=submit value='No, go back to the area list.'>";
        $body .= "</form> p?>";
    }

    if ($mode eq 'save_do') {
        $body .= "<?h1 Saving h1?><?p Attempting to convert the area <br /><b>$areas{$area}->{'des'}</b>... p?>";
        my $save = $areas{$area}->{'save'};
        my ($success, $message) = $save->($u, $encid);
        if ($success) {
            $body .= "<?h1 Success h1?><?p Converted successfully. p?>";
            $body .= $message;
        } else {
            $body .= "<?h1 Error h1?><?p There was an error during the conversion. $message p?>";
        }
    }

    if ($mode eq 'saveall_do') {
        $body .= "<?h1 Saving h1?><?p Attempting to convert everything... p?>";
        foreach (@areanames) {
            $body .= "<?p Trying to convert <b>$areas{$_}->{'des'}</b>... p?>";
            my $save = $areas{$_}->{'save'};
            my ($success, $message) = $save->($u, $encid);
            if ($success) {
                $body .= "<?h1 Success h1?><?p Converted successfully. p?>";
                $body .= $message;
            } else {
                $body .= "<?h1 Error h1?><?p There was an error during the conversion. $message p?>";
            }
        }
    }

    return;

    sub browse_personals {
        my ($u, $encid) = @_;

        my $ret = "";
        my ($name, $bio, $groups);

        LJ::load_user_props($u, qw(url urlname));
        $name = $u->{'name'};
        if ($u->{'has_bio'} eq "Y") {
            $bio = $dbcm->selectrow_array("SELECT bio FROM userbio WHERE userid=$u->{'userid'}");
        };
        $groups = "";
        $sth = $dbh->prepare("SELECT groupname FROM friendgroup WHERE userid=$u->{'userid'}");
        $sth->execute;
        while (($_) = $sth->fetchrow_array) {
            $groups .= $_ . ' ';
        };

        my $valid = LJ::is_utf8($name . ' ' . $u->{'url'} . ' ' . $u->{'urlname'} . ' ' . $bio . ' ' . $groups);

        convert(\$name, $encid);
        convert(\$u->{'url'}, $encid);
        convert(\$u->{'urlname'}, $encid);
        convert(\$bio, $encid) if $bio;
        convert(\$groups, $encid);

        $ret = "<b>Name:</b> $name<br />";
        $ret .= "<b>Website URL:</b> $u->{'url'}<br />";
        $ret .= "<b>URL name:</b> $u->{'urlname'}<br />";
        $ret .= "<b>Bio:</b> $bio<br />" if $bio;
        $ret .= "<b>Names of friend groups:</b> $groups<br />";
        return $valid, $ret;
    }

    sub browse_interests {
        my ($u, $encid) = @_;
        my $ret = "";
        my $interests = "";
        my $sth = $dbh->prepare("SELECT i.interest FROM interests i, userinterests ui WHERE i.intid=ui.intid AND ui.userid=$u->{'userid'}");
        $sth->execute;
        while($_ = $sth->fetchrow_array) {
            $interests .= $_ . ' ';
        }

        my $valid = LJ::is_utf8($interests);

        convert(\$interests, $encid);

        $ret = "<b>Interests:</b> $interests<br />";
        return $valid, $ret;
    }

    sub browse_pickwd {
        my ($u, $encid) = @_;
        my $ret = "";
        my $kwds = "";
        my $sth = $dbh->prepare("SELECT k.keyword FROM keywords k, userpicmap up WHERE k.kwid=up.kwid AND up.userid=$u->{'userid'}");
        $sth->execute;
        while($_ = $sth->fetchrow_array) {
            $kwds .= $_ . ' ';
        }

        my $valid = LJ::is_utf8($kwds);
        
        convert(\$kwds, $encid);

        $ret = "<b>Picture keywords:</b> $kwds<br />";
        return $valid, $ret;
    }

    sub browse_polls {
        my ($u, $encid) = @_;
        my $sth;
        my $ret = "";
        my $valid = 1;

        # first get some of the pollids of this user
        my @pollids;
        $sth = $dbh->prepare("SELECT pollid FROM poll WHERE posterid=$u->{'userid'} ".
                             "LIMIT 50");
        $sth->execute;
        while (my ($pid) = $sth->fetchrow_array) {
            push @pollids, $pid;
        }
        unless (@pollids) {
            $ret .= "You have no polls defined.";
            return 1, $ret;
        }
        my $pids = join(',', @pollids);

        my @strings; my $limit = 5; my $nlimit = 10;
        $sth = $dbh->prepare("SELECT name FROM poll WHERE pollid IN ($pids)");
        $sth->execute;
        while (my ($name) = $sth->fetchrow_array) {
            push @strings, $name if LJ::is_utf8($name) and --$limit >=0;
            push @strings, $name if !LJ::is_utf8($name) and --$nlimit >=0;
            $valid = 0 unless LJ::is_utf8($name);
        }
        $ret .= "<?p <b>Sample poll names:</b> p?><?p ";
        foreach (@strings) { convert(\$_, $encid); $ret .= $_ . "<br />"; }
        $ret .= "p?>";
        
        $limit = 5; $nlimit = 10; @strings = ();
        $sth = $dbh->prepare("SELECT qtext FROM pollquestion WHERE pollid IN ($pids)");
        $sth->execute;
        while (my ($question) = $sth->fetchrow_array) {
            push @strings, $question if LJ::is_utf8($question) and --$limit >=0;
            push @strings, $question if !LJ::is_utf8($question) and --$nlimit >=0;
            $valid = 0 unless LJ::is_utf8($question);
        }
        $ret .= "<?p <b>Sample poll questions:</b> p?><?p ";
        foreach (@strings) { convert(\$_, $encid); $ret .= $_ . "<br />"; }
        $ret .= "p?>";
        
        $limit = 5; $nlimit = 10; @strings = ();
        $sth = $dbh->prepare("SELECT item FROM pollitem WHERE pollid IN ($pids)");
        $sth->execute;
        while (my ($item) = $sth->fetchrow_array) {
            push @strings, $item if LJ::is_utf8($item) and --$limit >=0;
            push @strings, $item if !LJ::is_utf8($item) and --$nlimit >=0;
            $valid = 0 unless LJ::is_utf8($item);
        }
        $ret .= "<?p <b>Sample poll answer choices:</b> p?><?p ";
        foreach (@strings) { convert(\$_, $encid); $ret .= $_ . "<br />"; }
        $ret .= "p?>";
        
        $limit = 5; $nlimit = 10; @strings = ();
        $sth = $dbh->prepare("SELECT value FROM pollresult WHERE pollid IN ($pids)");
        $sth->execute;
        while (my ($res) = $sth->fetchrow_array) {
            push @strings, $res if LJ::is_utf8($res) and --$limit >=0;
            push @strings, $res if !LJ::is_utf8($res) and --$nlimit >=0;
            $valid = 0 unless LJ::is_utf8($res);
        }
        $ret .= "<?p <b>Sample poll answers:</b> p?><?p ";
        foreach (@strings) { convert(\$_, $encid); $ret .= $_ . "<br />"; }
        $ret .= "p?>";
        
        return $valid, $ret;
    }
    
    sub browse_styles {
        my ($u, $encid) = @_;
        my $ret = "";
        my $anystyles = 0;
        my $valid = 1;
        
        my $sth = $dbh->prepare("SELECT styleid, styledes, formatdata FROM style WHERE user=?");
        $sth->execute($u->{'user'});
        while (my ($styleid, $styledes, $fdata) = $sth->fetchrow_array) {
            $anystyles = 1;
            $valid = 0 unless LJ::is_utf8($styledes) && LJ::is_utf8($fdata);
            my $utfdata = LJ::is_utf8($fdata);
            convert(\$styledes, $encid);
            convert(\$fdata, $encid);
            
            $ret .= "<?p <b>Style number:</b> $styleid<br />";
            $ret .= "<b>Description:</b> $styledes<br />";
            if ($utfdata) {
                $ret .= "<b>Format data:</b> valid UTF-8<br />";
            } else {
                $ret .= "<b>Format data:</b> contains non-Unicode characters (too large to display)<br />";
            }
            $ret .= "p?>";
        }
        unless ($anystyles) { $ret .= "<?p You have no styles defined. p?>"; }
        
        my ($overrides) = $dbh->selectrow_array("SELECT override FROM overrides WHERE user=?", undef, $u->{'user'});
        if ($overrides) {
            $valid = 0 unless LJ::is_utf8($overrides);
            convert(\$overrides, $encid);
            $ret .= "<?p Overrides: p?>";
            $ret .= "<?p $overrides p?>";
        } else { $ret .= "<?p You have no overrides defined. p?>"; }
        
        return $valid, $ret;
    }
    
    sub browse_memories {
        my ($u, $encid) = @_;
        my $ret = "";
        my $valid = 1;
        
        $ret .= "<?p Keywords used in memories: p?><?p ";
        my $kwds = LJ::Memories::get_keywords($u);
        foreach my $kw (values %{$kwds || {}}) {
            $valid = 0 unless LJ::is_utf8($kw);
            convert(\$kw, $encid);
            $ret .= $kw . ' ';
        }
        $ret .= " p?>";
        $ret .= "<?p Sample of memory decriptions: p?><?p ";
        my $memories = LJ::Memories::get_by_user($u);
        my $limit = 15;
        foreach my $memory (values %{$memories || {}}) {
            my $des = $memory->{des};
            $valid = 0 unless LJ::is_utf8($des);
            convert(\$des, $encid);
            $ret .= $des . "<br />" if --$limit >= 0;
        }
        $ret .= " p?>";
        
        return $valid, $ret;
    }
    
    sub save_personals {
        my ($u, $encid) = @_;
        my $success = 1;
        my $message = "";
        my $sth;
        
        my ($name, $bio, $groups);
        my $userid = $u->{'userid'};
        
        # convert name
        $name = $u->{'name'};
        unless (LJ::is_utf8($name)) {
            convert(\$name, $encid);
            LJ::update_user($userid, { name => $name });
            $message .= "<?p Converted the name. p?>";
        }
        
        # convert url/urlname
        LJ::load_user_props($u, qw(url urlname));
        foreach my $prop (qw(url urlname)) {
            unless(LJ::is_utf8($u->{$prop})) {
                convert(\$u->{$prop}, $encid);
                LJ::set_userprop($u->{'userid'}, $prop, $u->{$prop});
                $message .= "<?p Converted userprop: $prop . p?>";
            }
        }
        
        # convert bio
        if ($u->{'has_bio'} eq "Y") {
            $bio = $dbcm->selectrow_array("SELECT bio FROM userbio WHERE userid=$userid");
            unless (LJ::is_utf8($bio)) {
                convert(\$bio, $encid);
                $u->do("UPDATE userbio SET bio=? WHERE userid=$userid", undef, $bio);
                if ($u->err) {
                    return 0, "Database error: " . $u->errstr;
                }
                LJ::MemCache::delete([$userid, "bio:$userid"]);
                $message .= "<?p Converted the bio. p?>";
            }
        }
        
        # convert groups
        $groups = {};
        $sth = $dbh->prepare("SELECT groupnum, groupname FROM friendgroup WHERE userid=$userid ORDER BY sortorder");
        $sth->execute;
        if ($dbh->err) {
            return 0, ("Database error: " . $dbh->errstr);
        }
        
        while ($_ = $sth->fetchrow_hashref) {
            $groups->{$_->{'groupnum'}} = $_->{'groupname'};
        }
        
        my $converted_groups = 0;
        
        foreach (keys %$groups) {
            unless(LJ::is_utf8($groups->{$_})) {
                my $name = $groups->{$_};
                convert(\$name, $encid);
                $dbh->do("UPDATE friendgroup SET groupname=? WHERE userid=$userid AND groupnum=$_", undef, $name);
                if ($dbh->err) {
                    return 0, "Database error: $dbh->errstr";
                }
                $converted_groups = 1;
            }
        }
        if ($converted_groups) {
            $message .= "<?p Converted friend groups. p?>";
        }
        
        return $success, $message;
    }
    
    sub save_interests {
        my ($u, $encid) = @_;
        my $success = 1;
        my $message = "";
        my $sth;
        
        $sth = $dbh->prepare("SELECT i.interest, i.intid FROM interests i, userinterests ui ".
                             "WHERE i.intid=ui.intid AND ui.userid=$u->{'userid'}");
        $sth->execute;
        my %interests = ();
        while ($_ = $sth->fetchrow_hashref) {
            $interests{$_->{'interest'}} = $_->{'intid'};
        }
        my @ints;
        my $changed = 0;
        foreach(keys %interests) {
            unless (LJ::is_utf8($_)) {
                convert(\$_, $encid);
                $changed = 1;
            }
            push @ints, $_;
        }
        if ($changed) {
            LJ::set_interests($u, \%interests, \@ints);
          }
        
        $message = "Converted interests" if $changed;
        
        return 1, $message;
    } 
    
    sub save_pickwd {
        my ($u, $encid) = @_;
        my $success = 1;
        my $message = "";
        my $sth;
        my $userid = $u->{'userid'};
        
        my %kwds;
        
        my $sth = $dbh->prepare("SELECT k.keyword, k.kwid FROM keywords k, userpicmap up ".
                                "WHERE k.kwid=up.kwid AND up.userid=$userid");
        $sth->execute;
        while($_ = $sth->fetchrow_hashref) {
            $kwds{$_->{'keyword'}} = $_->{'kwid'};
        }
        my $changed = 0;
        foreach my $keyword (keys %kwds) {
            next if LJ::is_utf8($keyword);
            $changed = 1;
            my $kw = $keyword;
            convert(\$kw, $encid);
            my $newid = LJ::get_keyword_id($kw);
            $dbh->do("UPDATE userpicmap SET kwid=$newid WHERE userid=$userid AND kwid=$kwds{$keyword}");
        }
        if ($changed) {
            $message = "<?p Converted picture keywords. p?>";
        }
        return 1, $message;
    }
    
    sub save_polls {
        my ($u, $encid) = @_;
        my $success = 1;
        my $message = "";
        my $sth;
        my $changed = 0;
        
        # convert poll names
        my @pollids;
        $sth = $dbh->prepare("SELECT pollid, name FROM poll WHERE posterid=$u->{'userid'}");
        $sth->execute;
        while (my ($pid,$name) = $sth->fetchrow_array) {
            push @pollids, $pid;
            next if LJ::is_utf8($name);
            convert(\$name, $encid);
            my $qname = $dbh->quote($name);
            $dbh->do("UPDATE poll SET name=$qname WHERE pollid=$pid");
            $changed = 1;
        }
        if ($changed) {
            $message .= "<?p Converted poll names. p?>";
        }
        
        my $pids = join(',', @pollids);
        
        # convert poll questions
        $changed = 0;
        $sth = $dbh->prepare("SELECT pollid, pollqid, qtext FROM pollquestion WHERE pollid IN ($pids)");
        $sth->execute;
        while (my ($pid, $pqid, $text) = $sth->fetchrow_array) {
            next if LJ::is_utf8($text);
            convert(\$text, $encid);
            my $qtext = $dbh->quote($text);
            $dbh->do("UPDATE pollquestion SET qtext=$qtext WHERE pollid=$pid AND pollqid=$pqid");
            $changed = 1;
        }
        if ($changed) {
            $message .= "<?p Converted poll questions. p?>";
        }
        
        # convert poll items
        $changed = 0;
        $sth = $dbh->prepare("SELECT pollid, pollqid, pollitid, item FROM pollitem WHERE pollid IN ($pids)");
        $sth->execute;
        while (my ($pid, $pqid, $pitid, $item) = $sth->fetchrow_array) {
            next if LJ::is_utf8($item);
            convert(\$item, $encid);
            my $qitem = $dbh->quote($item);
            $dbh->do("UPDATE pollitem SET item=$qitem WHERE pollid=$pid AND pollqid=$pqid AND pollitid=$pitid");
            $changed = 1;
        }
        if ($changed) {
            $message .= "<?p Converted poll items. p?>";
        }
        
        # convert poll results
        $changed = 0;
        $sth = $dbh->prepare("SELECT pollid, pollqid, userid, value FROM pollresult WHERE pollid IN ($pids)");
        $sth->execute;
        while (my ($pid, $pqid, $userid, $res) = $sth->fetchrow_array) {
            next if LJ::is_utf8($res);
            convert(\$res, $encid);
            my $qres = $dbh->quote($res);
            $dbh->do("UPDATE pollresult SET value=$qres WHERE pollid=$pid AND pollqid=$pqid AND userid=$userid");
            $changed = 1;
        }
        if ($changed) {
            $message .= "<?p Converted poll results. p?>";
        }
        
        return 1, $message;
        
    }
    
    sub save_styles {
        my ($u, $encid) = @_;
        my $success = 1;
        my $message = "";
        my $sth;
        my $changed = 0;
        
        my $quser = $dbh->quote($u->{'user'});
        
        my $sth = $dbh->prepare("SELECT styleid, styledes, formatdata FROM style WHERE user=$quser");
        $sth->execute;
        while (my ($styleid, $styledes, $fdata) = $sth->fetchrow_array) { 
            next if LJ::is_utf8($styledes) && LJ::is_utf8($fdata);
            convert(\$styledes, $encid);
            convert(\$fdata, $encid);
            my $newdes = $dbh->quote($styledes);
            my $newdata = $dbh->quote($fdata);
            $dbh->do("UPDATE style SET styledes=$newdes, formatdata=$newdata WHERE styleid=$styleid");
            $changed =1;
        }
        if ($changed) {
            $message .= "<?p Converted styles. p?>";
        }
        
        my ($overrides) = $dbh->selectrow_array("SELECT override FROM overrides WHERE user=$quser");
        if ($overrides && !LJ::is_utf8($overrides)) {
            convert(\$overrides, $encid);
            my $qoverrides = $dbh->quote($overrides);
            $dbh->do("UPDATE overrides SET override=$qoverrides WHERE user=$quser");
            $message .= "<?p Converted overrides. p?>";
        }
        
        return 1, $message;
    }
    
    sub save_memories {
        my ($u, $encid) = @_;
        my $success = 1;
        my $message = "";
        my $changed = 0;
        my $userid = $u->{'userid'};
        
        my $keywords = LJ::Memories::get_keywords($u);
        my %kwds = ( map { $keywords->{$_} => $_ } keys %{$keywords || {}} );
        foreach my $keyword (keys %kwds) {
            next if LJ::is_utf8($keyword);
            $changed = 1;
            my $kw = $keyword;
            convert(\$kw, $encid);
            my $newid = LJ::get_keyword_id($u, $kw);

            # not an API because this is the only place this happens, and it's very rare
            if ($u->{dversion} > 5) {
                $u->do("UPDATE memkeyword2 SET kwid = ? WHERE userid = ? kwid = ?",
                       undef, $newid, $u->{userid}, $kwds{$keyword});
            } else {
                $dbh->do("UPDATE memkeyword SET kwid=$newid WHERE kwid=$kwds{$keyword}");
            }
        }
        if ($changed) {
            $message .= "<?p Converted memory keywords. p?>";
        }
        
        # now the memory descriptions
        $changed = 0;
        my $memories = LJ::Memories::get_by_user($u);
        foreach my $memory (values %{$memories || {}}) {
            my $des = $memory->{des};
            next if LJ::is_utf8($des);
            $changed = 1;
            convert(\$des, $encid);
            LJ::Memories::update_memory($u, $memory->{memid}, { des => $des });
        }
        if ($changed) {
            $message .= "<?p Converted memory descriptions. p?>";
        }
        
        return 1, $message;
    }
    
    sub convert {
        my ($rtext, $encid) = @_;
        if ($encid && !LJ::is_utf8($$rtext)) {
            my $enc = $LJ::CACHE_ENCODINGS{$encid};
            unless (lc($enc) eq "utf-8") {
                $$rtext = Unicode::MapUTF8::to_utf8({-string=>$$rtext, -charset=>$enc});
            }
            LJ::text_out($rtext);
        }
    }

}
_code?><?page
title=><?_code return $title; _code?>
body=><?_code return $body; _code?>
page?>
