Mercurial > pidgin
changeset 24108:1bb3f2345f99
merge of '5316525f53e27f838d18a6a08b82c7d55f674591'
and '6d53778240fe04225c89fcd3495e89facc71bee5'
author | SHiNE CsyFeK <csyfek@gmail.com> |
---|---|
date | Fri, 12 Sep 2008 14:26:41 +0000 |
parents | d4e0b7c484b1 (diff) 71fecd0f4ce6 (current diff) |
children | a5838e21ddf6 |
files | pidgin/artwork/art-tools/clean-svg-definitions.sh pidgin/artwork/art-tools/render-pidgin-emotes.rb pidgin/artwork/hicolor/16x16/actions/pidgin-change-bgcolor.png pidgin/artwork/hicolor/16x16/actions/pidgin-change-fgcolor.png pidgin/artwork/hicolor/16x16/actions/pidgin-drag-down.png pidgin/artwork/hicolor/16x16/actions/pidgin-drag-left.png pidgin/artwork/hicolor/16x16/actions/pidgin-drag-right.png pidgin/artwork/hicolor/16x16/actions/pidgin-drag-up.png pidgin/artwork/hicolor/16x16/actions/pidgin-emote-select.png pidgin/artwork/hicolor/16x16/actions/pidgin-font-face.png pidgin/artwork/hicolor/16x16/actions/pidgin-font-size-down.png pidgin/artwork/hicolor/16x16/actions/pidgin-font-size-up.png pidgin/artwork/hicolor/16x16/actions/pidgin-get-attention.png pidgin/artwork/hicolor/16x16/actions/pidgin-insert-image.png pidgin/artwork/hicolor/16x16/actions/pidgin-insert-link.png pidgin/artwork/hicolor/16x16/actions/pidgin-insert.png pidgin/artwork/hicolor/16x16/actions/pidgin-message-new.png pidgin/artwork/hicolor/16x16/actions/pidgin-send-file.png pidgin/artwork/hicolor/16x16/actions/pidgin-unblock.png pidgin/artwork/hicolor/16x16/actions/pidgin-view-plugins.png pidgin/artwork/hicolor/16x16/actions/pidgin-view-transfers.png pidgin/artwork/hicolor/16x16/animations/process-working0.png pidgin/artwork/hicolor/16x16/animations/process-working1.png pidgin/artwork/hicolor/16x16/animations/process-working10.png pidgin/artwork/hicolor/16x16/animations/process-working11.png pidgin/artwork/hicolor/16x16/animations/process-working12.png pidgin/artwork/hicolor/16x16/animations/process-working13.png pidgin/artwork/hicolor/16x16/animations/process-working14.png pidgin/artwork/hicolor/16x16/animations/process-working15.png pidgin/artwork/hicolor/16x16/animations/process-working16.png pidgin/artwork/hicolor/16x16/animations/process-working17.png pidgin/artwork/hicolor/16x16/animations/process-working18.png pidgin/artwork/hicolor/16x16/animations/process-working19.png pidgin/artwork/hicolor/16x16/animations/process-working2.png pidgin/artwork/hicolor/16x16/animations/process-working20.png pidgin/artwork/hicolor/16x16/animations/process-working21.png pidgin/artwork/hicolor/16x16/animations/process-working22.png pidgin/artwork/hicolor/16x16/animations/process-working23.png pidgin/artwork/hicolor/16x16/animations/process-working24.png pidgin/artwork/hicolor/16x16/animations/process-working25.png pidgin/artwork/hicolor/16x16/animations/process-working26.png pidgin/artwork/hicolor/16x16/animations/process-working27.png pidgin/artwork/hicolor/16x16/animations/process-working28.png pidgin/artwork/hicolor/16x16/animations/process-working29.png pidgin/artwork/hicolor/16x16/animations/process-working3.png pidgin/artwork/hicolor/16x16/animations/process-working30.png pidgin/artwork/hicolor/16x16/animations/process-working4.png pidgin/artwork/hicolor/16x16/animations/process-working5.png pidgin/artwork/hicolor/16x16/animations/process-working6.png pidgin/artwork/hicolor/16x16/animations/process-working7.png pidgin/artwork/hicolor/16x16/animations/process-working8.png pidgin/artwork/hicolor/16x16/animations/process-working9.png pidgin/artwork/hicolor/16x16/animations/typing0.png pidgin/artwork/hicolor/16x16/animations/typing1.png pidgin/artwork/hicolor/16x16/animations/typing2.png pidgin/artwork/hicolor/16x16/animations/typing3.png pidgin/artwork/hicolor/16x16/animations/typing4.png pidgin/artwork/hicolor/16x16/animations/typing5.png pidgin/artwork/hicolor/16x16/apps/pidgin-aim.png pidgin/artwork/hicolor/16x16/apps/pidgin-bonjour.png pidgin/artwork/hicolor/16x16/apps/pidgin-facebook.png pidgin/artwork/hicolor/16x16/apps/pidgin-gadu-gadu.png pidgin/artwork/hicolor/16x16/apps/pidgin-google-talk.png pidgin/artwork/hicolor/16x16/apps/pidgin-icq.png pidgin/artwork/hicolor/16x16/apps/pidgin-irc.png pidgin/artwork/hicolor/16x16/apps/pidgin-jabber.png pidgin/artwork/hicolor/16x16/apps/pidgin-meanwhile.png pidgin/artwork/hicolor/16x16/apps/pidgin-msn.png pidgin/artwork/hicolor/16x16/apps/pidgin-myspace.png pidgin/artwork/hicolor/16x16/apps/pidgin-novell.png pidgin/artwork/hicolor/16x16/apps/pidgin-qq.png pidgin/artwork/hicolor/16x16/apps/pidgin-silc.png pidgin/artwork/hicolor/16x16/apps/pidgin-simple.png pidgin/artwork/hicolor/16x16/apps/pidgin-yahoo.png pidgin/artwork/hicolor/16x16/apps/pidgin-zephyr.png pidgin/artwork/hicolor/16x16/apps/pidgin.png pidgin/artwork/hicolor/16x16/devices/pidgin-hiptop.png pidgin/artwork/hicolor/16x16/devices/pidgin-mobile.png pidgin/artwork/hicolor/16x16/emblems/pidgin-aol-client.png pidgin/artwork/hicolor/16x16/emblems/pidgin-birthday.png pidgin/artwork/hicolor/16x16/emblems/pidgin-blocked.png pidgin/artwork/hicolor/16x16/emblems/pidgin-bot.png pidgin/artwork/hicolor/16x16/emblems/pidgin-external.png pidgin/artwork/hicolor/16x16/emblems/pidgin-female.png pidgin/artwork/hicolor/16x16/emblems/pidgin-founder.png pidgin/artwork/hicolor/16x16/emblems/pidgin-free-for-chat.png pidgin/artwork/hicolor/16x16/emblems/pidgin-game.png pidgin/artwork/hicolor/16x16/emblems/pidgin-half-operator.png pidgin/artwork/hicolor/16x16/emblems/pidgin-male.png pidgin/artwork/hicolor/16x16/emblems/pidgin-music.png pidgin/artwork/hicolor/16x16/emblems/pidgin-not-authorized.png pidgin/artwork/hicolor/16x16/emblems/pidgin-operator.png pidgin/artwork/hicolor/16x16/emblems/pidgin-qq-member.png pidgin/artwork/hicolor/16x16/emblems/pidgin-secure.png pidgin/artwork/hicolor/16x16/emblems/pidgin-unavailable.png pidgin/artwork/hicolor/16x16/emblems/pidgin-video.png pidgin/artwork/hicolor/16x16/emblems/pidgin-voice.png pidgin/artwork/hicolor/16x16/status/pidgin-available.png pidgin/artwork/hicolor/16x16/status/pidgin-away.png pidgin/artwork/hicolor/16x16/status/pidgin-busy.png pidgin/artwork/hicolor/16x16/status/pidgin-chatroom.png pidgin/artwork/hicolor/16x16/status/pidgin-contact.png pidgin/artwork/hicolor/16x16/status/pidgin-dialog-auth.png pidgin/artwork/hicolor/16x16/status/pidgin-dialog-error.png pidgin/artwork/hicolor/16x16/status/pidgin-dialog-info.png pidgin/artwork/hicolor/16x16/status/pidgin-dialog-mail.png pidgin/artwork/hicolor/16x16/status/pidgin-dialog-question.png pidgin/artwork/hicolor/16x16/status/pidgin-extended-away.png pidgin/artwork/hicolor/16x16/status/pidgin-invisible.png pidgin/artwork/hicolor/16x16/status/pidgin-offline.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-available.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-away.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-busy.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-extended-away.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-invisible.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-message-pending.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-new-im.png pidgin/artwork/hicolor/16x16/status/pidgin-tray-offline.png pidgin/artwork/hicolor/22x22/apps/pidgin.png pidgin/artwork/hicolor/22x22/status/pidgin-available.png pidgin/artwork/hicolor/22x22/status/pidgin-away.png pidgin/artwork/hicolor/22x22/status/pidgin-busy.png pidgin/artwork/hicolor/22x22/status/pidgin-chatroom.png pidgin/artwork/hicolor/22x22/status/pidgin-contact.png pidgin/artwork/hicolor/22x22/status/pidgin-extended-away.png pidgin/artwork/hicolor/22x22/status/pidgin-invisible.png pidgin/artwork/hicolor/22x22/status/pidgin-offline.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-available.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-away.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-busy.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-extended-away.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-invisible.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-message-pending.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-new-im.png pidgin/artwork/hicolor/22x22/status/pidgin-tray-offline.png pidgin/artwork/hicolor/24x24/apps/pidgin-aim.png pidgin/artwork/hicolor/24x24/apps/pidgin-bonjour.png pidgin/artwork/hicolor/24x24/apps/pidgin-facebook.png pidgin/artwork/hicolor/24x24/apps/pidgin-gadu-gadu.png pidgin/artwork/hicolor/24x24/apps/pidgin-google-talk.png pidgin/artwork/hicolor/24x24/apps/pidgin-icq.png pidgin/artwork/hicolor/24x24/apps/pidgin-irc.png pidgin/artwork/hicolor/24x24/apps/pidgin-jabber.png pidgin/artwork/hicolor/24x24/apps/pidgin-meanwhile.png pidgin/artwork/hicolor/24x24/apps/pidgin-msn.png pidgin/artwork/hicolor/24x24/apps/pidgin-myspace.png pidgin/artwork/hicolor/24x24/apps/pidgin-novell.png pidgin/artwork/hicolor/24x24/apps/pidgin-qq.png pidgin/artwork/hicolor/24x24/apps/pidgin-silc.png pidgin/artwork/hicolor/24x24/apps/pidgin-simple.png pidgin/artwork/hicolor/24x24/apps/pidgin-yahoo.png pidgin/artwork/hicolor/24x24/apps/pidgin-zephyr.png pidgin/artwork/hicolor/24x24/apps/pidgin.png pidgin/artwork/hicolor/24x24/emotes/Makefile.am pidgin/artwork/hicolor/24x24/emotes/Makefile.mingw pidgin/artwork/hicolor/24x24/emotes/default.theme.in pidgin/artwork/hicolor/24x24/emotes/none/Makefile.am pidgin/artwork/hicolor/24x24/emotes/none/Makefile.mingw pidgin/artwork/hicolor/24x24/emotes/none/none.theme.in pidgin/artwork/hicolor/24x24/emotes/none/theme pidgin/artwork/hicolor/24x24/emotes/pidgin-act-up.png pidgin/artwork/hicolor/24x24/emotes/pidgin-airplane.png pidgin/artwork/hicolor/24x24/emotes/pidgin-alien.png pidgin/artwork/hicolor/24x24/emotes/pidgin-angel.png pidgin/artwork/hicolor/24x24/emotes/pidgin-angry.png pidgin/artwork/hicolor/24x24/emotes/pidgin-arrogant.png pidgin/artwork/hicolor/24x24/emotes/pidgin-at-wits-end.png pidgin/artwork/hicolor/24x24/emotes/pidgin-bad.png pidgin/artwork/hicolor/24x24/emotes/pidgin-bashful.png pidgin/artwork/hicolor/24x24/emotes/pidgin-beat-up.png pidgin/artwork/hicolor/24x24/emotes/pidgin-beauty.png pidgin/artwork/hicolor/24x24/emotes/pidgin-beer.png pidgin/artwork/hicolor/24x24/emotes/pidgin-blowkiss.png pidgin/artwork/hicolor/24x24/emotes/pidgin-bomb.png pidgin/artwork/hicolor/24x24/emotes/pidgin-bowl.png pidgin/artwork/hicolor/24x24/emotes/pidgin-boy.png pidgin/artwork/hicolor/24x24/emotes/pidgin-brb.png pidgin/artwork/hicolor/24x24/emotes/pidgin-bulgy-eyes.png pidgin/artwork/hicolor/24x24/emotes/pidgin-bunny.png pidgin/artwork/hicolor/24x24/emotes/pidgin-bye.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cake.png pidgin/artwork/hicolor/24x24/emotes/pidgin-call-me.png pidgin/artwork/hicolor/24x24/emotes/pidgin-camera.png pidgin/artwork/hicolor/24x24/emotes/pidgin-can.png pidgin/artwork/hicolor/24x24/emotes/pidgin-car.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cat.png pidgin/artwork/hicolor/24x24/emotes/pidgin-chicken.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cigarette.png pidgin/artwork/hicolor/24x24/emotes/pidgin-clap.png pidgin/artwork/hicolor/24x24/emotes/pidgin-clock.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cloudy.png pidgin/artwork/hicolor/24x24/emotes/pidgin-clover.png pidgin/artwork/hicolor/24x24/emotes/pidgin-clown.png pidgin/artwork/hicolor/24x24/emotes/pidgin-coffee.png pidgin/artwork/hicolor/24x24/emotes/pidgin-coins.png pidgin/artwork/hicolor/24x24/emotes/pidgin-computer.png pidgin/artwork/hicolor/24x24/emotes/pidgin-confused.png pidgin/artwork/hicolor/24x24/emotes/pidgin-console.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cow.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cowboy.png pidgin/artwork/hicolor/24x24/emotes/pidgin-crying.png pidgin/artwork/hicolor/24x24/emotes/pidgin-curl-lip.png pidgin/artwork/hicolor/24x24/emotes/pidgin-curse.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cute.png pidgin/artwork/hicolor/24x24/emotes/pidgin-cyclops.png pidgin/artwork/hicolor/24x24/emotes/pidgin-dance.png pidgin/artwork/hicolor/24x24/emotes/pidgin-dazed.png pidgin/artwork/hicolor/24x24/emotes/pidgin-desire.png pidgin/artwork/hicolor/24x24/emotes/pidgin-devil.png pidgin/artwork/hicolor/24x24/emotes/pidgin-disappointed.png pidgin/artwork/hicolor/24x24/emotes/pidgin-disdain.png pidgin/artwork/hicolor/24x24/emotes/pidgin-doctor.png pidgin/artwork/hicolor/24x24/emotes/pidgin-dog.png pidgin/artwork/hicolor/24x24/emotes/pidgin-doh.png pidgin/artwork/hicolor/24x24/emotes/pidgin-dont-know.png pidgin/artwork/hicolor/24x24/emotes/pidgin-drink.png pidgin/artwork/hicolor/24x24/emotes/pidgin-drool.png pidgin/artwork/hicolor/24x24/emotes/pidgin-eat.png pidgin/artwork/hicolor/24x24/emotes/pidgin-embarrassed.png pidgin/artwork/hicolor/24x24/emotes/pidgin-excruciating.png pidgin/artwork/hicolor/24x24/emotes/pidgin-eyeroll.png pidgin/artwork/hicolor/24x24/emotes/pidgin-female-fighter.png pidgin/artwork/hicolor/24x24/emotes/pidgin-film.png pidgin/artwork/hicolor/24x24/emotes/pidgin-fingers-crossed.png pidgin/artwork/hicolor/24x24/emotes/pidgin-flag.png pidgin/artwork/hicolor/24x24/emotes/pidgin-foot-in-mouth.png pidgin/artwork/hicolor/24x24/emotes/pidgin-freaked-out.png pidgin/artwork/hicolor/24x24/emotes/pidgin-ghost.png pidgin/artwork/hicolor/24x24/emotes/pidgin-giggle.png pidgin/artwork/hicolor/24x24/emotes/pidgin-girl.png pidgin/artwork/hicolor/24x24/emotes/pidgin-glasses-cool.png pidgin/artwork/hicolor/24x24/emotes/pidgin-glasses-nerdy.png pidgin/artwork/hicolor/24x24/emotes/pidgin-go-away.png pidgin/artwork/hicolor/24x24/emotes/pidgin-goat.png pidgin/artwork/hicolor/24x24/emotes/pidgin-good.png pidgin/artwork/hicolor/24x24/emotes/pidgin-hammer.png pidgin/artwork/hicolor/24x24/emotes/pidgin-handcuffs.png pidgin/artwork/hicolor/24x24/emotes/pidgin-handshake.png pidgin/artwork/hicolor/24x24/emotes/pidgin-highfive.png pidgin/artwork/hicolor/24x24/emotes/pidgin-hug-left.png pidgin/artwork/hicolor/24x24/emotes/pidgin-hug-right.png pidgin/artwork/hicolor/24x24/emotes/pidgin-hypnotized.png pidgin/artwork/hicolor/24x24/emotes/pidgin-in-love.png pidgin/artwork/hicolor/24x24/emotes/pidgin-island.png pidgin/artwork/hicolor/24x24/emotes/pidgin-jump.png pidgin/artwork/hicolor/24x24/emotes/pidgin-kiss.png pidgin/artwork/hicolor/24x24/emotes/pidgin-kissed.png pidgin/artwork/hicolor/24x24/emotes/pidgin-kissing.png pidgin/artwork/hicolor/24x24/emotes/pidgin-knife.png pidgin/artwork/hicolor/24x24/emotes/pidgin-lamp.png pidgin/artwork/hicolor/24x24/emotes/pidgin-lashes.png pidgin/artwork/hicolor/24x24/emotes/pidgin-laugh.png pidgin/artwork/hicolor/24x24/emotes/pidgin-liquor.png pidgin/artwork/hicolor/24x24/emotes/pidgin-loser.png pidgin/artwork/hicolor/24x24/emotes/pidgin-love-over.png pidgin/artwork/hicolor/24x24/emotes/pidgin-love.png pidgin/artwork/hicolor/24x24/emotes/pidgin-lying.png pidgin/artwork/hicolor/24x24/emotes/pidgin-mad-tongue.png pidgin/artwork/hicolor/24x24/emotes/pidgin-mail.png pidgin/artwork/hicolor/24x24/emotes/pidgin-male-fighter1.png pidgin/artwork/hicolor/24x24/emotes/pidgin-male-fighter2.png pidgin/artwork/hicolor/24x24/emotes/pidgin-mean.png pidgin/artwork/hicolor/24x24/emotes/pidgin-meeting.png pidgin/artwork/hicolor/24x24/emotes/pidgin-messed.png pidgin/artwork/hicolor/24x24/emotes/pidgin-mobile.png pidgin/artwork/hicolor/24x24/emotes/pidgin-mohawk.png pidgin/artwork/hicolor/24x24/emotes/pidgin-moneymouth.png pidgin/artwork/hicolor/24x24/emotes/pidgin-monkey.png pidgin/artwork/hicolor/24x24/emotes/pidgin-moon.png pidgin/artwork/hicolor/24x24/emotes/pidgin-msn-away.png pidgin/artwork/hicolor/24x24/emotes/pidgin-msn-busy.png pidgin/artwork/hicolor/24x24/emotes/pidgin-msn.png pidgin/artwork/hicolor/24x24/emotes/pidgin-msn_online.png pidgin/artwork/hicolor/24x24/emotes/pidgin-music.png pidgin/artwork/hicolor/24x24/emotes/pidgin-musical-note.png pidgin/artwork/hicolor/24x24/emotes/pidgin-nailbiting.png pidgin/artwork/hicolor/24x24/emotes/pidgin-neutral.png pidgin/artwork/hicolor/24x24/emotes/pidgin-on-the-phone.png pidgin/artwork/hicolor/24x24/emotes/pidgin-party.png pidgin/artwork/hicolor/24x24/emotes/pidgin-peace.png pidgin/artwork/hicolor/24x24/emotes/pidgin-phone.png pidgin/artwork/hicolor/24x24/emotes/pidgin-pig.png pidgin/artwork/hicolor/24x24/emotes/pidgin-pill.png pidgin/artwork/hicolor/24x24/emotes/pidgin-pirate.png pidgin/artwork/hicolor/24x24/emotes/pidgin-pissed-off.png pidgin/artwork/hicolor/24x24/emotes/pidgin-pizza.png pidgin/artwork/hicolor/24x24/emotes/pidgin-plate.png pidgin/artwork/hicolor/24x24/emotes/pidgin-poop.png pidgin/artwork/hicolor/24x24/emotes/pidgin-pray.png pidgin/artwork/hicolor/24x24/emotes/pidgin-present.png pidgin/artwork/hicolor/24x24/emotes/pidgin-pumpkin.png pidgin/artwork/hicolor/24x24/emotes/pidgin-qq.png pidgin/artwork/hicolor/24x24/emotes/pidgin-question.png pidgin/artwork/hicolor/24x24/emotes/pidgin-quiet.png pidgin/artwork/hicolor/24x24/emotes/pidgin-rain.png pidgin/artwork/hicolor/24x24/emotes/pidgin-rainbow.png pidgin/artwork/hicolor/24x24/emotes/pidgin-rose-dead.png pidgin/artwork/hicolor/24x24/emotes/pidgin-rose.png pidgin/artwork/hicolor/24x24/emotes/pidgin-rotfl.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sad.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sarcastic.png pidgin/artwork/hicolor/24x24/emotes/pidgin-search.png pidgin/artwork/hicolor/24x24/emotes/pidgin-secret.png pidgin/artwork/hicolor/24x24/emotes/pidgin-shame.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sheep.png pidgin/artwork/hicolor/24x24/emotes/pidgin-shock.png pidgin/artwork/hicolor/24x24/emotes/pidgin-shout.png pidgin/artwork/hicolor/24x24/emotes/pidgin-shut-mouth.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sick.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sidefrown.png pidgin/artwork/hicolor/24x24/emotes/pidgin-silly.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sinister.png pidgin/artwork/hicolor/24x24/emotes/pidgin-skeleton.png pidgin/artwork/hicolor/24x24/emotes/pidgin-skywalker.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sleepy.png pidgin/artwork/hicolor/24x24/emotes/pidgin-smile-big.png pidgin/artwork/hicolor/24x24/emotes/pidgin-smile.png pidgin/artwork/hicolor/24x24/emotes/pidgin-smirk.png pidgin/artwork/hicolor/24x24/emotes/pidgin-snail.png pidgin/artwork/hicolor/24x24/emotes/pidgin-snicker.png pidgin/artwork/hicolor/24x24/emotes/pidgin-snowman.png pidgin/artwork/hicolor/24x24/emotes/pidgin-soccerball.png pidgin/artwork/hicolor/24x24/emotes/pidgin-soldier.png pidgin/artwork/hicolor/24x24/emotes/pidgin-star.png pidgin/artwork/hicolor/24x24/emotes/pidgin-starving.png pidgin/artwork/hicolor/24x24/emotes/pidgin-stop.png pidgin/artwork/hicolor/24x24/emotes/pidgin-struggle.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sun.png pidgin/artwork/hicolor/24x24/emotes/pidgin-sweat.png pidgin/artwork/hicolor/24x24/emotes/pidgin-talktohand.png pidgin/artwork/hicolor/24x24/emotes/pidgin-teeth.png pidgin/artwork/hicolor/24x24/emotes/pidgin-terror.png pidgin/artwork/hicolor/24x24/emotes/pidgin-thinking.png pidgin/artwork/hicolor/24x24/emotes/pidgin-thunder.png pidgin/artwork/hicolor/24x24/emotes/pidgin-time-out.png pidgin/artwork/hicolor/24x24/emotes/pidgin-tongue.png pidgin/artwork/hicolor/24x24/emotes/pidgin-tremble.png pidgin/artwork/hicolor/24x24/emotes/pidgin-turtle.png pidgin/artwork/hicolor/24x24/emotes/pidgin-tv.png pidgin/artwork/hicolor/24x24/emotes/pidgin-umbrella.png pidgin/artwork/hicolor/24x24/emotes/pidgin-vampire.png pidgin/artwork/hicolor/24x24/emotes/pidgin-victory.png pidgin/artwork/hicolor/24x24/emotes/pidgin-waiting.png pidgin/artwork/hicolor/24x24/emotes/pidgin-watermelon.png pidgin/artwork/hicolor/24x24/emotes/pidgin-waving.png pidgin/artwork/hicolor/24x24/emotes/pidgin-weep.png pidgin/artwork/hicolor/24x24/emotes/pidgin-wilt.png pidgin/artwork/hicolor/24x24/emotes/pidgin-wink.png pidgin/artwork/hicolor/24x24/emotes/pidgin-worship.png pidgin/artwork/hicolor/24x24/emotes/pidgin-yawn.png pidgin/artwork/hicolor/24x24/emotes/pidgin-yin-yang.png pidgin/artwork/hicolor/24x24/emotes/theme pidgin/artwork/hicolor/24x24/status/pidgin-available.png pidgin/artwork/hicolor/24x24/status/pidgin-away.png pidgin/artwork/hicolor/24x24/status/pidgin-busy.png pidgin/artwork/hicolor/24x24/status/pidgin-chatroom.png pidgin/artwork/hicolor/24x24/status/pidgin-contact.png pidgin/artwork/hicolor/24x24/status/pidgin-extended-away.png pidgin/artwork/hicolor/24x24/status/pidgin-invisible.png pidgin/artwork/hicolor/24x24/status/pidgin-offline.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-available.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-away.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-busy.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-extended-away.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-invisible.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-message-pending.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-new-im.png pidgin/artwork/hicolor/24x24/status/pidgin-tray-offline.png pidgin/artwork/hicolor/32x32/actions/pidgin-select-avatar.png pidgin/artwork/hicolor/32x32/apps/pidgin.png pidgin/artwork/hicolor/32x32/status/pidgin-available.png pidgin/artwork/hicolor/32x32/status/pidgin-away.png pidgin/artwork/hicolor/32x32/status/pidgin-busy.png pidgin/artwork/hicolor/32x32/status/pidgin-extended-away.png pidgin/artwork/hicolor/32x32/status/pidgin-invisible.png pidgin/artwork/hicolor/32x32/status/pidgin-offline.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-available.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-away.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-busy.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-extended-away.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-invisible.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-message-pending.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-new-im.png pidgin/artwork/hicolor/32x32/status/pidgin-tray-offline.png pidgin/artwork/hicolor/48x48/apps/pidgin-aim.png pidgin/artwork/hicolor/48x48/apps/pidgin-bonjour.png pidgin/artwork/hicolor/48x48/apps/pidgin-facebook.png pidgin/artwork/hicolor/48x48/apps/pidgin-gadu-gadu.png pidgin/artwork/hicolor/48x48/apps/pidgin-icq.png pidgin/artwork/hicolor/48x48/apps/pidgin-irc.png pidgin/artwork/hicolor/48x48/apps/pidgin-jabber.png pidgin/artwork/hicolor/48x48/apps/pidgin-meanwhile.png pidgin/artwork/hicolor/48x48/apps/pidgin-msn.png pidgin/artwork/hicolor/48x48/apps/pidgin-myspace.png pidgin/artwork/hicolor/48x48/apps/pidgin-novell.png pidgin/artwork/hicolor/48x48/apps/pidgin-qq.png pidgin/artwork/hicolor/48x48/apps/pidgin-silc.png pidgin/artwork/hicolor/48x48/apps/pidgin-simple.png pidgin/artwork/hicolor/48x48/apps/pidgin-yahoo.png pidgin/artwork/hicolor/48x48/apps/pidgin-zephyr.png pidgin/artwork/hicolor/48x48/apps/pidgin.png pidgin/artwork/hicolor/48x48/status/pidgin-available.png pidgin/artwork/hicolor/48x48/status/pidgin-away.png pidgin/artwork/hicolor/48x48/status/pidgin-busy.png pidgin/artwork/hicolor/48x48/status/pidgin-dialog-auth.png pidgin/artwork/hicolor/48x48/status/pidgin-dialog-cool.png pidgin/artwork/hicolor/48x48/status/pidgin-dialog-dialog.png pidgin/artwork/hicolor/48x48/status/pidgin-dialog-error.png pidgin/artwork/hicolor/48x48/status/pidgin-dialog-info.png pidgin/artwork/hicolor/48x48/status/pidgin-dialog-mail.png pidgin/artwork/hicolor/48x48/status/pidgin-extended-away.png pidgin/artwork/hicolor/48x48/status/pidgin-invisible.png pidgin/artwork/hicolor/48x48/status/pidgin-offline.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-available.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-away.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-busy.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-extended-away.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-invisible.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-message-pending.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-new-im.png pidgin/artwork/hicolor/48x48/status/pidgin-tray-offline.png pidgin/artwork/hicolor/48x48/status/question.png pidgin/artwork/hicolor/48x48/status/warning.png pidgin/artwork/hicolor/scalable/apps/pidgin.svg pidgin/artwork/hicolor/scalable/status/pidgin-auth.svg pidgin/artwork/hicolor/scalable/status/pidgin-cool.svg pidgin/artwork/hicolor/scalable/status/pidgin-dialog.svg pidgin/artwork/hicolor/scalable/status/pidgin-error.svg pidgin/artwork/hicolor/scalable/status/pidgin-info.svg pidgin/artwork/hicolor/scalable/status/pidgin-mail.svg pidgin/artwork/hicolor/scalable/status/pidgin-question.svg pidgin/artwork/hicolor/scalable/status/pidgin-warning.svg pidgin/artwork/pixmaps/logo.png pidgin/artwork/pixmaps/pidgin.ico |
diffstat | 46 files changed, 2503 insertions(+), 1878 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/qq/AUTHORS Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/AUTHORS Fri Sep 12 14:26:41 2008 +0000 @@ -1,35 +1,38 @@ Code Contributors -===== -puzzlebird : original author -gfhuang : patches for libpurple 2.0.0beta2, maintainer -henryouly : file transfer, udp sock5 proxy and qq_show, maintainer -hzhr : maintainer -joymarquis : maintainer -arfankai : fixed bugs in char_conv.c -rakescar : provided filter for HTML tag -yyw : improved performance on PPC linux -lvxiang : provided ip to location original code -markhuetsch : OpenQ merge into libpurple, maintainer 2006-2007 -ccpaging : maintainer since 2007 -icesky : maintainer since 2007 -csyfek : faces, maintainer since 2007 +========= +puzzlebird : original author +gfhuang : patches for libpurple 2.0.0beta2, maintainer +Yuan Qingyun : patches for libpurple 1.5.0, maintainer +henryouly : file transfer, udp sock5 proxy and qq_show, maintainer +hzhr : maintainer +joymarquis : maintainer +arfankai : fixed bugs in char_conv.c +rakescar : provided filter for HTML tag +yyw : improved performance on PPC linux +lvxiang : provided ip to location original code +markhuetsch : OpenQ merge into libpurple, maintainer 2006-2007 +ccpaging : maintainer since 2007 +icesky : maintainer since 2007 +csyfek : faces, maintainer since 2007 Lovely Patch Writers -===== -gnap : message displaying, documentation -manphiz : qun processing -moo : qun processing -Coly Li : qun processing +========= +gnap : message displaying, documentation +manphiz : qun processing +moo : qun processing +Coly Li : qun processing +Emil Alexiev : captcha verification on login based on LumaQQ for MAC (2007), + login, add buddy, remove buddy, message exchange and logout Acknowledgement -===== -Shufeng Tan : http://sf.net/projects/perl-oicq -Jeff Ye : http://www.sinomac.com -Hu Zheng : http://forlinux.yeah.net -yunfan : http://www.myswear.net +========= +Shufeng Tan : http://sf.net/projects/perl-oicq +Jeff Ye : http://www.sinomac.com +Hu Zheng : http://forlinux.yeah.net +yunfan : http://www.myswear.net +OpenQ Team : http://openq.linuxsir.org +LumaQQ Team : http://lumaqq.linuxsir.org khc@pidgin.im qulogic@pidgin.im rlaager@pidgin.im -OpenQ Team -LumaQQ Team -OpenQ Google Group +OpenQ Google Group : http://groups.google.com/group/openq
--- a/libpurple/protocols/qq/ChangeLog Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/ChangeLog Fri Sep 12 14:26:41 2008 +0000 @@ -1,6 +1,36 @@ +2008.09.05 - ccpaging <ccpaging(at)gmail.com> + * Filter chars 0x01-0x20 in nickname + +2008.09.05 - ccpaging <ccpaging(at)gmail.com> + * Fixed compilation even pidgin-udp-patch not applied + * Place and analysis 'before login packet' after login. packages will be updated slowly and server may send lots of 'server command packet', while 'before login packet' is placed after 'finished update' + +2008.09.02 - ccpaging <ccpaging(at)gmail.com> + * Bugfix: can not send message to the QUN blocked adding + * Tickets: + Fixes #6957 + +2008.09.02 - ccpaging <ccpaging(at)gmail.com> + * Use new tactics of information update: + 1. send next package till the previous package received + 2. fix duplicated get_room_info and get_room_buddies commands + +2008.08.16 - ccpaging <ecc_hy(at)hotmail.com> + * Rename group to room. If you used pidginqq before, this may create a new room with same title, you may delete old one + * Replace purple_debug with purple_debug_info, purple_debug_warning, purple_debug_error + * Add server notice and server new, and two options to turn on/off + * Minor modify for reducing transaction's debug infor + * Minor modifies for system notice and QQ news. + * Add 4 new strings need translate compare with p10. + * Tickets: + Fixes #6990 + 2008.08.10 - csyfek <csyfek(at)gmail.com> * Commit to Pidgin +2008.08.07 - ccpaging <ecc_hy(at)hotmail.com> + * Support managing multi-connections according to simple.c + 2008.08.06 - ccpaging <ecc_hy(at)hotmail.com> * Rename names of variables, Group, to Room * Functions of group_network merged into qq_network and qq_process
--- a/libpurple/protocols/qq/buddy_info.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Fri Sep 12 14:26:41 2008 +0000 @@ -284,7 +284,7 @@ qd = (qq_data *) gc->proto_data; g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(qd, QQ_CMD_GET_USER_INFO, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) uid_str, strlen(uid_str)); query = g_new0(qq_info_query, 1); query->uid = uid; @@ -293,6 +293,20 @@ qd->info_query = g_list_append(qd->info_query, query); } +void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, + gint update_class, guint32 ship32) +{ + qq_data *qd; + gchar raw_data[16] = {0}; + + g_return_if_fail(uid != 0); + + qd = (qq_data *) gc->proto_data; + g_snprintf(raw_data, sizeof(raw_data), "%d", uid); + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) raw_data, strlen(raw_data), + update_class, ship32); +} + /* set up the fields requesting personal information and send a get_info packet * for myself */ void qq_prepare_modify_info(PurpleConnection *gc) @@ -314,7 +328,6 @@ /* send packet to modify personal information */ static void qq_send_packet_modify_info(PurpleConnection *gc, contact_info *info) { - qq_data *qd = (qq_data *) gc->proto_data; gint bytes = 0; guint8 raw_data[MAX_PACKET_SIZE - 128] = {0}; guint8 bar; @@ -446,7 +459,7 @@ bytes += qq_put8(raw_data + bytes, bar); - qq_send_cmd(qd, QQ_CMD_UPDATE_INFO, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, raw_data, bytes); } @@ -677,9 +690,9 @@ mid->info->qq_show = g_strdup(info->qq_show); mid->info->unknown6 = g_strdup(info->unknown6); - purple_request_fields(gc, _("Modify my information"), - _("Modify my information"), NULL, fields, - _("Update my information"), G_CALLBACK(modify_info_ok_cb), + purple_request_fields(gc, _("Modify information"), + _("Modify information"), NULL, fields, + _("Update information"), G_CALLBACK(modify_info_ok_cb), _("Cancel"), G_CALLBACK(modify_info_cancel_cb), purple_connection_get_account(gc), NULL, NULL, mid); @@ -697,8 +710,8 @@ data[data_len] = '\0'; if (qd->uid == atoi((gchar *) data)) { /* return should be my uid */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Update info ACK OK\n"); - purple_notify_info(gc, NULL, _("Your information has been updated"), NULL); + purple_debug_info("QQ", "Update info ACK OK\n"); + purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), _("Change buddy information.")); } } @@ -762,7 +775,7 @@ && g_ascii_strncasecmp(icon_path + dir_len + 1 + prefix_len + icon_len, QQ_ICON_SUFFIX, suffix_len) == 0 && icon_len <= 3)) { if (icon_global) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", errmsg); + purple_debug_error("QQ", "%s\n", errmsg); else purple_notify_error(gc, _("Invalid QQ Face"), errmsg, NULL); g_free(errmsg); @@ -775,7 +788,7 @@ /* ensure face number in proper range */ if (icon_num > QQ_FACES) { if (icon_global) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", errmsg); + purple_debug_error("QQ", "%s\n", errmsg); else purple_notify_error(gc, _("Invalid QQ Face"), errmsg, NULL); g_free(errmsg); @@ -849,7 +862,7 @@ } /* process reply to get_info packet */ -void qq_process_get_info_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_get_buddy_info(guint8 *data, gint data_len, PurpleConnection *gc) { gchar **segments; qq_info_query *query; @@ -902,22 +915,24 @@ void qq_info_query_free(qq_data *qd) { - gint i; + gint count; qq_info_query *p; g_return_if_fail(qd != NULL); - i = 0; + count = 0; while (qd->info_query != NULL) { p = (qq_info_query *) (qd->info_query->data); qd->info_query = g_list_remove(qd->info_query, p); g_free(p); - i++; + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d info queries are freed!\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d info queries are freed!\n", count); + } } -void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid) +void qq_request_get_level(PurpleConnection *gc, guint32 uid) { qq_data *qd = (qq_data *) gc->proto_data; guint8 buf[16] = {0}; @@ -927,10 +942,10 @@ bytes += qq_put32(buf + bytes, uid); qd = (qq_data *) gc->proto_data; - qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, bytes); + qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); } -void qq_send_packet_get_buddies_levels(PurpleConnection *gc) +void qq_request_get_buddies_level(PurpleConnection *gc, gint update_class) { guint8 *buf; guint16 size; @@ -942,12 +957,11 @@ if ( qd->buddies == NULL) { return; } - /* server only sends back levels for online buddies, no point - * in asking for anyone else */ - size = 4 * g_list_length(qd->buddies) + 1; + /* server only reply levels for online buddies */ + size = 4 * g_list_length(qd->buddies) + 1 + 4; buf = g_newa(guint8, size); bytes += qq_put8(buf + bytes, 0x00); - + while (NULL != node) { q_bud = (qq_buddy *) node->data; if (NULL != q_bud) { @@ -955,7 +969,10 @@ } node = node->next; } - qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, size); + + /* my id should be the end if included */ + bytes += qq_put32(buf + bytes, qd->uid); + qq_send_cmd_mess(gc, QQ_CMD_GET_LEVEL, buf, size, update_class, 0); } void qq_process_get_level_reply(guint8 *decr_buf, gint decr_len, PurpleConnection *gc) @@ -970,9 +987,9 @@ qq_data *qd = (qq_data *) gc->proto_data; gint bytes = 0; - decr_len--; + decr_len--; if (decr_len % 12 != 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Get levels list of abnormal length. Truncating last %d bytes.\n", decr_len % 12); decr_len -= (decr_len % 12); } @@ -980,19 +997,18 @@ bytes += 1; /* this byte seems random */ /* - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Byte one of get_level packet: %d\n", buf[0]); + purple_debug_info("QQ", "Byte one of get_level packet: %d\n", buf[0]); */ for (i = 0; i < decr_len; i += 12) { bytes += qq_get32(&uid, decr_buf + bytes); bytes += qq_get32(&onlineTime, decr_buf + bytes); bytes += qq_get16(&level, decr_buf + bytes); bytes += qq_get16(&timeRemainder, decr_buf + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ_LEVEL", - "%d, tmOnline: %d, level: %d, tmRemainder: %d\n", + purple_debug_info("QQ_LEVEL", "%d, tmOnline: %d, level: %d, tmRemainder: %d\n", uid, onlineTime, level, timeRemainder); if (uid == qd->uid) { qd->my_level = level; - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Got my levels as %d\n", qd->my_level); + purple_debug_warning("QQ", "Got my levels as %d\n", qd->my_level); continue; } @@ -1000,7 +1016,7 @@ if (purple_name == NULL) { continue; } - + b = purple_find_buddy(account, purple_name); g_free(purple_name); @@ -1008,10 +1024,9 @@ if (b != NULL) { q_bud = (qq_buddy *) b->proto_data; } - + if (q_bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Got levels of %d not in my buddy list\n", uid); + purple_debug_error("QQ", "Got levels of %d not in my buddy list\n", uid); continue; }
--- a/libpurple/protocols/qq/buddy_info.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Fri Sep 12 14:26:41 2008 +0000 @@ -51,14 +51,14 @@ #define QQ_FRIEND_FLAG_MOBILE 0x10 #define QQ_FRIEND_FLAG_BIND_MOBILE 0x20 */ -#define QQ_COMM_FLAG_QQ_MEMBER 0x02 -#define QQ_COMM_FLAG_QQ_VIP 0x04 +#define QQ_COMM_FLAG_QQ_VIP 0x02 +#define QQ_COMM_FLAG_QQ_MEMBER 0x04 #define QQ_COMM_FLAG_TCP_MODE 0x10 #define QQ_COMM_FLAG_MOBILE 0x20 #define QQ_COMM_FLAG_BIND_MOBILE 0x40 #define QQ_COMM_FLAG_VIDEO 0x80 -#define QQ_EXT_FLAG_SPACE 0x02 +#define QQ_EXT_FLAG_ZONE 0x02 #define QQ_BUDDY_GENDER_GG 0x00 #define QQ_BUDDY_GENDER_MM 0x01 @@ -67,14 +67,22 @@ #define QQ_ICON_PREFIX "qq_" #define QQ_ICON_SUFFIX ".png" +enum { + QQ_BUDDY_INFO_UPDATE_ONLY = 0, + QQ_BUDDY_INFO_DISPLAY, + QQ_BUDDY_INFO_MODIFY, +}; + void qq_send_packet_get_info(PurpleConnection *gc, guint32 uid, gboolean show_window); +void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, + gint update_class, guint32 ship32); void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile); void qq_prepare_modify_info(PurpleConnection *gc); void qq_process_modify_info_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_process_get_info_reply(guint8 *data, gint data_len, PurpleConnection *gc); +void qq_process_get_buddy_info(guint8 *data, gint data_len, PurpleConnection *gc); void qq_info_query_free(qq_data *qd); -void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid); -void qq_send_packet_get_buddies_levels(PurpleConnection *gc); +void qq_request_get_level(PurpleConnection *gc, guint32 uid); +void qq_request_get_buddies_level(PurpleConnection *gc, gint update_class); void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/buddy_list.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Fri Sep 12 14:26:41 2008 +0000 @@ -56,7 +56,7 @@ } qq_buddy_online; /* get a list of online_buddies */ -void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position) +void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, gint update_class) { qq_data *qd; guint8 *raw_data; @@ -77,15 +77,14 @@ /* 003-004 */ bytes += qq_put16(raw_data + bytes, 0x0000); - qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_ONLINE, raw_data, 5); + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_ONLINE, raw_data, 5, update_class, 0); qd->last_get_online = time(NULL); } -/* position starts with 0x0000, +/* position starts with 0x0000, * server may return a position tag if list is too long for one packet */ -void qq_send_packet_get_buddies_list(PurpleConnection *gc, guint16 position) +void qq_request_get_buddies_list(PurpleConnection *gc, guint16 position, gint update_class) { - qq_data *qd = (qq_data *) gc->proto_data; guint8 raw_data[16] = {0}; gint bytes = 0; @@ -98,13 +97,12 @@ * March 22, found the 00,00,00 starts to work as well */ bytes += qq_put8(raw_data + bytes, 0x00); - qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes); + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes, update_class, 0); } /* get all list, buddies & Quns with groupsid support */ -void qq_send_packet_get_buddies_and_rooms(PurpleConnection *gc, guint32 position) +void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, gint update_class) { - qq_data *qd = (qq_data *) gc->proto_data; guint8 raw_data[16] = {0}; gint bytes = 0; @@ -116,7 +114,7 @@ bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put32(raw_data + bytes, position); - qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_AND_ROOMS, raw_data, bytes); + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_AND_ROOMS, raw_data, bytes, update_class, 0); } /* parse the data into qq_buddy_status */ @@ -146,8 +144,8 @@ /* 015-030: unknown key */ bytes += qq_getdata(&(bs->unknown_key[0]), QQ_KEY_LENGTH, data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ_STATUS", - "uid: %d, U1: %d, ip: %s:%d, U2:%d, status:%d, U3:%04X\n", + purple_debug_info("QQ_STATUS", + "uid: %d, U1: %d, ip: %s:%d, U2:%d, status:%d, U3:%04X\n", bs->uid, bs->unknown1, inet_ntoa(bs->ip), bs->port, bs->unknown2, bs->status, bs->unknown3); @@ -180,13 +178,12 @@ count = 0; while (bytes < data_len) { if (data_len - bytes < QQ_ONLINE_BUDDY_ENTRY_LEN) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "[buddies online] only %d, need %d", + purple_debug_error("QQ", "[buddies online] only %d, need %d", (data_len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN); break; } memset(&bo, 0 ,sizeof(bo)); - + /* set flag */ bytes_buddy = bytes; /* based on one online buddy entry */ @@ -204,31 +201,29 @@ bytes += qq_get8(&bo.ending, data + bytes); /* 0x00 */ if (bo.bs.uid == 0 || (bytes - bytes_buddy) != QQ_ONLINE_BUDDY_ENTRY_LEN) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "uid=0 or entry complete len(%d) != %d", + purple_debug_error("QQ", "uid=0 or entry complete len(%d) != %d", (bytes - bytes_buddy), QQ_ONLINE_BUDDY_ENTRY_LEN); continue; } /* check if it is a valid entry */ if (bo.bs.uid == qd->uid) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "I am in online list %d\n", bo.bs.uid); + purple_debug_warning("QQ", "I am in online list %d\n", bo.bs.uid); continue; } /* update buddy information */ purple_name = uid_to_purple_name(bo.bs.uid); if (purple_name == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Got an online buddy %d, but not find purple name\n", bo.bs.uid); continue; } b = purple_find_buddy(purple_connection_get_account(gc), purple_name); g_free(purple_name); - + q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Got an online buddy %d, but not in my buddy list\n", bo.bs.uid); continue; } @@ -247,11 +242,11 @@ } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d online buddies, nextposition=%u\n", + purple_debug_info("QQ", "Received %d online buddies, nextposition=%u\n", count, (guint) position); return position; } @@ -274,7 +269,7 @@ qd = (qq_data *) gc->proto_data; if (data_len <= 2) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "empty buddies list"); + purple_debug_error("QQ", "empty buddies list"); return -1; } /* qq_show_packet("QQ get buddies list", data, data_len); */ @@ -297,6 +292,7 @@ pascal_len = convert_as_pascal_string(data + bytes, &q_bud->nickname, QQ_CHARSET_DEFAULT); bytes += pascal_len; + qq_filter_str(q_bud->nickname); bytes += qq_get16(&unknown, data + bytes); bytes += qq_get8(&q_bud->ext_flag, data + bytes); @@ -305,7 +301,7 @@ bytes_expected = 12 + pascal_len; if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes - buddy_bytes); g_free(q_bud->nickname); g_free(q_bud); @@ -315,7 +311,7 @@ } #if 1 - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", q_bud->uid, q_bud->ext_flag, q_bud->comm_flag, q_bud->nickname); #endif @@ -334,11 +330,11 @@ } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies, nextposition=%u\n", + purple_debug_info("QQ", "Received %d buddies, nextposition=%u\n", count, (guint) position); return position; } @@ -364,8 +360,7 @@ bytes += qq_get8(&reply_code, data + bytes); if(0 != reply_code) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "qq_process_get_buddies_and_rooms, %d", reply_code); + purple_debug_warning("QQ", "qq_process_get_buddies_and_rooms, %d", reply_code); } bytes += qq_get32(&unknown, data + bytes); @@ -381,48 +376,45 @@ /* 05: groupid*4 */ /* seems to always be 0 */ bytes += qq_get8(&groupid, data + bytes); /* - purple_debug(PURPLE_DEBUG_INFO, "QQ", "groupid: %i\n", groupid); + purple_debug_info("QQ", "groupid: %i\n", groupid); groupid >>= 2; */ if (uid == 0 || (type != 0x1 && type != 0x4)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Buddy entry, uid=%d, type=%d", uid, type); + purple_debug_info("QQ", "Buddy entry, uid=%d, type=%d", uid, type); continue; - } + } if(0x1 == type) { /* a buddy */ - /* don't do anything but count - buddies are handled by - * qq_send_packet_get_buddies_list */ + /* don't do anything but count - buddies are handled by + * qq_request_get_buddies_list */ ++i; } else { /* a group */ group = qq_room_search_id(gc, uid); if(group == NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Not find room id %d in qq_process_get_buddies_and_rooms\n", uid); qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, uid); } else { - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); } ++j; } } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "qq_process_get_buddies_and_rooms: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies and %d groups, nextposition=%u\n", i, j, (guint) position); + purple_debug_info("QQ", "Received %d buddies and %d groups, nextposition=%u\n", i, j, (guint) position); return position; } #define QQ_MISC_STATUS_HAVING_VIIDEO 0x00000001 #define QQ_CHANGE_ONLINE_STATUS_REPLY_OK 0x30 /* ASCII value of "0" */ -/* TODO: figure out what's going on with the IP region. Sometimes I get valid IP addresses, - * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy, +/* TODO: figure out what's going on with the IP region. Sometimes I get valid IP addresses, + * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy, * using different accounts to get info. */ /* check if status means online or offline */ @@ -433,7 +425,7 @@ case QQ_BUDDY_ONLINE_AWAY: case QQ_BUDDY_ONLINE_INVISIBLE: return TRUE; - case QQ_BUDDY_ONLINE_OFFLINE: + case QQ_BUDDY_CHANGE_TO_OFFLINE: return FALSE; } return FALSE; @@ -441,9 +433,9 @@ /* Help calculate the correct icon index to tell the server. */ gint get_icon_offset(PurpleConnection *gc) -{ +{ PurpleAccount *account; - PurplePresence *presence; + PurplePresence *presence; account = purple_connection_get_account(gc); presence = purple_account_get_presence(account); @@ -460,7 +452,7 @@ } /* send a packet to change my online status */ -void qq_send_packet_change_status(PurpleConnection *gc) +void qq_request_change_status(PurpleConnection *gc, gint update_class) { qq_data *qd; guint8 raw_data[16] = {0}; @@ -469,13 +461,13 @@ guint32 misc_status; gboolean fake_video; PurpleAccount *account; - PurplePresence *presence; + PurplePresence *presence; account = purple_connection_get_account(gc); presence = purple_account_get_presence(account); qd = (qq_data *) gc->proto_data; - if (!qd->logged_in) + if (!qd->is_login) return; if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) { @@ -497,7 +489,7 @@ bytes += qq_put8(raw_data + bytes, away_cmd); bytes += qq_put32(raw_data + bytes, misc_status); - qq_send_cmd(qd, QQ_CMD_CHANGE_ONLINE_STATUS, raw_data, bytes); + qq_send_cmd_mess(gc, QQ_CMD_CHANGE_STATUS, raw_data, bytes, update_class, 0); } /* parse the reply packet for change_status */ @@ -513,15 +505,15 @@ g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - + bytes = 0; bytes = qq_get8(&reply, data + bytes); if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Change status fail 0x%02X\n", reply); + purple_debug_warning("QQ", "Change status fail 0x%02X\n", reply); return; } - /* purple_debug(PURPLE_DEBUG_INFO, "QQ", "Change status OK\n"); */ + /* purple_debug_info("QQ", "Change status OK\n"); */ name = uid_to_purple_name(qd->uid); b = purple_find_buddy(gc->account, name); g_free(name); @@ -532,7 +524,7 @@ } /* it is a server message indicating that one of my buddies has changed its status */ -void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gint bytes; @@ -547,16 +539,16 @@ qd = (qq_data *) gc->proto_data; if (data_len < 35) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[buddy status change] only %d, need 35 bytes\n", data_len); + purple_debug_error("QQ", "[buddy status change] only %d, need 35 bytes\n", data_len); return; } - + memset(&bs, 0, sizeof(bs)); bytes = 0; /* 000-030: qq_buddy_status */ bytes += get_buddy_status(&bs, data + bytes); - /* 031-034: Unknow, maybe my uid */ - /* This has a value of 0 when we've changed our status to + /* 031-034: Unknow, maybe my uid */ + /* This has a value of 0 when we've changed our status to * QQ_BUDDY_ONLINE_INVISIBLE */ bytes += qq_get32(&my_uid, data + bytes); @@ -565,20 +557,18 @@ g_free(name); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "got information of unknown buddy %d\n", bs.uid); + purple_debug_warning("QQ", "Get status of unknown buddy %d\n", bs.uid); return; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "status:.uid = %d, q_bud->uid = %d\n", bs.uid , q_bud->uid); - if(bs.ip.s_addr != 0) { + if(bs.ip.s_addr != 0) { q_bud->ip.s_addr = bs.ip.s_addr; q_bud->port = bs.port; } q_bud->status =bs.status; - if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL) { - qq_send_packet_get_level(gc, q_bud->uid); + if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL && q_bud->level <= 0) { + qq_request_get_level(gc, q_bud->uid); } qq_update_buddy_contact(gc, q_bud); } @@ -589,24 +579,24 @@ gchar *purple_name; PurpleBuddy *bud; gchar *status_id; - + g_return_if_fail(q_bud != NULL); purple_name = uid_to_purple_name(q_bud->uid); if (purple_name == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not find purple name: %d\n", q_bud->uid); + purple_debug_error("QQ", "Not find purple name: %d\n", q_bud->uid); return; } bud = purple_find_buddy(gc->account, purple_name); if (bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not find buddy: %d\n", q_bud->uid); + purple_debug_error("QQ", "Not find buddy: %d\n", q_bud->uid); g_free(purple_name); return; } - + purple_blist_server_alias_buddy(bud, q_bud->nickname); /* server */ - q_bud->last_refresh = time(NULL); + q_bud->last_update = time(NULL); /* purple supports signon and idle time * but it is not much use for QQ, I do not use them */ @@ -619,7 +609,7 @@ case QQ_BUDDY_ONLINE_NORMAL: status_id = "available"; break; - case QQ_BUDDY_ONLINE_OFFLINE: + case QQ_BUDDY_CHANGE_TO_OFFLINE: status_id = "offline"; break; case QQ_BUDDY_ONLINE_AWAY: @@ -630,10 +620,10 @@ break; default: status_id = "invisible"; - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "unknown status: %x\n", q_bud->status); + purple_debug_error("QQ", "unknown status: %x\n", q_bud->status); break; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "buddy %d %s\n", q_bud->uid, status_id); + purple_debug_info("QQ", "buddy %d %s\n", q_bud->uid, status_id); purple_prpl_got_user_status(gc->account, purple_name, status_id, NULL); if (q_bud->comm_flag & QQ_COMM_FLAG_MOBILE && q_bud->status != QQ_BUDDY_OFFLINE) @@ -641,11 +631,6 @@ else purple_prpl_got_user_status_deactive(gc->account, purple_name, "mobile"); - if (q_bud->comm_flag & QQ_COMM_FLAG_VIDEO && q_bud->status != QQ_BUDDY_OFFLINE) - purple_prpl_got_user_status(gc->account, purple_name, "video", NULL); - else - purple_prpl_got_user_status_deactive(gc->account, purple_name, "video"); - g_free(purple_name); } @@ -664,9 +649,9 @@ while (list != NULL) { q_bud = (qq_buddy *) list->data; - if (q_bud != NULL && now > q_bud->last_refresh + QQ_UPDATE_ONLINE_INTERVAL + if (q_bud != NULL && now > q_bud->last_update + QQ_UPDATE_ONLINE_INTERVAL && q_bud->status != QQ_BUDDY_ONLINE_INVISIBLE) { - q_bud->status = QQ_BUDDY_ONLINE_OFFLINE; + q_bud->status = QQ_BUDDY_CHANGE_TO_OFFLINE; qq_update_buddy_contact(gc, q_bud); } list = list->next;
--- a/libpurple/protocols/qq/buddy_list.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.h Fri Sep 12 14:26:41 2008 +0000 @@ -42,19 +42,19 @@ enum { QQ_BUDDY_OFFLINE = 0x00, - QQ_BUDDY_ONLINE_NORMAL = 0x0a, - QQ_BUDDY_ONLINE_OFFLINE = 0x14, - QQ_BUDDY_ONLINE_AWAY = 0x1e, - QQ_BUDDY_ONLINE_INVISIBLE = 0x28 + QQ_BUDDY_ONLINE_NORMAL = 10, + QQ_BUDDY_CHANGE_TO_OFFLINE = 20, + QQ_BUDDY_ONLINE_AWAY = 30, + QQ_BUDDY_ONLINE_INVISIBLE = 40 }; -void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position); +void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, gint update_class); guint8 qq_process_get_buddies_online_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_send_packet_get_buddies_list(PurpleConnection *gc, guint16 position); +void qq_request_get_buddies_list(PurpleConnection *gc, guint16 position, gint update_class); guint16 qq_process_get_buddies_list_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_send_packet_get_buddies_and_rooms(PurpleConnection *gc, guint32 position); +void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, gint update_class); guint32 qq_process_get_buddies_and_rooms(guint8 *data, gint data_len, PurpleConnection *gc); void qq_refresh_all_buddy_status(PurpleConnection *gc); @@ -63,7 +63,7 @@ gint get_icon_offset(PurpleConnection *gc); -void qq_send_packet_change_status(PurpleConnection *gc); +void qq_request_change_status(PurpleConnection *gc, gint update_class); void qq_process_change_status_reply(guint8 *data, gint data_len, PurpleConnection *gc); void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc);
--- a/libpurple/protocols/qq/buddy_opt.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Fri Sep 12 14:26:41 2008 +0000 @@ -60,19 +60,17 @@ /* send packet to remove a buddy from my buddy list */ static void _qq_send_packet_remove_buddy(PurpleConnection *gc, guint32 uid) { - qq_data *qd = (qq_data *) gc->proto_data; gchar uid_str[11]; g_return_if_fail(uid > 0); g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(qd, QQ_CMD_DEL_BUDDY, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_DEL_BUDDY, (guint8 *) uid_str, strlen(uid_str)); } /* try to remove myself from someone's buddy list */ static void _qq_send_packet_remove_self_from(PurpleConnection *gc, guint32 uid) { - qq_data *qd = (qq_data *) gc->proto_data; guint8 raw_data[16] = {0}; gint bytes = 0; @@ -80,7 +78,7 @@ bytes += qq_put32(raw_data + bytes, uid); - qq_send_cmd(qd, QQ_CMD_REMOVE_SELF, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_REMOVE_SELF, raw_data, bytes); } /* try to add a buddy without authentication */ @@ -94,7 +92,7 @@ /* we need to send the ascii code of this uid to qq server */ g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(qd, QQ_CMD_ADD_BUDDY_WO_AUTH, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_WO_AUTH, (guint8 *) uid_str, strlen(uid_str)); /* must be set after sending packet to get the correct send_seq */ req = g_new0(qq_add_buddy_request, 1); @@ -106,7 +104,6 @@ /* this buddy needs authentication, text conversion is done at lowest level */ static void _qq_send_packet_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text) { - qq_data *qd = (qq_data *) gc->proto_data; gchar *text_qq, uid_str[11]; guint8 bar, *raw_data; gint bytes = 0; @@ -128,7 +125,7 @@ g_free(text_qq); } - qq_send_cmd(qd, QQ_CMD_BUDDY_AUTH, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_BUDDY_AUTH, raw_data, bytes); } static void _qq_send_packet_add_buddy_auth_with_gc_and_uid(gc_and_uid *g, const gchar *text) @@ -204,11 +201,11 @@ g2->uid = uid; msg1 = g_strdup_printf(_("You rejected %d's request"), uid); - msg2 = g_strdup(_("Input your reason:")); + msg2 = g_strdup(_("Message:")); nombre = uid_to_purple_name(uid); purple_request_input(gc, _("Reject request"), msg1, msg2, - _("Sorry, you are not my type..."), TRUE, FALSE, + _("Sorry, you are not my style..."), TRUE, FALSE, NULL, _("Reject"), G_CALLBACK(_qq_reject_add_request_real), _("Cancel"), NULL, purple_connection_get_account(gc), nombre, NULL, g2); @@ -261,7 +258,7 @@ qd = (qq_data *) gc->proto_data; if (data[0] != QQ_ADD_BUDDY_AUTH_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add buddy with auth request failed\n"); + purple_debug_warning("QQ", "Add buddy with auth request failed\n"); if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) { return; } @@ -269,7 +266,7 @@ purple_notify_error(gc, NULL, _("Add buddy with auth request failed"), msg_utf8); g_free(msg_utf8); } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Add buddy with auth request OK\n"); + purple_debug_info("QQ", "Add buddy with auth request OK\n"); } } @@ -284,16 +281,17 @@ if (data[0] != QQ_REMOVE_BUDDY_REPLY_OK) { /* there is no reason return from server */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove buddy fails\n"); + purple_debug_warning("QQ", "Remove buddy fails\n"); + purple_notify_info(gc, _("QQ Buddy"), _("Failed:"), _("Remove buddy")); } else { /* if reply */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove buddy OK\n"); + purple_debug_info("QQ", "Remove buddy OK\n"); /* TODO: We don't really need to notify the user about this, do we? */ - purple_notify_info(gc, NULL, _("You have successfully removed a buddy"), NULL); + purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), _("Remove buddy")); } } /* process the server reply for my request to remove myself from a buddy */ -void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; @@ -303,11 +301,12 @@ if (data[0] != QQ_REMOVE_SELF_REPLY_OK) { /* there is no reason return from server */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove self fails\n"); + purple_debug_warning("QQ", "Remove self fails\n"); + purple_notify_info(gc, _("QQ Buddy"), _("Failed:"), _("Remove from other's buddy list")); } else { /* if reply */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove self from a buddy OK\n"); + purple_debug_info("QQ", "Remove from a buddy OK\n"); /* TODO: Does the user really need to be notified about this? */ - purple_notify_info(gc, NULL, _("You have successfully removed yourself from your friend's buddy list"), NULL); + purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), _("Remove from other's buddy list")); } } @@ -340,25 +339,25 @@ } if (for_uid == 0) { /* we have no record for this */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "We have no record for add buddy reply [%d], discard\n", seq); + purple_debug_error("QQ", "We have no record for add buddy reply [%d], discard\n", seq); return; } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Add buddy reply [%d] is for id [%d]\n", seq, for_uid); + purple_debug_info("QQ", "Add buddy reply [%d] is for id [%d]\n", seq, for_uid); } if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) return; - + uid = segments[0]; reply = segments[1]; if (strtol(uid, NULL, 10) != qd->uid) { /* should not happen */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Add buddy reply is to [%s], not me!", uid); + purple_debug_error("QQ", "Add buddy reply is to [%s], not me!", uid); g_strfreev(segments); return; } if (strtol(reply, NULL, 10) > 0) { /* need auth */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add buddy attempt fails, need authentication\n"); + purple_debug_warning("QQ", "Add buddy attempt fails, need authentication\n"); nombre = uid_to_purple_name(for_uid); b = purple_find_buddy(gc->account, nombre); if (b != NULL) @@ -366,7 +365,7 @@ g = g_new0(gc_and_uid, 1); g->gc = gc; g->uid = for_uid; - msg = g_strdup_printf(_("User %d needs authentication"), for_uid); + msg = g_strdup_printf(_("%d needs authentication"), for_uid); purple_request_input(gc, NULL, msg, _("Input request here"), /* TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands */ _("Would you be my friend?"), @@ -380,8 +379,8 @@ g_free(nombre); } else { /* add OK */ qq_add_buddy_by_recv_packet(gc, for_uid, TRUE, TRUE); - msg = g_strdup_printf(_("You have added %d to buddy list"), for_uid); - purple_notify_info(gc, NULL, msg, NULL); + msg = g_strdup_printf(_("Add into %d's buddy list"), for_uid); + purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), msg); g_free(msg); } g_strfreev(segments); @@ -397,7 +396,7 @@ if (g == NULL) { g = purple_group_new(group_name); purple_blist_add_group(g, NULL); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add new group: %s\n", group_name); + purple_debug_warning("QQ", "Add new group: %s\n", group_name); } return g; @@ -440,11 +439,11 @@ b->proto_data = q_bud; qd->buddies = g_list_append(qd->buddies, q_bud); qq_send_packet_get_info(gc, q_bud->uid, FALSE); - qq_send_packet_get_buddies_online(gc, 0); + qq_request_get_buddies_online(gc, 0, 0); } purple_blist_add_buddy(b, NULL, g, NULL); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add new buddy: [%s]\n", name); + purple_debug_warning("QQ", "Add new buddy: [%s]\n", name); g_free(name); g_free(group_name); @@ -454,8 +453,8 @@ /* add a buddy and send packet to QQ server * note that when purple load local cached buddy list into its blist - * it also calls this funtion, so we have to - * define qd->logged_in=TRUE AFTER serv_finish_login(gc) */ + * it also calls this funtion, so we have to + * define qd->is_login=TRUE AFTER serv_finish_login(gc) */ void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { qq_data *qd; @@ -463,7 +462,7 @@ PurpleBuddy *b; qd = (qq_data *) gc->proto_data; - if (!qd->logged_in) + if (!qd->is_login) return; /* IMPORTANT ! */ uid = purple_name_to_uid(buddy->name); @@ -474,8 +473,8 @@ if (b != NULL) purple_blist_remove_buddy(b); purple_notify_error(gc, NULL, - _("QQid Error"), - _("Invalid QQid")); + _("QQ Number Error"), + _("Invalid QQ Number")); } } @@ -490,7 +489,7 @@ qd = (qq_data *) gc->proto_data; uid = purple_name_to_uid(buddy->name); - if (!qd->logged_in) + if (!qd->is_login) return; if (uid > 0) @@ -502,7 +501,7 @@ if (q_bud != NULL) qd->buddies = g_list_remove(qd->buddies, q_bud); else - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "We have no qq_buddy record for %s\n", buddy->name); + purple_debug_warning("QQ", "We have no qq_buddy record for %s\n", buddy->name); /* remove buddy on blist, this does not trigger qq_remove_buddy again * do this only if the request comes from block request, * otherwise purple segmentation fault */ @@ -514,41 +513,45 @@ /* free add buddy request queue */ void qq_add_buddy_request_free(qq_data *qd) { - gint i; + gint count; qq_add_buddy_request *p; - i = 0; - while (qd->add_buddy_request) { + count = 0; + while (qd->add_buddy_request != NULL) { p = (qq_add_buddy_request *) (qd->add_buddy_request->data); qd->add_buddy_request = g_list_remove(qd->add_buddy_request, p); g_free(p); - i++; + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d add buddy requests are freed!\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d add buddy requests are freed!\n", count); + } } /* free up all qq_buddy */ void qq_buddies_list_free(PurpleAccount *account, qq_data *qd) { - gint i; + gint count; qq_buddy *p; gchar *name; PurpleBuddy *b; - i = 0; + count = 0; while (qd->buddies) { p = (qq_buddy *) (qd->buddies->data); qd->buddies = g_list_remove(qd->buddies, p); name = uid_to_purple_name(p->uid); - b = purple_find_buddy(account, name); - if(b != NULL) + b = purple_find_buddy(account, name); + if(b != NULL) b->proto_data = NULL; else - purple_debug(PURPLE_DEBUG_INFO, "QQ", "qq_buddy %s not found in purple proto_data\n", name); + purple_debug_info("QQ", "qq_buddy %s not found in purple proto_data\n", name); g_free(name); g_free(p); - i++; + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d qq_buddy structures are freed!\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d qq_buddy structures are freed!\n", count); + } }
--- a/libpurple/protocols/qq/char_conv.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.c Fri Sep 12 14:26:41 2008 +0000 @@ -98,7 +98,7 @@ } /* convert a string from from_charset to to_charset, using g_convert */ -static gchar *_my_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset) +static gchar *_my_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset) { GError *error = NULL; gchar *ret; @@ -111,9 +111,9 @@ if (error == NULL) { return ret; /* conversion is OK */ } - + /* conversion error */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ_CONVERT", "%s\n", error->message); + purple_debug_error("QQ_CONVERT", "%s\n", error->message); qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ_CONVERT", (guint8 *) str, (len == -1) ? strlen(str) : len, @@ -127,8 +127,8 @@ * take the input as a pascal string and return a converted c-string in UTF-8 * returns the number of bytes read, return -1 if fatal error * the converted UTF-8 will be saved in ret - */ -gint convert_as_pascal_string(guint8 *data, gchar **ret, const gchar *from_charset) + */ +gint convert_as_pascal_string(guint8 *data, gchar **ret, const gchar *from_charset) { guint8 len; @@ -182,7 +182,7 @@ g_string_append_printf(encoded, "<font color=\"%s\"><font face=\"%s\"><font size=\"%d\">", color_code, font_name, font_size / 3); - purple_debug(PURPLE_DEBUG_INFO, "QQ_MESG", + purple_debug_info("QQ_MESG", "recv <font color=\"%s\"><font face=\"%s\"><font size=\"%d\">\n", color_code, font_name, font_size / 3); g_string_append(encoded, msg_utf8); @@ -222,7 +222,7 @@ return _my_convert(str, -1, UTF8, from_charset); } -/* QQ uses binary code for smiley, while purple uses strings. +/* QQ uses binary code for smiley, while purple uses strings. * There is a mapping relation between these two. */ gchar *qq_smiley_to_purple(gchar *text) { @@ -286,7 +286,8 @@ } for (temp = str; *temp != 0; temp++) { - if (*temp == '\r' || *temp == '\n') *temp = ' '; + /*if (*temp == '\r' || *temp == '\n') *temp = ' ';*/ + if (*temp > 0 && *temp < 0x20) *temp = ' '; } g_strstrip(str); }
--- a/libpurple/protocols/qq/file_trans.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/file_trans.c Fri Sep 12 14:26:41 2008 +0000 @@ -22,10 +22,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifdef _WIN32 -#define random rand -#endif - #include "internal.h" #include "debug.h" @@ -62,7 +58,7 @@ { guint8 seed; - seed = random(); + seed = rand() & 0xFF; return _get_file_key(seed); } @@ -261,7 +257,7 @@ if (bytes == len + 12) { _qq_xfer_write(raw_data, bytes, qd->xfer); } else - purple_debug(PURPLE_DEBUG_INFO, "QQ", "send_file: want %d but got %d\n", len + 12, bytes); + purple_debug_info("QQ", "send_file: want %d but got %d\n", len + 12, bytes); return bytes; } @@ -323,13 +319,13 @@ bytes_expected = 61; break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "qq_send_file_ctl_packet: Unknown packet type[%d]\n", + purple_debug_info("QQ", "qq_send_file_ctl_packet: Unknown packet type[%d]\n", packet_type); bytes_expected = 0; } if (bytes != bytes_expected) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d", + purple_debug_error("QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d", bytes_expected, bytes); return; } @@ -346,24 +342,24 @@ guint8 *buf; int buflen; hex_dump = hex_dump_to_str(encrypted_data, encrypted_len); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "encrypted packet: \n%s", hex_dump); + purple_debug_info("QQ", "encrypted packet: \n%s", hex_dump); g_free(hex_dump); buf = g_newa(guint8, MAX_PACKET_SIZE); buflen = encrypted_len; if (qq_crypt(DECRYPT, encrypted_data, encrypted_len, info->file_session_key, buf, &buflen)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt success\n"); + purple_debug_info("QQ", "decrypt success\n"); if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0) - purple_debug(PURPLE_DEBUG_INFO, "QQ", "checksum ok\n"); + purple_debug_info("QQ", "checksum ok\n"); hex_dump = hex_dump_to_str(buf, buflen); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypted packet: \n%s", hex_dump); + purple_debug_info("QQ", "decrypted packet: \n%s", hex_dump); g_free(hex_dump); } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt fail\n"); + purple_debug_info("QQ", "decrypt fail\n"); } #endif - purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); + purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); _qq_send_file(gc, encrypted_data, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); } @@ -410,7 +406,7 @@ info->fragment_num = (filesize - 1) / QQ_FILE_FRAGMENT_MAXLEN + 1; info->fragment_len = QQ_FILE_FRAGMENT_MAXLEN; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "start transfering data, %d fragments with %d length each\n", info->fragment_num, info->fragment_len); /* Unknown */ @@ -435,7 +431,7 @@ filename_len); break; case QQ_FILE_DATA_INFO: - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "sending %dth fragment with length %d, offset %d\n", fragment_index, len, (fragment_index-1)*fragment_size); /* bytes += qq_put16(raw_data + bytes, ++(qd->send_seq)); */ @@ -448,7 +444,7 @@ bytes += qq_putdata(raw_data + bytes, data, len); break; case QQ_FILE_EOF: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "end of sending data\n"); + purple_debug_info("QQ", "end of sending data\n"); /* bytes += qq_put16(raw_data + bytes, info->fragment_num + 1); */ bytes += qq_put16(raw_data + bytes, info->fragment_num); bytes += qq_put8(raw_data + bytes, sub_type); @@ -474,7 +470,7 @@ break; } } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); + purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); _qq_send_file(gc, raw_data, bytes, QQ_FILE_DATA_PACKET_TAG, info->to_uid); } @@ -516,7 +512,7 @@ decrypted_data = g_newa(guint8, data_len); decrypted_len = qq_decrypt(decrypted_data, data, data_len, qd->session_md5); if ( decrypted_len <= 0 ) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt rcv file ctrl packet\n"); + purple_debug_error("QQ", "Error decrypt rcv file ctrl packet\n"); return; } @@ -526,7 +522,7 @@ decryped_bytes += qq_get16(&seq, decrypted_data + decryped_bytes); decryped_bytes += 4+1+1+19+1; /* skip something */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "==> [%d] receive %s packet\n", seq, qq_get_file_cmd_desc(packet_type)); + purple_debug_info("QQ", "==> [%d] receive %s packet\n", seq, qq_get_file_cmd_desc(packet_type)); qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", decrypted_data, decrypted_len, "decrypted control packet received:"); @@ -566,7 +562,7 @@ qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0); break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "unprocess file command %d\n", packet_type); + purple_debug_info("QQ", "unprocess file command %d\n", packet_type); } } @@ -577,7 +573,7 @@ ft_info *info = (ft_info *) xfer->data; guint32 mask; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "receiving %dth fragment with length %d, slide window status %o, max_fragment_index %d\n", index, len, info->window, info->max_fragment_index); if (info->window == 0 && info->max_fragment_index == 0) { @@ -585,11 +581,11 @@ purple_xfer_cancel_local(xfer); return; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "object file opened for writing\n"); + purple_debug_info("QQ", "object file opened for writing\n"); } mask = 0x1 << (index % sizeof(info->window)); if (index < info->max_fragment_index || (info->window & mask)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "duplicate %dth fragment, drop it!\n", index+1); + purple_debug_info("QQ", "duplicate %dth fragment, drop it!\n", index+1); return; } @@ -609,7 +605,7 @@ if (mask & 0x8000) mask = 0x0001; else mask = mask << 1; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "procceed %dth fragment, slide window status %o, max_fragment_index %d\n", + purple_debug_info("QQ", "procceed %dth fragment, slide window status %o, max_fragment_index %d\n", index, info->window, info->max_fragment_index); } @@ -654,12 +650,12 @@ PurpleXfer *xfer = qd->xfer; ft_info *info = (ft_info *) xfer->data; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "receiving %dth fragment ack, slide window status %o, max_fragment_index %d\n", fragment_index, info->window, info->max_fragment_index); if (fragment_index < info->max_fragment_index || fragment_index >= info->max_fragment_index + sizeof(info->window)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "duplicate %dth fragment, drop it!\n", fragment_index+1); + purple_debug_info("QQ", "duplicate %dth fragment, drop it!\n", fragment_index+1); return; } mask = 0x1 << (fragment_index % sizeof(info->window)); @@ -696,7 +692,7 @@ else mask = mask << 1; } } - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "procceed %dth fragment ack, slide window status %o, max_fragment_index %d\n", fragment_index, info->window, info->max_fragment_index); } @@ -737,7 +733,7 @@ info->max_fragment_index = 0; info->window = 0; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "start receiving data, %d fragments with %d length each\n", info->fragment_num, info->fragment_len); _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, @@ -747,7 +743,7 @@ bytes += qq_get32(&fragment_index, data + bytes); bytes += qq_get32(&fragment_offset, data + bytes); bytes += qq_get16(&fragment_len, data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "received %dth fragment with length %d, offset %d\n", fragment_index, fragment_len, fragment_offset); @@ -756,7 +752,7 @@ _qq_recv_file_progess(gc, data + bytes, fragment_len, fragment_index, fragment_offset); break; case QQ_FILE_EOF: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "end of receiving\n"); + purple_debug_info("QQ", "end of receiving\n"); _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, 0, 0, NULL, 0); break; @@ -795,11 +791,11 @@ purple_xfer_end(qd->xfer); break; case QQ_FILE_BASIC_INFO: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "here\n"); + purple_debug_info("QQ", "here\n"); _qq_send_file_data_packet(gc, QQ_FILE_DATA_INFO, 0, 0, 0, NULL, 0); break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "_qq_process_recv_file_data: unknown packet type [%d]\n", + purple_debug_info("QQ", "_qq_process_recv_file_data: unknown packet type [%d]\n", packet_type); break; } @@ -824,6 +820,6 @@ _qq_process_recv_file_data(gc, data + bytes, len - bytes); break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "unknown packet tag"); + purple_debug_info("QQ", "unknown packet tag"); } }
--- a/libpurple/protocols/qq/group.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group.c Fri Sep 12 14:26:41 2008 +0000 @@ -64,9 +64,9 @@ pce = g_new0(struct proto_chat_entry, 1); pce->label = _("ID: "); - pce->identifier = QQ_GROUP_KEY_EXTERNAL_ID; + pce->identifier = QQ_ROOM_KEY_EXTERNAL_ID; m = g_list_append(m, pce); - + return m; } @@ -77,7 +77,7 @@ defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); if (chat_name != NULL) - g_hash_table_insert(defaults, QQ_GROUP_KEY_EXTERNAL_ID, g_strdup(chat_name)); + g_hash_table_insert(defaults, QQ_ROOM_KEY_EXTERNAL_ID, g_strdup(chat_name)); return defaults; } @@ -96,33 +96,33 @@ rl = purple_roomlist_new(purple_connection_get_account(gc)); qd->roomlist = rl; - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Group ID"), QQ_GROUP_KEY_EXTERNAL_ID, FALSE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Group ID"), QQ_ROOM_KEY_EXTERNAL_ID, FALSE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Creator"), QQ_GROUP_KEY_CREATOR_UID, FALSE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Creator"), QQ_ROOM_KEY_CREATOR_UID, FALSE); fields = g_list_append(fields, f); f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, - _("Group Description"), QQ_GROUP_KEY_GROUP_DESC_UTF8, FALSE); + _("Group Description"), QQ_ROOM_KEY_DESC_UTF8, FALSE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_INTERNAL_ID, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_INTERNAL_ID, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_TYPE, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_TYPE, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Auth"), QQ_GROUP_KEY_AUTH_TYPE, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Auth"), QQ_ROOM_KEY_AUTH_TYPE, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_GROUP_CATEGORY, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_CATEGORY, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_GROUP_NAME_UTF8, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_TITLE_UTF8, TRUE); fields = g_list_append(fields, f); purple_roomlist_set_fields(rl, fields); purple_roomlist_set_in_progress(qd->roomlist, TRUE); purple_request_input(gc, _("QQ Qun"), - _("Please enter external group ID"), - _("You can only search for permanent QQ groups\n"), - NULL, FALSE, FALSE, NULL, - _("Search"), G_CALLBACK(_qq_group_search_callback), - _("Cancel"), G_CALLBACK(_qq_group_search_cancel_callback), + _("Please enter Qun number"), + _("You can only search for permanent Qun\n"), + NULL, FALSE, FALSE, NULL, + _("Search"), G_CALLBACK(_qq_group_search_callback), + _("Cancel"), G_CALLBACK(_qq_group_search_cancel_callback), purple_connection_get_account(gc), NULL, NULL, gc); @@ -157,7 +157,7 @@ purple_group = purple_find_group(PURPLE_GROUP_QQ_QUN); if (purple_group == NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "We have no QQ Qun\n"); + purple_debug_info("QQ", "We have no QQ Qun\n"); return; } @@ -170,7 +170,7 @@ chat = (PurpleChat *) node; if (account != chat->account) /* not qq account*/ continue; - group = qq_group_from_hashtable(gc, chat->components); + group = qq_room_create_by_hashtable(gc, chat->components); if (group == NULL) continue; @@ -178,8 +178,7 @@ continue; count++; - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Load %d QQ Qun configurations\n", count); + purple_debug_info("QQ", "Load %d QQ Qun configurations\n", count); }
--- a/libpurple/protocols/qq/group.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group.h Fri Sep 12 14:26:41 2008 +0000 @@ -34,27 +34,29 @@ #define PURPLE_GROUP_QQ_QUN "QQ 群" typedef enum { - QQ_GROUP_MEMBER_STATUS_NOT_MEMBER = 0x00, /* default 0x00 means not member */ - QQ_GROUP_MEMBER_STATUS_IS_MEMBER, - QQ_GROUP_MEMBER_STATUS_APPLYING, - QQ_GROUP_MEMBER_STATUS_IS_ADMIN, -} qq_group_member_status; + QQ_ROOM_ROLE_NO = 0x00, /* default 0x00 means not member */ + QQ_ROOM_ROLE_YES, + QQ_ROOM_ROLE_REQUESTING, + QQ_ROOM_ROLE_ADMIN, +} qq_room_role; typedef struct _qq_group { /* all these will be saved when we exit Purple */ - qq_group_member_status my_status; /* my status for this group */ - gchar *my_status_desc; /* my status description */ + qq_room_role my_role; /* my role for this room */ + gchar *my_role_desc; /* my role description */ guint32 id; guint32 ext_id; guint8 type8; /* permanent or temporory */ guint32 creator_uid; - guint32 group_category; + guint32 category; guint8 auth_type; - gchar *group_name_utf8; - gchar *group_desc_utf8; + gchar *title_utf8; + gchar *desc_utf8; /* all these will be loaded from the network */ gchar *notice_utf8; /* group notice by admin */ - GList *members; + GList *members; + + gboolean is_got_info; } qq_group; GList *qq_chat_info(PurpleConnection *gc);
--- a/libpurple/protocols/qq/group_conv.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_conv.c Fri Sep 12 14:26:41 2008 +0000 @@ -25,25 +25,40 @@ #include <glib.h> #include "qq.h" -#include "conversation.h" - #include "group_conv.h" #include "buddy_list.h" +#include "header_info.h" +#include "qq_network.h" +#include "qq_process.h" #include "utils.h" /* show group conversation window */ -void qq_group_conv_show_window(PurpleConnection *gc, qq_group *group) +PurpleConversation *qq_room_conv_create(PurpleConnection *gc, qq_group *group) { PurpleConversation *conv; qq_data *qd; - g_return_if_fail(group != NULL); + g_return_val_if_fail(group != NULL, NULL); qd = (qq_data *) gc->proto_data; - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - group->group_name_utf8, purple_connection_get_account(gc)); - if (conv == NULL) /* show only one window per group */ - serv_got_joined_chat(gc, qd->channel++, group->group_name_utf8); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + group->title_utf8, purple_connection_get_account(gc)); + if (conv != NULL) { + /* show only one conversation per group */ + return conv; + } + + serv_got_joined_chat(gc, qd->channel++, group->title_utf8); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); + if (conv != NULL) { + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, group->notice_utf8); + if (group->is_got_info) + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id); + else + qq_update_room(gc, 0, group->id); + return conv; + } + return NULL; } /* refresh online member in group conversation window */ @@ -59,7 +74,7 @@ names = NULL; flags = NULL; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - group->group_name_utf8, purple_connection_get_account(gc)); + group->title_utf8, purple_connection_get_account(gc)); if (conv != NULL && group->members != NULL) { list = group->members; while (list != NULL) {
--- a/libpurple/protocols/qq/group_conv.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_conv.h Fri Sep 12 14:26:41 2008 +0000 @@ -26,9 +26,10 @@ #define _QQ_GROUP_CONV_H_ #include "connection.h" +#include "conversation.h" #include "group.h" -void qq_group_conv_show_window(PurpleConnection *gc, qq_group *group); +PurpleConversation *qq_room_conv_create(PurpleConnection *gc, qq_group *group); void qq_group_conv_refresh_online_member(PurpleConnection *gc, qq_group *group); #endif
--- a/libpurple/protocols/qq/group_find.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_find.c Fri Sep 12 14:26:41 2008 +0000 @@ -110,10 +110,10 @@ group = NULL; while (list != NULL) { group = (qq_group *) list->data; - if (group->group_name_utf8 == NULL) { + if (group->title_utf8 == NULL) { continue; } - if (!g_ascii_strcasecmp(purple_conversation_get_name(conv), group->group_name_utf8)) + if (!g_ascii_strcasecmp(purple_conversation_get_name(conv), group->title_utf8)) break; list = list->next; } @@ -167,3 +167,83 @@ return NULL; } + +qq_group *qq_room_get_next(PurpleConnection *gc, guint32 room_id) +{ + GList *list; + qq_group *group; + qq_data *qd; + gboolean is_find = FALSE; + + qd = (qq_data *) gc->proto_data; + + if (qd->groups == NULL) { + return NULL; + } + + if (room_id <= 0) { + return (qq_group *) qd->groups->data; + } + + list = qd->groups; + while (list != NULL) { + group = (qq_group *) list->data; + list = list->next; + if (group->id == room_id) { + is_find = TRUE; + break; + } + } + + if ( !is_find || list == NULL) { + return NULL; + } + + return (qq_group *)list->data; +} + +qq_group *qq_room_get_next_conv(PurpleConnection *gc, guint32 room_id) +{ + GList *list; + qq_group *group; + qq_data *qd; + gboolean is_find; + + qd = (qq_data *) gc->proto_data; + + list = qd->groups; + if (room_id > 0) { + /* search next room */ + is_find = FALSE; + while (list != NULL) { + group = (qq_group *) list->data; + list = list->next; + if (group->id == room_id) { + is_find = TRUE; + break; + } + } + if ( !is_find || list == NULL) { + return NULL; + } + } + + is_find = FALSE; + while (list != NULL) { + group = (qq_group *) list->data; + if (group->my_role == QQ_ROOM_ROLE_YES || group->my_role == QQ_ROOM_ROLE_ADMIN) { + if (NULL != purple_find_conversation_with_account( + PURPLE_CONV_TYPE_CHAT,group->title_utf8, purple_connection_get_account(gc))) { + /* In convseration*/ + is_find = TRUE; + break; + } + } + list = list->next; + } + + if ( !is_find) { + return NULL; + } + return group; +}
--- a/libpurple/protocols/qq/group_find.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_find.h Fri Sep 12 14:26:41 2008 +0000 @@ -32,10 +32,12 @@ qq_buddy *qq_group_find_member_by_uid(qq_group *group, guint32 uid); void qq_group_remove_member_by_uid(qq_group *group, guint32 uid); qq_buddy *qq_group_find_or_add_member(PurpleConnection *gc, qq_group *group, guint32 member_uid); -gboolean qq_group_find_id_by_seq(PurpleConnection *gc, guint16 seq, guint32 *id); qq_group *qq_group_find_by_channel(PurpleConnection *gc, gint channel); qq_group *qq_room_search_ext_id(PurpleConnection *gc, guint32 ext_id); qq_group *qq_room_search_id(PurpleConnection *gc, guint32 room_id); +qq_group *qq_room_get_next(PurpleConnection *gc, guint32 room_id); +qq_group *qq_room_get_next_conv(PurpleConnection *gc, guint32 room_id); + #endif
--- a/libpurple/protocols/qq/group_free.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_free.c Fri Sep 12 14:26:41 2008 +0000 @@ -54,9 +54,9 @@ { g_return_if_fail(group != NULL); qq_group_free_member(group); - g_free(group->my_status_desc); - g_free(group->group_name_utf8); - g_free(group->group_desc_utf8); + g_free(group->my_role_desc); + g_free(group->title_utf8); + g_free(group->desc_utf8); g_free(group->notice_utf8); g_free(group); } @@ -64,16 +64,18 @@ void qq_group_free_all(qq_data *qd) { qq_group *group; - gint i; - g_return_if_fail(qd != NULL); + gint count; - i = 0; + g_return_if_fail(qd != NULL); + count = 0; while (qd->groups != NULL) { - i++; group = (qq_group *) qd->groups->data; qd->groups = g_list_remove(qd->groups, group); qq_group_free(group); + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d groups are freed\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d rooms are freed\n", count); + } }
--- a/libpurple/protocols/qq/group_im.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Fri Sep 12 14:26:41 2008 +0000 @@ -37,10 +37,12 @@ #include "group_info.h" #include "group_im.h" #include "group_opt.h" +#include "group_conv.h" #include "im.h" #include "header_info.h" #include "packet_parse.h" #include "qq_network.h" +#include "qq_process.h" #include "utils.h" typedef struct _qq_recv_group_im { @@ -85,12 +87,12 @@ if (bytes == data_len) /* create OK */ qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_MSG, group->id, raw_data, data_len); else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Fail creating group_im packet, expect %d bytes, build %d bytes\n", data_len, bytes); } /* this is the ACK */ -void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc) +void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc) { /* return should be the internal group id * but we have nothing to do with it */ @@ -98,7 +100,7 @@ } /* receive an application to join the group */ -void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, user_uid; guint8 type8; @@ -119,8 +121,8 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); - msg = g_strdup_printf(_("User %d requested to join group %d"), user_uid, ext_id); - reason = g_strdup_printf(_("Reason: %s"), reason_utf8); + msg = g_strdup_printf(_("%d request to join Qun %d"), user_uid, ext_id); + reason = g_strdup_printf(_("Message: %s"), reason_utf8); g = g_new0(group_member_opt, 1); g->gc = gc; @@ -149,7 +151,7 @@ } /* the request to join a group is rejected */ -void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, admin_uid; guint8 type8; @@ -170,14 +172,14 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join group %d has been rejected by admin %d"), ext_id, admin_uid); - reason = g_strdup_printf(_("Reason: %s"), reason_utf8); + (_("Failed to join Qun %d, operated by admin %d"), ext_id, admin_uid); + reason = g_strdup_printf(_("Message: %s"), reason_utf8); purple_notify_warning(gc, _("QQ Qun Operation"), msg, reason); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); } @@ -187,7 +189,7 @@ } /* the request to join a group is approved */ -void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, admin_uid; guint8 type8; @@ -208,13 +210,13 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join group %d has been approved by admin %d"), ext_id, admin_uid); + (_("Successed to join Qun %d, operated by admin %d"), ext_id, admin_uid); purple_notify_warning(gc, _("QQ Qun Operation"), msg, NULL); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); } @@ -223,7 +225,7 @@ } /* process the packet when removed from a group */ -void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, uid; guint8 type8; @@ -241,12 +243,12 @@ g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("You [%d] have left group \"%d\""), uid, ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), msg, NULL); + msg = g_strdup_printf(_("[%d] removed from Qun \"%d\""), uid, ext_id); + purple_notify_info(gc, _("QQ Qun Operation"), _("Notice:"), msg); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); } @@ -254,7 +256,7 @@ } /* process the packet when added to a group */ -void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, uid; guint8 type8; @@ -272,18 +274,18 @@ g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("You [%d] have been added to group \"%d\""), uid, ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), msg, _("This group has been added to your buddy list")); + msg = g_strdup_printf(_("[%d] added to Qun \"%d\""), uid, ext_id); + purple_notify_info(gc, _("QQ Qun Operation"), _("Notice:"), msg); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); } else { /* no such group, try to create a dummy first, and then update */ group = qq_group_create_internal_record(gc, id, ext_id, NULL); - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); + qq_update_room(gc, 0, group->id); /* the return of this cmd will automatically update the group in blist */ } @@ -291,7 +293,7 @@ } /* recv an IM from a group chat */ -void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type) +void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type) { gchar *msg_with_purple_smiley, *msg_utf8_encoded, *im_src_name; guint16 unknown; @@ -310,7 +312,9 @@ qd = (qq_data *) gc->proto_data; - /* qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", data, data_len, "group im hex dump"); */ +#if 0 + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", data, data_len, "group im hex dump"); +#endif im_group = g_newa(qq_recv_group_im, 1); @@ -374,13 +378,9 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->group_name_utf8, purple_connection_get_account(gc)); - if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/prompt_group_msg_on_recv")) { - /* New conv should open, get group info*/ - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); - - serv_got_joined_chat(gc, qd->channel++, group->group_name_utf8); - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->group_name_utf8, purple_connection_get_account(gc)); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); + if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/show_room_when_newin")) { + conv = qq_room_conv_create(gc, group); } if (conv != NULL) {
--- a/libpurple/protocols/qq/group_im.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_im.h Fri Sep 12 14:26:41 2008 +0000 @@ -31,30 +31,17 @@ void qq_send_packet_group_im(PurpleConnection *gc, qq_group *group, const gchar *msg); -/* void qq_process_group_cmd_im(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); */ void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc); -/* void qq_process_recv_group_im(guint8 *data, guint8 **cursor, - * gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type); */ -void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type); +void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type); -/* void qq_process_recv_group_im_apply_join(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_rejected(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_approved(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_removed(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_added(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/group_info.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Fri Sep 12 14:26:41 2008 +0000 @@ -41,16 +41,16 @@ * this interval determines if their member info is outdated */ #define QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL 180 -static gboolean _is_group_member_need_update_info(qq_buddy *member) +static gboolean check_update_interval(qq_buddy *member) { g_return_val_if_fail(member != NULL, FALSE); return (member->nickname == NULL) || - (time(NULL) - member->last_refresh) > QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL; + (time(NULL) - member->last_update) > QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL; } /* this is done when we receive the reply to get_online_members sub_cmd * all member are set offline, and then only those in reply packets are online */ -static void _qq_group_set_members_all_offline(qq_group *group) +static void set_all_offline(qq_group *group) { GList *list; qq_buddy *member; @@ -59,65 +59,29 @@ list = group->members; while (list != NULL) { member = (qq_buddy *) list->data; - member->status = QQ_BUDDY_ONLINE_OFFLINE; + member->status = QQ_BUDDY_CHANGE_TO_OFFLINE; list = list->next; } } -/* send packet to get online group member, called by keep_alive */ -void qq_send_cmd_group_all_get_online_members(PurpleConnection *gc) -{ - qq_data *qd; - qq_group *group; - GList *list; - - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; - - list = qd->groups; - while (list != NULL) { - group = (qq_group *) list->data; - if (group->my_status == QQ_GROUP_MEMBER_STATUS_IS_MEMBER || - group->my_status == QQ_GROUP_MEMBER_STATUS_IS_ADMIN) - /* no need to get info time and time again, online members enough */ - qq_send_cmd_group_get_online_members(gc, group); - - list = list->next; - } -} - -void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group) -{ - g_return_if_fail(group != NULL); - - /* only get online members when conversation window is on */ - if (NULL == purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,group->group_name_utf8, purple_connection_get_account(gc))) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Conversation \"%s\" is not open, ignore to get online members\n", group->group_name_utf8); - return; - } - - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id); -} - /* send packet to get info for each group member */ -void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group) +gint qq_request_room_get_buddies(PurpleConnection *gc, qq_group *group, gint update_class) { guint8 *raw_data; gint bytes, num; GList *list; qq_buddy *member; - g_return_if_fail(group != NULL); + g_return_val_if_fail(group != NULL, 0); for (num = 0, list = group->members; list != NULL; list = list->next) { member = (qq_buddy *) list->data; - if (_is_group_member_need_update_info(member)) + if (check_update_interval(member)) num++; } if (num <= 0) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "No group member info needs to be updated now.\n"); - return; + purple_debug_info("QQ", "No group member info needs to be updated now.\n"); + return 0; } raw_data = g_newa(guint8, 4 * num); @@ -127,12 +91,14 @@ list = group->members; while (list != NULL) { member = (qq_buddy *) list->data; - if (_is_group_member_need_update_info(member)) + if (check_update_interval(member)) bytes += qq_put32(raw_data + bytes, member->uid); list = list->next; } - qq_send_room_cmd(gc, QQ_ROOM_CMD_GET_MEMBER_INFO, group->id, raw_data, bytes); + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_BUDDIES, group->id, raw_data, bytes, + update_class, 0); + return num; } void qq_process_room_cmd_get_info(guint8 *data, gint data_len, PurpleConnection *gc) @@ -174,8 +140,8 @@ bytes += qq_get32(&(group->creator_uid), data + bytes); bytes += qq_get8(&(group->auth_type), data + bytes); bytes += qq_get32(&unknown4, data + bytes); /* oldCategory */ - bytes += qq_get16(&unknown, data + bytes); - bytes += qq_get32(&(group->group_category), data + bytes); + bytes += qq_get16(&unknown, data + bytes); + bytes += qq_get32(&(group->category), data + bytes); bytes += qq_get16(&max_members, data + bytes); bytes += qq_get8(&unknown1, data + bytes); /* the following, while Eva: @@ -183,17 +149,17 @@ * 2(qunNoticeLen), qunNoticeLen(qunNoticeContent, 1(qunDescLen), * qunDestLen(qunDestcontent)) */ bytes += qq_get8(&unknown1, data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", - group->type8, group->creator_uid, group->group_category, max_members); - + purple_debug_info("QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", + group->type8, group->creator_uid, group->category, max_members); + /* strlen + <str content> */ - bytes += convert_as_pascal_string(data + bytes, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\"\n", group->group_name_utf8); + bytes += convert_as_pascal_string(data + bytes, &(group->title_utf8), QQ_CHARSET_DEFAULT); bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ bytes += convert_as_pascal_string(data + bytes, ¬ice, QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "notice \"%s\"\n", notice); - bytes += convert_as_pascal_string(data + bytes, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group_desc \"%s\"\n", group->group_desc_utf8); + bytes += convert_as_pascal_string(data + bytes, &(group->desc_utf8), QQ_CHARSET_DEFAULT); + + purple_debug_info("QQ", "room [%s] notice [%s] desc [%s] unknow 0x%04X\n", + group->title_utf8, notice, group->desc_utf8, unknown); num = 0; /* now comes the member list separated by 0x00 */ @@ -205,7 +171,7 @@ #if 0 if(organization != 0 || role != 0) { - purple_debug(PURPLE_DEBUG_INFO, "QQ_GRP", "%d, organization=%d, role=%d\n", member_uid, organization, role); + purple_debug_info("QQ_GRP", "%d, organization=%d, role=%d\n", member_uid, organization, role); } #endif @@ -214,30 +180,31 @@ member->role = role; } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\" has %d members\n", group->group_name_utf8, num); + purple_debug_info("QQ", "group \"%s\" has %d members\n", group->title_utf8, num); if (group->creator_uid == qd->uid) - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_ADMIN; - - qq_group_refresh(gc, group); - - purple_conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - group->group_name_utf8, purple_connection_get_account(gc)); - if(NULL == purple_conv) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Conversation \"%s\" is not open, do not set topic\n", group->group_name_utf8); - return; - } + group->my_role = QQ_ROOM_ROLE_ADMIN; /* filter \r\n in notice */ qq_filter_str(notice); group->notice_utf8 = strdup(notice); g_free(notice); - + + qq_group_refresh(gc, group); + + purple_conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + group->title_utf8, purple_connection_get_account(gc)); + if(NULL == purple_conv) { + purple_debug_warning("QQ", + "Conversation \"%s\" is not open, do not set topic\n", group->title_utf8); + return; + } + + purple_debug_info("QQ", "Set chat topic to %s\n", group->notice_utf8); purple_conv_chat_set_topic(PURPLE_CONV_CHAT(purple_conv), NULL, group->notice_utf8); } @@ -252,7 +219,7 @@ g_return_if_fail(data != NULL && len > 0); if (len <= 3) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Invalid group online member reply, discard it!\n"); + purple_debug_error("QQ", "Invalid group online member reply, discard it!\n"); return; } @@ -263,13 +230,12 @@ group = qq_room_search_id(gc, id); if (group == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "We have no group info for internal id [%d]\n", id); + purple_debug_error("QQ", "We have no group info for internal id [%d]\n", id); return; } /* set all offline first, then update those online */ - _qq_group_set_members_all_offline(group); + set_all_offline(group); num = 0; while (bytes < len) { bytes += qq_get32(&member_uid, data + bytes); @@ -279,15 +245,15 @@ member->status = QQ_BUDDY_ONLINE_NORMAL; } if(bytes > len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); + purple_debug_error("QQ", + "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" has %d online members\n", group->group_name_utf8, num); + purple_debug_info("QQ", "Group \"%s\" has %d online members\n", group->title_utf8, num); } /* process the reply to get_members_info packet */ -void qq_process_room_cmd_get_members(guint8 *data, gint len, PurpleConnection *gc) +void qq_process_room_cmd_get_buddies(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; gint num; @@ -300,7 +266,7 @@ g_return_if_fail(data != NULL && len > 0); #if 0 - qq_show_packet("qq_process_room_cmd_get_members", data, len); + qq_show_packet("qq_process_room_cmd_get_buddies", data, len); #endif bytes = 0; @@ -331,19 +297,19 @@ qq_filter_str(nick); member->nickname = g_strdup(nick); g_free(nick); - + #if 0 - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "member [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", member_uid, member->ext_flag, member->comm_flag, member->nickname); #endif - member->last_refresh = time(NULL); + member->last_update = time(NULL); } if (bytes > len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" obtained %d member info\n", group->group_name_utf8, num); + purple_debug_info("QQ", "Group \"%s\" obtained %d member info\n", group->title_utf8, num); }
--- a/libpurple/protocols/qq/group_info.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_info.h Fri Sep 12 14:26:41 2008 +0000 @@ -29,12 +29,9 @@ #include "connection.h" #include "group.h" -void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group); -void qq_send_cmd_group_all_get_online_members(PurpleConnection *gc); - -void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group); +gint qq_request_room_get_buddies(PurpleConnection *gc, qq_group *group, gint update_class); void qq_process_room_cmd_get_info(guint8 *data, gint len, PurpleConnection *gc); void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc); -void qq_process_room_cmd_get_members(guint8 *data, gint len, PurpleConnection *gc); +void qq_process_room_cmd_get_buddies(guint8 *data, gint len, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/group_internal.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.c Fri Sep 12 14:26:41 2008 +0000 @@ -31,49 +31,49 @@ #include "group_internal.h" #include "utils.h" -static gchar *_qq_group_set_my_status_desc(qq_group *group) +static gchar *get_role_desc(qq_group *group) { - const char *status_desc; + const char *role_desc; g_return_val_if_fail(group != NULL, g_strdup("")); - switch (group->my_status) { - case QQ_GROUP_MEMBER_STATUS_NOT_MEMBER: - status_desc = _("I am not a member"); + switch (group->my_role) { + case QQ_ROOM_ROLE_NO: + role_desc = _("I am not a member"); break; - case QQ_GROUP_MEMBER_STATUS_IS_MEMBER: - status_desc = _("I am a member"); + case QQ_ROOM_ROLE_YES: + role_desc = _("I am a member"); break; - case QQ_GROUP_MEMBER_STATUS_APPLYING: - status_desc = _("I am applying to join"); + case QQ_ROOM_ROLE_REQUESTING: + role_desc = _("I am requesting"); break; - case QQ_GROUP_MEMBER_STATUS_IS_ADMIN: - status_desc = _("I am the admin"); + case QQ_ROOM_ROLE_ADMIN: + role_desc = _("I am the admin"); break; default: - status_desc = _("Unknown status"); + role_desc = _("Unknown status"); } - return g_strdup(status_desc); + return g_strdup(role_desc); } -static void _qq_group_add_to_blist(PurpleConnection *gc, qq_group *group) +static void add_room_to_blist(PurpleConnection *gc, qq_group *group) { GHashTable *components; PurpleGroup *g; PurpleChat *chat; components = qq_group_to_hashtable(group); - chat = purple_chat_new(purple_connection_get_account(gc), group->group_name_utf8, components); + chat = purple_chat_new(purple_connection_get_account(gc), group->title_utf8, components); g = qq_get_purple_group(PURPLE_GROUP_QQ_QUN); purple_blist_add_chat(chat, g, NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "You have added group \"%s\" to blist locally\n", group->group_name_utf8); + purple_debug_info("QQ", "You have added group \"%s\" to blist locally\n", group->title_utf8); } /* Create a dummy qq_group, which includes only internal_id, ext_id, - * and potentially group_name_utf8, in case we need to call group_conv_show_window + * and potentially title_utf8, in case we need to call group_conv_show_window * right after creation. All other attributes are set to empty. * We need to send a get_group_info to the QQ server to update it right away */ qq_group *qq_group_create_internal_record(PurpleConnection *gc, - guint32 internal_id, guint32 ext_id, gchar *group_name_utf8) + guint32 internal_id, guint32 ext_id, gchar *title_utf8) { qq_group *group; qq_data *qd; @@ -82,21 +82,21 @@ qd = (qq_data *) gc->proto_data; group = g_new0(qq_group, 1); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; - group->my_status_desc = _qq_group_set_my_status_desc(group); + group->my_role = QQ_ROOM_ROLE_NO; + group->my_role_desc = get_role_desc(group); group->id = internal_id; group->ext_id = ext_id; group->type8 = 0x01; /* assume permanent Qun */ group->creator_uid = 10000; /* assume by QQ admin */ - group->group_category = 0x01; + group->category = 0x01; group->auth_type = 0x02; /* assume need auth */ - group->group_name_utf8 = g_strdup(group_name_utf8 == NULL ? "" : group_name_utf8); - group->group_desc_utf8 = g_strdup(""); + group->title_utf8 = g_strdup(title_utf8 == NULL ? "" : title_utf8); + group->desc_utf8 = g_strdup(""); group->notice_utf8 = g_strdup(""); group->members = NULL; qd->groups = g_list_append(qd->groups, group); - _qq_group_add_to_blist(gc, group); + add_room_to_blist(gc, group); return group; } @@ -124,26 +124,26 @@ { GHashTable *components; components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); - group->my_status_desc = _qq_group_set_my_status_desc(group); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_ROLE), g_strdup_printf("%d", group->my_role)); + group->my_role_desc = get_role_desc(group); g_hash_table_insert(components, - g_strdup(QQ_GROUP_KEY_INTERNAL_ID), g_strdup_printf("%d", group->id)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), + g_strdup(QQ_ROOM_KEY_INTERNAL_ID), g_strdup_printf("%d", group->id)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), g_strdup_printf("%d", group->ext_id)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_TYPE), g_strdup_printf("%d", group->type8)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TYPE), g_strdup_printf("%d", group->type8)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); g_hash_table_insert(components, - g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), g_strdup_printf("%d", group->group_category)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); + g_strdup(QQ_ROOM_KEY_CATEGORY), g_strdup_printf("%d", group->category)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_ROLE_DESC), g_strdup(group->my_role_desc)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_DESC_UTF8), g_strdup(group->desc_utf8)); return components; } /* create a qq_group from hashtable */ -qq_group *qq_group_from_hashtable(PurpleConnection *gc, GHashTable *data) +qq_group *qq_room_create_by_hashtable(PurpleConnection *gc, GHashTable *data) { qq_data *qd; qq_group *group; @@ -152,25 +152,25 @@ qd = (qq_data *) gc->proto_data; group = g_new0(qq_group, 1); - group->my_status = + group->my_role = qq_string_to_dec_value (NULL == g_hash_table_lookup(data, - QQ_GROUP_KEY_MEMBER_STATUS) ? - g_strdup_printf("%d", QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) : - g_hash_table_lookup(data, QQ_GROUP_KEY_MEMBER_STATUS)); - group->id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID)); - group->ext_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID)); - group->type8 = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_TYPE)); - group->creator_uid = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_CREATOR_UID)); - group->group_category = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_CATEGORY)); - group->auth_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_AUTH_TYPE)); - group->group_name_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_NAME_UTF8)); - group->group_desc_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_DESC_UTF8)); - group->my_status_desc = _qq_group_set_my_status_desc(group); + QQ_ROOM_KEY_ROLE) ? + g_strdup_printf("%d", QQ_ROOM_ROLE_NO) : + g_hash_table_lookup(data, QQ_ROOM_KEY_ROLE)); + group->id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID)); + group->ext_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID)); + group->type8 = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_TYPE)); + group->creator_uid = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_CREATOR_UID)); + group->category = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_CATEGORY)); + group->auth_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_AUTH_TYPE)); + group->title_utf8 = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_TITLE_UTF8)); + group->desc_utf8 = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_DESC_UTF8)); + group->my_role_desc = get_role_desc(group); + group->is_got_info = FALSE; qd->groups = g_list_append(qd->groups, group); - return group; } @@ -184,48 +184,54 @@ ext_id = g_strdup_printf("%d", group->ext_id); chat = purple_blist_find_chat(purple_connection_get_account(gc), ext_id); g_free(ext_id); - if (chat == NULL && group->my_status != QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { - _qq_group_add_to_blist(gc, group); - } else if (chat != NULL) { /* we have a local record, update its info */ - /* if there is group_name_utf8, we update the group name */ - if (group->group_name_utf8 != NULL && strlen(group->group_name_utf8) > 0) - purple_blist_alias_chat(chat, group->group_name_utf8); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); - group->my_status_desc = _qq_group_set_my_status_desc(group); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_INTERNAL_ID), - g_strdup_printf("%d", group->id)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), - g_strdup_printf("%d", group->ext_id)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_TYPE), g_strdup_printf("%d", group->type8)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), - g_strdup_printf("%d", group->group_category)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); + if (chat == NULL && group->my_role != QQ_ROOM_ROLE_NO) { + add_room_to_blist(gc, group); + return; + } + + if (chat == NULL) { + return; } + + /* we have a local record, update its info */ + /* if there is title_utf8, we update the group name */ + if (group->title_utf8 != NULL && strlen(group->title_utf8) > 0) + purple_blist_alias_chat(chat, group->title_utf8); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_ROLE), g_strdup_printf("%d", group->my_role)); + group->my_role_desc = get_role_desc(group); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_ROLE_DESC), g_strdup(group->my_role_desc)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_INTERNAL_ID), + g_strdup_printf("%d", group->id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), + g_strdup_printf("%d", group->ext_id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_TYPE), g_strdup_printf("%d", group->type8)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_CATEGORY), + g_strdup_printf("%d", group->category)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_DESC_UTF8), g_strdup(group->desc_utf8)); } -/* NOTE: If we knew how to convert between an external and internal group id, as the official +/* NOTE: If we knew how to convert between an external and internal group id, as the official * client seems to, the following would be unnecessary. That would be ideal. */ /* Use list to specify if id's alternate id is pending discovery. */ void qq_set_pending_id(GSList **list, guint32 id, gboolean pending) { - if (pending) + if (pending) *list = g_slist_prepend(*list, GINT_TO_POINTER(id)); - else + else *list = g_slist_remove(*list, GINT_TO_POINTER(id)); }
--- a/libpurple/protocols/qq/group_internal.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.h Fri Sep 12 14:26:41 2008 +0000 @@ -28,23 +28,23 @@ #include <glib.h> #include "group.h" -#define QQ_GROUP_KEY_MEMBER_STATUS "my_status_code" -#define QQ_GROUP_KEY_MEMBER_STATUS_DESC "my_status_desc" -#define QQ_GROUP_KEY_INTERNAL_ID "id" -#define QQ_GROUP_KEY_EXTERNAL_ID "ext_id" -#define QQ_GROUP_KEY_TYPE "type" -#define QQ_GROUP_KEY_CREATOR_UID "creator_uid" -#define QQ_GROUP_KEY_GROUP_CATEGORY "category" -#define QQ_GROUP_KEY_AUTH_TYPE "auth_type" -#define QQ_GROUP_KEY_GROUP_NAME_UTF8 "name_utf8" -#define QQ_GROUP_KEY_GROUP_DESC_UTF8 "desc_utf8" +#define QQ_ROOM_KEY_ROLE "my_role" +#define QQ_ROOM_KEY_ROLE_DESC "my_role_desc" +#define QQ_ROOM_KEY_INTERNAL_ID "id" +#define QQ_ROOM_KEY_EXTERNAL_ID "ext_id" +#define QQ_ROOM_KEY_TYPE "type" +#define QQ_ROOM_KEY_CREATOR_UID "creator_uid" +#define QQ_ROOM_KEY_CATEGORY "category" +#define QQ_ROOM_KEY_AUTH_TYPE "auth_type" +#define QQ_ROOM_KEY_TITLE_UTF8 "title_utf8" +#define QQ_ROOM_KEY_DESC_UTF8 "desc_utf8" -qq_group *qq_group_create_internal_record(PurpleConnection *gc, +qq_group *qq_group_create_internal_record(PurpleConnection *gc, guint32 internal_id, guint32 ext_id, gchar *group_name_utf8); void qq_group_delete_internal_record(qq_data *qd, guint32 id); GHashTable *qq_group_to_hashtable(qq_group *group); -qq_group *qq_group_from_hashtable(PurpleConnection *gc, GHashTable *data); +qq_group *qq_room_create_by_hashtable(PurpleConnection *gc, GHashTable *data); void qq_group_refresh(PurpleConnection *gc, qq_group *group);
--- a/libpurple/protocols/qq/group_join.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_join.c Fri Sep 12 14:26:41 2008 +0000 @@ -38,14 +38,17 @@ #include "group_info.h" #include "group_join.h" #include "group_opt.h" +#include "group_conv.h" #include "group_search.h" #include "header_info.h" #include "packet_parse.h" #include "qq_network.h" +#include "qq_process.h" enum { - QQ_GROUP_JOIN_OK = 0x01, - QQ_GROUP_JOIN_NEED_AUTH = 0x02, + QQ_ROOM_JOIN_OK = 0x01, + QQ_ROOM_JOIN_NEED_AUTH = 0x02, + QQ_ROOM_JOIN_DENIED = 0x03, }; static void _qq_group_exit_with_gc_and_id(gc_and_uid *g) @@ -64,24 +67,28 @@ } /* send packet to join a group without auth */ -void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group) +void qq_request_room_join(PurpleConnection *gc, qq_group *group) { g_return_if_fail(group != NULL); - if (group->my_status == QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { - group->my_status = QQ_GROUP_MEMBER_STATUS_APPLYING; + if (group->my_role == QQ_ROOM_ROLE_NO) { + group->my_role = QQ_ROOM_ROLE_REQUESTING; qq_group_refresh(gc, group); } switch (group->auth_type) { - case QQ_GROUP_AUTH_TYPE_NO_AUTH: - case QQ_GROUP_AUTH_TYPE_NEED_AUTH: + case QQ_ROOM_AUTH_TYPE_NO_AUTH: + case QQ_ROOM_AUTH_TYPE_NEED_AUTH: break; - case QQ_GROUP_AUTH_TYPE_NO_ADD: - purple_notify_warning(gc, NULL, _("This group does not allow others to join"), NULL); - return; + case QQ_ROOM_AUTH_TYPE_NO_ADD: + if (group->my_role == QQ_ROOM_ROLE_NO + && group->my_role == QQ_ROOM_ROLE_REQUESTING) { + purple_notify_warning(gc, NULL, _("The Qun does not allow others to join"), NULL); + return; + } + break; default: - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown group auth type: %d\n", group->auth_type); + purple_debug_error("QQ", "Unknown room auth type: %d\n", group->auth_type); break; } @@ -99,10 +106,10 @@ group = qq_room_search_id(gc, id); if (group == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Can not find qq_group by internal_id: %d\n", id); + purple_debug_error("QQ", "Can not find qq_group by internal_id: %d\n", id); return; } else { /* everything is OK */ - qq_send_cmd_group_auth(gc, group, QQ_GROUP_AUTH_REQUEST_APPLY, 0, reason_utf8); + qq_send_cmd_group_auth(gc, group, QQ_ROOM_AUTH_REQUEST_APPLY, 0, reason_utf8); } } @@ -112,10 +119,9 @@ gc_and_uid *g; g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Group (internal id: %d) needs authentication\n", group->id); + purple_debug_info("QQ", "Group (internal id: %d) needs authentication\n", group->id); - msg = g_strdup_printf("Group \"%s\" needs authentication\n", group->group_name_utf8); + msg = g_strdup_printf("Group \"%s\" needs authentication\n", group->title_utf8); g = g_new0(gc_and_uid, 1); g->gc = gc; g->uid = group->id; @@ -125,7 +131,7 @@ _("Send"), G_CALLBACK(_qq_group_join_auth_with_gc_and_id), _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), - purple_connection_get_account(gc), group->group_name_utf8, NULL, + purple_connection_get_account(gc), group->title_utf8, NULL, g); g_free(msg); } @@ -143,8 +149,8 @@ else reason_qq = utf8_to_qq(reason_utf8, QQ_CHARSET_DEFAULT); - if (opt == QQ_GROUP_AUTH_REQUEST_APPLY) { - group->my_status = QQ_GROUP_MEMBER_STATUS_APPLYING; + if (opt == QQ_ROOM_AUTH_REQUEST_APPLY) { + group->my_role = QQ_ROOM_ROLE_REQUESTING; qq_group_refresh(gc, group); uid = 0; } @@ -173,8 +179,7 @@ qd = (qq_data *) gc->proto_data; if (len < 4) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid exit group reply, expect %d bytes, read %d bytes\n", 4, len); + purple_debug_error("QQ", "Invalid exit group reply, expect %d bytes, read %d bytes\n", 4, len); return; } @@ -189,7 +194,7 @@ purple_blist_remove_chat(chat); qq_group_delete_internal_record(qd, id); } - purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully left the group"), NULL); + purple_notify_info(gc, _("QQ Qun Operation"), _("Successed:"), _("Remove from Qun")); } /* Process the reply to group_auth subcmd */ @@ -203,16 +208,15 @@ qd = (qq_data *) gc->proto_data; if (len < 4) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid join group reply, expect %d bytes, read %d bytes\n", 4, len); + purple_debug_error("QQ", + "Invalid join room reply, expect %d bytes, read %d bytes\n", 4, len); return; } bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); - purple_notify_info(gc, _("QQ Group Auth"), - _("Your authorization request has been accepted by the QQ server"), NULL); + purple_notify_info(gc, _("QQ Qun Operation"), _("Successed:"), _("Join to Qun")); } /* process group cmd reply "join group" */ @@ -222,15 +226,16 @@ guint32 id; guint8 reply; qq_group *group; + gchar *msg; g_return_if_fail(data != NULL && len > 0); if (len < 5) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Invalid join group reply, expect %d bytes, read %d bytes\n", 5, len); return; } - + bytes = 0; bytes += qq_get32(&id, data + bytes); bytes += qq_get8(&reply, data + bytes); @@ -240,26 +245,32 @@ /* need to check if group is NULL or not. */ g_return_if_fail(group != NULL); switch (reply) { - case QQ_GROUP_JOIN_OK: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed joining group \"%s\"\n", group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + case QQ_ROOM_JOIN_OK: + purple_debug_info("QQ", "Successed in joining group \"%s\"\n", group->title_utf8); + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); /* this must be shown before getting online members */ - qq_group_conv_show_window(gc, group); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); + qq_room_conv_create(gc, group); break; - case QQ_GROUP_JOIN_NEED_AUTH: - purple_debug(PURPLE_DEBUG_INFO, "QQ", + case QQ_ROOM_JOIN_NEED_AUTH: + purple_debug_info("QQ", "Fail joining group [%d] %s, needs authentication\n", - group->ext_id, group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + group->ext_id, group->title_utf8); + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); _qq_group_join_auth(gc, group); break; + case QQ_ROOM_JOIN_DENIED: + msg = g_strdup_printf(_("Qun %d denied to join"), group->ext_id); + purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), msg); + g_free(msg); + break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Error joining group [%d] %s, unknown reply: 0x%02x\n", - group->ext_id, group->group_name_utf8, reply); + purple_debug_info("QQ", + "Failed joining group [%d] %s, unknown reply: 0x%02x\n", + group->ext_id, group->title_utf8, reply); + + purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), _("Join Qun, Unknow Reply")); } } @@ -274,7 +285,7 @@ g_return_if_fail(data != NULL); qd = (qq_data *) gc->proto_data; - ext_id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID); + ext_id_ptr = g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID); g_return_if_fail(ext_id_ptr != NULL); errno = 0; ext_id = strtol(ext_id_ptr, NULL, 10); @@ -286,7 +297,7 @@ group = qq_room_search_ext_id(gc, ext_id); if (group) { - qq_send_cmd_group_join_group(gc, group); + qq_request_room_join(gc, group); } else { qq_set_pending_id(&qd->joining_groups, ext_id, TRUE); qq_send_cmd_group_search_group(gc, ext_id); @@ -301,7 +312,7 @@ g_return_if_fail(data != NULL); - id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID); + id_ptr = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID); id = strtol(id_ptr, NULL, 10); g_return_if_fail(id > 0); @@ -312,8 +323,7 @@ purple_request_action(gc, _("QQ Qun Operation"), _("Are you sure you want to leave this Qun?"), - _ - ("Note, if you are the creator, \nthis operation will eventually remove this Qun."), + _("Note, if you are the creator, \nthis operation will eventually remove this Qun."), 1, purple_connection_get_account(gc), NULL, NULL, g, 2, _("Cancel"),
--- a/libpurple/protocols/qq/group_join.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_join.h Fri Sep 12 14:26:41 2008 +0000 @@ -30,20 +30,20 @@ #include "group.h" enum { - QQ_GROUP_AUTH_TYPE_NO_AUTH = 0x01, - QQ_GROUP_AUTH_TYPE_NEED_AUTH = 0x02, - QQ_GROUP_AUTH_TYPE_NO_ADD = 0x03 + QQ_ROOM_AUTH_TYPE_NO_AUTH = 0x01, + QQ_ROOM_AUTH_TYPE_NEED_AUTH = 0x02, + QQ_ROOM_AUTH_TYPE_NO_ADD = 0x03 }; enum { - QQ_GROUP_AUTH_REQUEST_APPLY = 0x01, - QQ_GROUP_AUTH_REQUEST_APPROVE = 0x02, - QQ_GROUP_AUTH_REQUEST_REJECT = 0x03 + QQ_ROOM_AUTH_REQUEST_APPLY = 0x01, + QQ_ROOM_AUTH_REQUEST_APPROVE = 0x02, + QQ_ROOM_AUTH_REQUEST_REJECT = 0x03 }; void qq_send_cmd_group_auth(PurpleConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8); void qq_group_join(PurpleConnection *gc, GHashTable *data); -void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group); +void qq_request_room_join(PurpleConnection *gc, qq_group *group); void qq_group_exit(PurpleConnection *gc, GHashTable *data); void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc); void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc);
--- a/libpurple/protocols/qq/group_opt.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.c Fri Sep 12 14:26:41 2008 +0000 @@ -38,6 +38,7 @@ #include "header_info.h" #include "packet_parse.h" #include "qq_network.h" +#include "qq_process.h" #include "utils.h" static int _compare_guint32(const void *a, @@ -67,7 +68,7 @@ } data_len = 6 + count * 4; data = g_newa(guint8, data_len); - + bytes = 0; bytes += qq_put8(data + bytes, operation); for (i = 0; i < count; i++) @@ -88,7 +89,7 @@ g_return_if_fail(g != NULL && g->gc != NULL && g->id > 0 && g->member > 0); group = qq_room_search_id(g->gc, g->id); g_return_if_fail(group != NULL); - qq_send_cmd_group_auth(g->gc, group, QQ_GROUP_AUTH_REQUEST_REJECT, g->member, msg_utf8); + qq_send_cmd_group_auth(g->gc, group, QQ_ROOM_AUTH_REQUEST_REJECT, g->member, msg_utf8); g_free(g); } @@ -111,11 +112,11 @@ g_return_if_fail(g != NULL && g->gc != NULL && g->member > 0); msg1 = g_strdup_printf(_("You rejected %d's request"), g->member); - msg2 = g_strdup(_("Enter your reason:")); + msg2 = g_strdup(_("Message:")); nombre = uid_to_purple_name(g->member); purple_request_input(g->gc, /* title */ NULL, msg1, msg2, - _("Sorry, you are not my type..."), /* multiline */ TRUE, /* masked */ FALSE, + _("Sorry, you are not my style..."), /* multiline */ TRUE, /* masked */ FALSE, /* hint */ NULL, _("Send"), G_CALLBACK(_qq_group_reject_application_real), _("Cancel"), G_CALLBACK(_qq_group_do_nothing_with_struct), @@ -133,7 +134,7 @@ g_return_if_fail(g != NULL && g->gc != NULL && g->id > 0 && g->member > 0); group = qq_room_search_id(g->gc, g->id); g_return_if_fail(group != NULL); - qq_send_cmd_group_auth(g->gc, group, QQ_GROUP_AUTH_REQUEST_APPROVE, g->member, ""); + qq_send_cmd_group_auth(g->gc, group, QQ_ROOM_AUTH_REQUEST_APPROVE, g->member, ""); qq_group_find_or_add_member(g->gc, group, g->member); g_free(g); } @@ -189,9 +190,9 @@ qq_group_find_or_add_member(gc, group, add_members[i]); if (del > 0) - _qq_group_member_opt(gc, group, QQ_GROUP_MEMBER_DEL, del_members); + _qq_group_member_opt(gc, group, QQ_ROOM_MEMBER_DEL, del_members); if (add > 0) - _qq_group_member_opt(gc, group, QQ_GROUP_MEMBER_ADD, add_members); + _qq_group_member_opt(gc, group, QQ_ROOM_MEMBER_ADD, add_members); } void qq_group_process_modify_members_reply(guint8 *data, gint len, PurpleConnection *gc) @@ -209,9 +210,9 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in modify members for Qun %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in modify members for room %d\n", group->ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully modified Qun member"), NULL); + purple_notify_info(gc, _("QQ Qun Operation"), _("Successed:"), _("Change Qun member")); } void qq_room_change_info(PurpleConnection *gc, qq_group *group) @@ -223,8 +224,8 @@ g_return_if_fail(group != NULL); - group_name = group->group_name_utf8 == NULL ? "" : utf8_to_qq(group->group_name_utf8, QQ_CHARSET_DEFAULT); - group_desc = group->group_desc_utf8 == NULL ? "" : utf8_to_qq(group->group_desc_utf8, QQ_CHARSET_DEFAULT); + group_name = group->title_utf8 == NULL ? "" : utf8_to_qq(group->title_utf8, QQ_CHARSET_DEFAULT); + group_desc = group->desc_utf8 == NULL ? "" : utf8_to_qq(group->desc_utf8, QQ_CHARSET_DEFAULT); notice = group->notice_utf8 == NULL ? "" : utf8_to_qq(group->notice_utf8, QQ_CHARSET_DEFAULT); data_len = 64 + strlen(group_name) + strlen(group_desc) + strlen(notice); @@ -237,7 +238,7 @@ /* 007-008 */ bytes += qq_put16(data + bytes, 0x0000); /* 009-010 */ - bytes += qq_put16(data + bytes, group->group_category); + bytes += qq_put16(data + bytes, group->category); bytes += qq_put8(data + bytes, strlen(group_name)); bytes += qq_putdata(data + bytes, (guint8 *) group_name, strlen(group_name)); @@ -251,7 +252,7 @@ bytes += qq_putdata(data + bytes, (guint8 *) group_desc, strlen(group_desc)); if (bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Overflow in qq_room_change_info, max %d bytes, now %d bytes\n", data_len, bytes); return; @@ -274,10 +275,10 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in modify info for Qun %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in modify info for Qun %d\n", group->ext_id); qq_group_refresh(gc, group); - purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully modified Qun information"), NULL); + purple_notify_info(gc, _("QQ Qun Operation"), _("Successed:"), _("Change Qun information")); } /* we create a very simple group first, and then let the user to modify */ @@ -297,9 +298,9 @@ bytes = 0; /* we create the simpleset group, only group name is given */ /* 001 */ - bytes += qq_put8(data + bytes, QQ_GROUP_TYPE_PERMANENT); + bytes += qq_put8(data + bytes, QQ_ROOM_TYPE_PERMANENT); /* 002 */ - bytes += qq_put8(data + bytes, QQ_GROUP_AUTH_TYPE_NEED_AUTH); + bytes += qq_put8(data + bytes, QQ_ROOM_AUTH_TYPE_NEED_AUTH); /* 003-004 */ bytes += qq_put16(data + bytes, 0x0000); /* 005-006 */ @@ -313,7 +314,7 @@ bytes += qq_put32(data + bytes, qd->uid); /* I am member of coz */ if (bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Overflow in qq_room_create, max %d bytes, now %d bytes\n", data_len, bytes); return; @@ -352,14 +353,14 @@ g_return_if_fail(id > 0 && ext_id); group = qq_group_create_internal_record(gc, id, ext_id, NULL); - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_ADMIN; + group->my_role = QQ_ROOM_ROLE_ADMIN; group->creator_uid = qd->uid; qq_group_refresh(gc, group); qq_send_room_cmd_only(gc, QQ_ROOM_CMD_ACTIVATE, id); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, id); + qq_update_room(gc, 0, group->id); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in create Qun, external ID %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in create Qun, external ID %d\n", group->ext_id); g = g_new0(gc_and_uid, 1); g->gc = gc; @@ -368,7 +369,7 @@ purple_request_action(gc, _("QQ Qun Operation"), _("You have successfully created a Qun"), _ - ("Would you like to set up the Qun details now?"), + ("Would you like to set up the detail information now?"), 1, purple_connection_get_account(gc), NULL, NULL, g, 2, @@ -391,7 +392,7 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in activate Qun %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in activate Qun %d\n", group->ext_id); } void qq_group_manage_group(PurpleConnection *gc, GHashTable *data) @@ -402,7 +403,7 @@ g_return_if_fail(data != NULL); - id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID); + id_ptr = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID); id = strtol(id_ptr, NULL, 10); g_return_if_fail(id > 0);
--- a/libpurple/protocols/qq/group_opt.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.h Fri Sep 12 14:26:41 2008 +0000 @@ -38,13 +38,13 @@ } group_member_opt; enum { - QQ_GROUP_TYPE_PERMANENT = 0x01, - QQ_GROUP_TYPE_TEMPORARY + QQ_ROOM_TYPE_PERMANENT = 0x01, + QQ_ROOM_TYPE_TEMPORARY }; enum { - QQ_GROUP_MEMBER_ADD = 0x01, - QQ_GROUP_MEMBER_DEL + QQ_ROOM_MEMBER_ADD = 0x01, + QQ_ROOM_MEMBER_DEL }; void qq_group_modify_members(PurpleConnection *gc, qq_group *group, guint32 *new_members);
--- a/libpurple/protocols/qq/group_search.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/group_search.c Fri Sep 12 14:26:41 2008 +0000 @@ -38,8 +38,8 @@ #include "qq_network.h" enum { - QQ_GROUP_SEARCH_TYPE_BY_ID = 0x01, - QQ_GROUP_SEARCH_TYPE_DEMO = 0x02 + QQ_ROOM_SEARCH_TYPE_BY_ID = 0x01, + QQ_ROOM_SEARCH_TYPE_DEMO = 0x02 }; /* send packet to search for qq_group */ @@ -49,7 +49,7 @@ gint bytes = 0; guint8 type; - type = (ext_id == 0x00000000) ? QQ_GROUP_SEARCH_TYPE_DEMO : QQ_GROUP_SEARCH_TYPE_BY_ID; + type = (ext_id == 0x00000000) ? QQ_ROOM_SEARCH_TYPE_DEMO : QQ_ROOM_SEARCH_TYPE_BY_ID; bytes = 0; bytes += qq_put8(raw_data + bytes, type); @@ -63,21 +63,21 @@ PurpleRoomlistRoom *room; gchar field[11]; - room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, group->group_name_utf8, NULL); + room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, group->title_utf8, NULL); g_snprintf(field, sizeof(field), "%d", group->ext_id); purple_roomlist_room_add_field(qd->roomlist, room, field); g_snprintf(field, sizeof(field), "%d", group->creator_uid); purple_roomlist_room_add_field(qd->roomlist, room, field); - purple_roomlist_room_add_field(qd->roomlist, room, group->group_desc_utf8); + purple_roomlist_room_add_field(qd->roomlist, room, group->desc_utf8); g_snprintf(field, sizeof(field), "%d", group->id); purple_roomlist_room_add_field(qd->roomlist, room, field); g_snprintf(field, sizeof(field), "%d", group->type8); purple_roomlist_room_add_field(qd->roomlist, room, field); g_snprintf(field, sizeof(field), "%d", group->auth_type); purple_roomlist_room_add_field(qd->roomlist, room, field); - g_snprintf(field, sizeof(field), "%d", group->group_category); + g_snprintf(field, sizeof(field), "%d", group->category); purple_roomlist_room_add_field(qd->roomlist, room, field); - purple_roomlist_room_add_field(qd->roomlist, room, group->group_name_utf8); + purple_roomlist_room_add_field(qd->roomlist, room, group->title_utf8); purple_roomlist_room_add(qd->roomlist, room); purple_roomlist_set_in_progress(qd->roomlist, FALSE); @@ -109,14 +109,14 @@ bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); - bytes += qq_get32(&(group.group_category), data + bytes); - bytes += convert_as_pascal_string(data + bytes, &(group.group_name_utf8), QQ_CHARSET_DEFAULT); + bytes += qq_get32(&(group.category), data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(group.title_utf8), QQ_CHARSET_DEFAULT); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get8(&(group.auth_type), data + bytes); - bytes += convert_as_pascal_string(data + bytes, &(group.group_desc_utf8), QQ_CHARSET_DEFAULT); + bytes += convert_as_pascal_string(data + bytes, &(group.desc_utf8), QQ_CHARSET_DEFAULT); /* end of one qq_group */ if(bytes != len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); } @@ -124,9 +124,9 @@ if (pending_id != NULL) { qq_set_pending_id(&qd->joining_groups, group.ext_id, FALSE); if (qq_room_search_id(gc, group.id) == NULL) - qq_group_create_internal_record(gc, - group.id, group.ext_id, group.group_name_utf8); - qq_send_cmd_group_join_group(gc, &group); + qq_group_create_internal_record(gc, + group.id, group.ext_id, group.title_utf8); + qq_request_room_join(gc, &group); } else { _qq_setup_roomlist(qd, &group); }
--- a/libpurple/protocols/qq/header_info.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/header_info.c Fri Sep 12 14:26:41 2008 +0000 @@ -122,7 +122,7 @@ case QQ_SERVER_0100: return "QQ Server 0100"; default: - return "Unknown"; + return "Unknown Version"; } } @@ -138,16 +138,16 @@ return "QQ_CMD_UPDATE_INFO"; case QQ_CMD_SEARCH_USER: return "QQ_CMD_SEARCH_USER"; - case QQ_CMD_GET_USER_INFO: - return "QQ_CMD_GET_USER_INFO"; + case QQ_CMD_GET_BUDDY_INFO: + return "QQ_CMD_GET_BUDDY_INFO"; case QQ_CMD_ADD_BUDDY_WO_AUTH: return "QQ_CMD_ADD_BUDDY_WO_AUTH"; case QQ_CMD_DEL_BUDDY: return "QQ_CMD_DEL_BUDDY"; case QQ_CMD_BUDDY_AUTH: return "QQ_CMD_BUDDY_AUTH"; - case QQ_CMD_CHANGE_ONLINE_STATUS: - return "QQ_CMD_CHANGE_ONLINE_STATUS"; + case QQ_CMD_CHANGE_STATUS: + return "QQ_CMD_CHANGE_STATUS"; case QQ_CMD_ACK_SYS_MSG: return "QQ_CMD_ACK_SYS_MSG"; case QQ_CMD_SEND_IM: @@ -172,10 +172,10 @@ return "QQ_CMD_TOKEN"; case QQ_CMD_RECV_MSG_SYS: return "QQ_CMD_RECV_MSG_SYS"; - case QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS: - return "QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS"; + case QQ_CMD_BUDDY_CHANGE_STATUS: + return "QQ_CMD_BUDDY_CHANGE_STATUS"; default: - return "Unknown"; + return "Unknown CMD"; } } @@ -204,8 +204,8 @@ return "QQ_ROOM_CMD_SEND_MSG"; case QQ_ROOM_CMD_GET_ONLINES: return "QQ_ROOM_CMD_GET_ONLINES"; - case QQ_ROOM_CMD_GET_MEMBER_INFO: - return "QQ_ROOM_CMD_GET_MEMBER_INFO"; + case QQ_ROOM_CMD_GET_BUDDIES: + return "QQ_ROOM_CMD_GET_BUDDIES"; case QQ_ROOM_CMD_CHANGE_CARD: return "QQ_ROOM_CMD_CHANGE_CARD"; case QQ_ROOM_CMD_GET_REALNAMES: @@ -231,6 +231,6 @@ case QQ_ROOM_CMD_TEMP_GET_MEMBERS: return "QQ_ROOM_CMD_TEMP_GET_MEMBERS"; default: - return "Unknown QQ Room Command"; + return "Unknown Room Command"; } }
--- a/libpurple/protocols/qq/header_info.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/header_info.h Fri Sep 12 14:26:41 2008 +0000 @@ -43,11 +43,11 @@ QQ_CMD_KEEP_ALIVE = 0x0002, /* get onlines from tencent */ QQ_CMD_UPDATE_INFO = 0x0004, /* update information */ QQ_CMD_SEARCH_USER = 0x0005, /* search for user */ - QQ_CMD_GET_USER_INFO = 0x0006, /* get user information */ + QQ_CMD_GET_BUDDY_INFO = 0x0006, /* get user information */ QQ_CMD_ADD_BUDDY_WO_AUTH = 0x0009, /* add buddy without auth */ QQ_CMD_DEL_BUDDY = 0x000a, /* delete a buddy */ QQ_CMD_BUDDY_AUTH = 0x000b, /* buddy authentication */ - QQ_CMD_CHANGE_ONLINE_STATUS = 0x000d, /* change my online status */ + QQ_CMD_CHANGE_STATUS = 0x000d, /* change my online status */ QQ_CMD_ACK_SYS_MSG = 0x0012, /* ack system message */ QQ_CMD_SEND_IM = 0x0016, /* send message */ QQ_CMD_RECV_IM = 0x0017, /* receive message */ @@ -59,11 +59,11 @@ QQ_CMD_GET_BUDDIES_ONLINE = 0x0027, /* get online buddies list */ QQ_CMD_CELL_PHONE_2 = 0x0029, /* cell phone 2 */ QQ_CMD_ROOM = 0x0030, /* room command */ - QQ_CMD_GET_BUDDIES_AND_ROOMS = 0x0058, + QQ_CMD_GET_BUDDIES_AND_ROOMS = 0x0058, QQ_CMD_GET_LEVEL = 0x005C, /* get level for one or more buddies */ QQ_CMD_TOKEN = 0x0062, /* get login token */ QQ_CMD_RECV_MSG_SYS = 0x0080, /* receive a system message */ - QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS = 0x0081, /* buddy change status */ + QQ_CMD_BUDDY_CHANGE_STATUS = 0x0081, /* buddy change status */ }; const gchar *qq_get_cmd_desc(gint type); @@ -80,7 +80,7 @@ QQ_ROOM_CMD_QUIT = 0x09, QQ_ROOM_CMD_SEND_MSG = 0x0a, QQ_ROOM_CMD_GET_ONLINES = 0x0b, - QQ_ROOM_CMD_GET_MEMBER_INFO = 0x0c, + QQ_ROOM_CMD_GET_BUDDIES = 0x0c, QQ_ROOM_CMD_CHANGE_CARD = 0x0E, QQ_ROOM_CMD_GET_REALNAMES = 0x0F,
--- a/libpurple/protocols/qq/im.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/im.c Fri Sep 12 14:26:41 2008 +0000 @@ -209,21 +209,17 @@ return "QQ_RECV_IM_TEMP_QUN_IM"; case QQ_RECV_IM_QUN_IM: return "QQ_RECV_IM_QUN_IM"; + case QQ_RECV_IM_NEWS: + return "QQ_RECV_IM_NEWS"; + case QQ_RECV_IM_FROM_BUDDY_2006: + return "QQ_RECV_IM_FROM_BUDDY_2006"; + case QQ_RECV_IM_FROM_UNKNOWN_2006: + return "QQ_RECV_IM_FROM_UNKNOWN_2006"; default: return "QQ_RECV_IM_UNKNOWN"; } } -/* when we receive a message, - * we send an ACK which is the first 16 bytes of incoming packet */ -static void _qq_send_packet_recv_im_ack(PurpleConnection *gc, guint16 seq, guint8 *data) -{ - qq_data *qd; - - qd = (qq_data *) gc->proto_data; - qq_send_cmd_detail(qd, QQ_CMD_RECV_IM, seq, FALSE, data, 16); -} - /* read the common parts of the normal_im, * returns the bytes read if succeed, or -1 if there is any error */ static gint _qq_normal_im_common_read(guint8 *data, gint len, qq_recv_normal_im_common *common) @@ -240,13 +236,64 @@ bytes += qq_get16(&(common->normal_im_type), data + bytes); if (bytes != 28) { /* read common place fail */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Expect 28 bytes, read %d bytes\n", bytes); + purple_debug_error("QQ", "Expect 28 bytes, read %d bytes\n", bytes); return -1; } return bytes; } +static void _qq_process_recv_news(guint8 *data, gint data_len, PurpleConnection *gc) +{ + qq_data *qd = (qq_data *) gc->proto_data; + gint bytes; + guint8 *temp; + guint8 temp_len; + gchar *title, *brief, *url; + gchar *title_utf8; + gchar *content, *content_utf8; + + g_return_if_fail(data != NULL && data_len != 0); + +#if 0 + qq_show_packet("Rcv news", data, data_len); +#endif + + temp = g_newa(guint8, data_len); + bytes = 4; /* ignore unknown 4 bytes */ + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + title = g_strndup((gchar *)temp, temp_len); + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + brief = g_strndup((gchar *)temp, temp_len); + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + url = g_strndup((gchar *)temp, temp_len); + + title_utf8 = qq_to_utf8(title, QQ_CHARSET_DEFAULT); + content = g_strdup_printf(_("%s\n\n%s"), brief, url); + content_utf8 = qq_to_utf8(content, QQ_CHARSET_DEFAULT); + + if (qd->is_show_news) { + purple_notify_info(gc, _("QQ Server News"), title_utf8, content_utf8); + } else { + purple_debug_info("QQ", "QQ Server news:\n%s\n%s", title_utf8, content_utf8); + } + g_free(title); + g_free(title_utf8); + g_free(brief); + g_free(url); + g_free(content); + g_free(content_utf8); +} + /* process received normal text IM */ static void _qq_process_recv_normal_im_text(guint8 *data, gint len, qq_recv_normal_im_common *common, PurpleConnection *gc) { @@ -266,7 +313,7 @@ /* now it is QQ_NORMAL_IM_TEXT */ /* if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); + purple_debug_warning("QQ", "Received normal IM text is empty\n"); return; } else */ @@ -313,9 +360,9 @@ } qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (qq_b != NULL) { - qq_b->client_version = common->sender_ver; + qq_b->client_version = common->sender_ver; } - + purple_msg_type = (im_text->msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0; msg_with_purple_smiley = qq_smiley_to_purple(im_text->msg); @@ -350,19 +397,18 @@ bytes = _qq_normal_im_common_read(data, len, common); if (bytes < 0) { - purple_debug (PURPLE_DEBUG_ERROR, "QQ", - "Fail read the common part of normal IM\n"); + purple_debug_error("QQ", "Fail read the common part of normal IM\n"); return; } switch (common->normal_im_type) { case QQ_NORMAL_IM_TEXT: - purple_debug (PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Normal IM, text type:\n [%d] => [%d], src: %s (%04X)\n", common->sender_uid, common->receiver_uid, qq_get_ver_desc (common->sender_ver), common->sender_ver); if (bytes >= len - 1) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); + purple_debug_warning("QQ", "Received normal IM text is empty\n"); return; } _qq_process_recv_normal_im_text(data + bytes, len - bytes, common, gc); @@ -382,16 +428,50 @@ case QQ_NORMAL_IM_FILE_NOTIFY: qq_process_recv_file_notify(data + bytes, len - bytes, common->sender_uid, gc); break; + case QQ_NORMAL_IM_FILE_REQUEST_TCP: + /* Check ReceivedFileIM::parseContents in eva*/ + /* some client use this function for detect invisable buddy*/ + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REQUEST_TCP\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_APPROVE_TCP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_APPROVE_TCP\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_REJECT_TCP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REJECT_TCP\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_PASV: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_PASV\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_REQUEST_UDP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REQUEST_TCP\n"); + qq_show_packet ("QQ", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_REQUEST_ACCEPT: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_REQUEST_ACCEPT\n"); + qq_show_packet ("QQ", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_REQUEST_CANCEL: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_REQUEST_CANCEL\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_NOTIFY_IP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_NOTIFY_IP\n"); + qq_show_packet ("Not support", data, len); + break; default: im_unprocessed = g_newa (qq_recv_normal_im_unprocessed, 1); im_unprocessed->common = common; im_unprocessed->unknown = data + bytes; im_unprocessed->length = len - bytes; /* a simple process here, maybe more later */ - purple_debug (PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Normal IM, unprocessed type [0x%04x], len %d\n", common->normal_im_type, im_unprocessed->length); - qq_show_packet ("QQ unk-im", im_unprocessed->unknown, im_unprocessed->length); + qq_show_packet ("QQ", im_unprocessed->unknown, im_unprocessed->length); return; } } @@ -412,7 +492,7 @@ reply = strtol(segments[0], NULL, 10); if (reply == QQ_RECV_SYS_IM_KICK_OUT) - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "We are kicked out by QQ server\n"); + purple_debug_warning("QQ", "We are kicked out by QQ server\n"); msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); purple_notify_warning(gc, NULL, _("System Message"), msg_utf8); } @@ -475,7 +555,7 @@ g_datalist_clear(&attribs); } - purple_debug(PURPLE_DEBUG_INFO, "QQ_MESG", "send mesg: %s\n", msg); + purple_debug_info("QQ_MESG", "send mesg: %s\n", msg); msg_filtered = purple_markup_strip_html(msg); msg_len = strlen(msg_filtered); now = time(NULL); @@ -526,9 +606,9 @@ qq_show_packet("QQ_raw_data debug", raw_data, bytes); if (bytes == raw_len) /* create packet OK */ - qq_send_cmd(qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Fail creating send_im packet, expect %d bytes, build %d bytes\n", raw_len, bytes); if (font_color) @@ -549,10 +629,10 @@ qd = gc->proto_data; if (data[0] != QQ_SEND_IM_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Send IM fail\n"); + purple_debug_warning("QQ", "Send IM fail\n"); purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL); } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "IM ACK OK\n"); + purple_debug_info("QQ", "IM ACK OK\n"); } } @@ -569,16 +649,17 @@ qd = (qq_data *) gc->proto_data; if (data_len < 16) { /* we need to ack with the first 16 bytes */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM is too short\n"); + purple_debug_error("QQ", "MSG is too short\n"); return; } else { - _qq_send_packet_recv_im_ack(gc, seq, data); + /* when we receive a message, + * we send an ACK which is the first 16 bytes of incoming packet */ + qq_send_server_reply(gc, QQ_CMD_RECV_IM, seq, data, 16); } /* check len first */ if (data_len < 20) { /* length of im_header */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail read recv IM header, len should longer than 20 bytes, read %d bytes\n", data_len); + purple_debug_error("QQ", "Invald MSG header, len %d < 20\n", data_len); return; } @@ -594,77 +675,71 @@ /* im_header prepared */ if (im_header->receiver_uid != qd->uid) { /* should not happen */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM to [%d], NOT me\n", im_header->receiver_uid); + purple_debug_error("QQ", "MSG to [%d], NOT me\n", im_header->receiver_uid); return; } /* check bytes */ if (bytes >= data_len - 1) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received IM is empty\n"); + purple_debug_warning("QQ", "Empty MSG\n"); return; } switch (im_header->im_type) { + case QQ_RECV_IM_NEWS: + _qq_process_recv_news(data + bytes, data_len - bytes, gc); + break; + case QQ_RECV_IM_FROM_BUDDY_2006: + case QQ_RECV_IM_FROM_UNKNOWN_2006: + case QQ_RECV_IM_TO_UNKNOWN: case QQ_RECV_IM_TO_BUDDY: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from buddy [%d], I am in his/her buddy list\n", im_header->sender_uid); - _qq_process_recv_normal_im(data + bytes, data_len - bytes, gc); /* position and rest length */ - break; - case QQ_RECV_IM_TO_UNKNOWN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from buddy [%d], I am a stranger to him/her\n", im_header->sender_uid); + purple_debug_info("QQ", "MSG from buddy [%d]\n", im_header->sender_uid); _qq_process_recv_normal_im(data + bytes, data_len - bytes, gc); break; case QQ_RECV_IM_UNKNOWN_QUN_IM: case QQ_RECV_IM_TEMP_QUN_IM: case QQ_RECV_IM_QUN_IM: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "IM from group, internal_id [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "MSG from room [%d]\n", im_header->sender_uid); /* sender_uid is in fact id */ - qq_process_recv_group_im(data + bytes, data_len - bytes, im_header->sender_uid, gc, im_header->im_type); + qq_process_room_msg_normal(data + bytes, data_len - bytes, im_header->sender_uid, gc, im_header->im_type); break; case QQ_RECV_IM_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, added by group internal_id [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "Notice from [%d], Added\n", im_header->sender_uid); /* sender_uid is group id * we need this to create a dummy group and add to blist */ - qq_process_recv_group_im_been_added(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_added(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_DEL_FROM_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, removed by group internal_ID [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "Notice from room [%d], Removed\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_been_removed(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_removed(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_APPLY_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, apply to join group internal_ID [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "Notice from room [%d], Joined\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_apply_join(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_apply_join(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM for group system info, approved by group internal_id [%d]\n", + purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_been_approved(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_approved(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM for group system info, rejected by group internal_id [%d]\n", + purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_been_rejected(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_rejected(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_SYS_NOTIFICATION: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from [%d], should be a system administrator\n", im_header->sender_uid); + purple_debug_info("QQ", "Admin notice from [%d]\n", im_header->sender_uid); _qq_process_recv_sys_im(data + bytes, data_len - bytes, gc); break; default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "IM from [%d], [0x%02x] %s is not processed\n", - im_header->sender_uid, - im_header->im_type, qq_get_recv_im_type_str(im_header->im_type)); + purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%02x]\n", + im_header->sender_uid, qq_get_recv_im_type_str(im_header->im_type), + im_header->im_type); + qq_show_packet("Unknown MSG type", data, data_len); } }
--- a/libpurple/protocols/qq/im.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/im.h Fri Sep 12 14:26:41 2008 +0000 @@ -41,6 +41,7 @@ enum { QQ_RECV_IM_TO_BUDDY = 0x0009, QQ_RECV_IM_TO_UNKNOWN = 0x000a, + QQ_RECV_IM_NEWS = 0x0018, QQ_RECV_IM_UNKNOWN_QUN_IM = 0x0020, QQ_RECV_IM_ADD_TO_QUN = 0x0021, QQ_RECV_IM_DEL_FROM_QUN = 0x0022, @@ -50,7 +51,9 @@ QQ_RECV_IM_CREATE_QUN = 0x0026, QQ_RECV_IM_TEMP_QUN_IM = 0x002A, QQ_RECV_IM_QUN_IM = 0x002B, - QQ_RECV_IM_SYS_NOTIFICATION = 0x0030 + QQ_RECV_IM_SYS_NOTIFICATION = 0x0030, + QQ_RECV_IM_FROM_BUDDY_2006 = 0x0084, + QQ_RECV_IM_FROM_UNKNOWN_2006 = 0x0085, }; guint8 *qq_get_send_im_tail(const gchar *font_color,
--- a/libpurple/protocols/qq/packet_parse.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.c Fri Sep 12 14:26:41 2008 +0000 @@ -46,8 +46,8 @@ memcpy(&b_dest, buf, sizeof(b_dest)); *b = b_dest; #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get8] buf %p\n", (void *)buf); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b); + purple_debug_info("QQ", "[DBG][get8] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b); #endif return sizeof(b_dest); } @@ -61,8 +61,8 @@ memcpy(&w_dest, buf, sizeof(w_dest)); *w = g_ntohs(w_dest); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get16] buf %p\n", (void *)buf); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w); + purple_debug_info("QQ", "[DBG][get16] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w); #endif return sizeof(w_dest); } @@ -75,8 +75,8 @@ memcpy(&dw_dest, buf, sizeof(dw_dest)); *dw = g_ntohl(dw_dest); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get32] buf %p\n", (void *)buf); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw); + purple_debug_info("QQ", "[DBG][get32] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw); #endif return sizeof(dw_dest); } @@ -93,7 +93,7 @@ { memcpy(data, buf, datalen); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getdata] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][getdata] buf %p\n", (void *)buf); #endif return datalen; } @@ -107,12 +107,12 @@ guint32 dw_dest; memcpy(&dw_dest, buf, sizeof(dw_dest)); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] buf %p\n", (void *)buf); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] dw_dest before 0x%08x\n", dw_dest); + purple_debug_info("QQ", "[DBG][getime] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][getime] dw_dest before 0x%08x\n", dw_dest); #endif dw_dest = g_ntohl(dw_dest); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest); + purple_debug_info("QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest); #endif memcpy(t, &dw_dest, sizeof(dw_dest)); return sizeof(dw_dest); @@ -125,8 +125,8 @@ { memcpy(buf, &b, sizeof(b)); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put8] buf %p\n", (void *)buf); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put8] b 0x%02x\n", b); + purple_debug_info("QQ", "[DBG][put8] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][put8] b 0x%02x\n", b); #endif return sizeof(b); } @@ -139,8 +139,8 @@ guint16 w_porter; w_porter = g_htons(w); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put16] buf %p\n", (void *)buf); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put16] w 0x%04x, w_porter 0x%04x\n", w, w_porter); + purple_debug_info("QQ", "[DBG][put16] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][put16] w 0x%04x, w_porter 0x%04x\n", w, w_porter); #endif memcpy(buf, &w_porter, sizeof(w_porter)); return sizeof(w_porter); @@ -154,8 +154,8 @@ guint32 dw_porter; dw_porter = g_htonl(dw); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put32] buf %p\n", (void *)buf); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter); + purple_debug_info("QQ", "[DBG][put32] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter); #endif memcpy(buf, &dw_porter, sizeof(dw_porter)); return sizeof(dw_porter); @@ -173,7 +173,7 @@ { memcpy(buf, data, datalen); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][putdata] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][putdata] buf %p\n", (void *)buf); #endif return datalen; }
--- a/libpurple/protocols/qq/qq.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Fri Sep 12 14:26:41 2008 +0000 @@ -24,10 +24,6 @@ #include "internal.h" -#ifdef _WIN32 -#define random rand -#endif - #include "accountopt.h" #include "debug.h" #include "notify.h" @@ -62,79 +58,69 @@ #define OPENQ_AUTHOR "Puzzlebird" #define OPENQ_WEBSITE "http://openq.sourceforge.net" -#define QQ_TCP_PORT 8000 -#define QQ_UDP_PORT 8000 +static GList *server_list_build(gchar select) +{ + GList *list = NULL; -static void server_list_create(PurpleAccount *account) { + if ( select == 'T' || select == 'A') { + list = g_list_append(list, "tcpconn.tencent.com:8000"); + list = g_list_append(list, "tcpconn2.tencent.com:8000"); + list = g_list_append(list, "tcpconn3.tencent.com:8000"); + list = g_list_append(list, "tcpconn4.tencent.com:8000"); + list = g_list_append(list, "tcpconn5.tencent.com:8000"); + list = g_list_append(list, "tcpconn6.tencent.com:8000"); + } + if ( select == 'U' || select == 'A') { + list = g_list_append(list, "sz.tencent.com:8000"); + list = g_list_append(list, "sz2.tencent.com:8000"); + list = g_list_append(list, "sz3.tencent.com:8000"); + list = g_list_append(list, "sz4.tencent.com:8000"); + list = g_list_append(list, "sz5.tencent.com:8000"); + list = g_list_append(list, "sz6.tencent.com:8000"); + list = g_list_append(list, "sz7.tencent.com:8000"); + list = g_list_append(list, "sz8.tencent.com:8000"); + list = g_list_append(list, "sz9.tencent.com:8000"); + } + return list; +} + +static void server_list_create(PurpleAccount *account) +{ PurpleConnection *gc; qq_data *qd; + PurpleProxyInfo *gpi; const gchar *user_server; - int port; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create server list\n"); gc = purple_account_get_connection(account); g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = gc->proto_data; + gpi = purple_proxy_get_setup(account); + qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE); - port = purple_account_get_int(account, "port", 0); - if (port == 0) { - if (qd->use_tcp) { - port = QQ_TCP_PORT; - } else { - port = QQ_UDP_PORT; - } - } - qd->user_port = port; - g_return_if_fail(qd->user_server == NULL); user_server = purple_account_get_string(account, "server", NULL); - if (user_server != NULL && strlen(user_server) > 0) { - qd->user_server = g_strdup(user_server); + purple_debug_info("QQ", "Select server '%s'\n", user_server); + if ( (user_server != NULL && strlen(user_server) > 0) && strcasecmp(user_server, "auto") != 0) { + qd->servers = g_list_append(qd->servers, g_strdup(user_server)); + return; } - if (qd->user_server != NULL) { - qd->servers = g_list_append(qd->servers, qd->user_server); - return; - } if (qd->use_tcp) { - qd->servers = g_list_append(qd->servers, "tcpconn.tencent.com"); - qd->servers = g_list_append(qd->servers, "tcpconn2.tencent.com"); - qd->servers = g_list_append(qd->servers, "tcpconn3.tencent.com"); - qd->servers = g_list_append(qd->servers, "tcpconn4.tencent.com"); - qd->servers = g_list_append(qd->servers, "tcpconn5.tencent.com"); - qd->servers = g_list_append(qd->servers, "tcpconn6.tencent.com"); + qd->servers = server_list_build('T'); return; } - - qd->servers = g_list_append(qd->servers, "sz.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz2.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz3.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz4.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz5.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz6.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz7.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz8.tencent.com"); - qd->servers = g_list_append(qd->servers, "sz9.tencent.com"); + + qd->servers = server_list_build('U'); } -static void server_list_remove_all(qq_data *qd) { +static void server_list_remove_all(qq_data *qd) +{ g_return_if_fail(qd != NULL); - if (qd->real_hostname) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n"); - g_free(qd->real_hostname); - qd->real_hostname = NULL; - } - - if (qd->user_server != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "free user_server\n"); - g_free(qd->user_server); - qd->user_server = NULL; - } - - purple_debug(PURPLE_DEBUG_INFO, "QQ", "free server list\n"); + purple_debug_info("QQ", "free server list\n"); g_list_free(qd->servers); + qd->curr_server = NULL; } static void qq_login(PurpleAccount *account) @@ -151,6 +137,7 @@ gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_AUTO_RESP; qd = g_new0(qq_data, 1); + memset(qd, 0, sizeof(qq_data)); qd->gc = gc; gc->proto_data = qd; @@ -165,10 +152,36 @@ } server_list_create(account); - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Server list has %d\n", g_list_length(qd->servers)); + purple_debug_info("QQ", "Server list has %d\n", g_list_length(qd->servers)); + + qd->is_show_notice = purple_account_get_bool(account, "show_notice", TRUE); + qd->is_show_news = purple_account_get_bool(account, "show_news", TRUE); + + qd->resend_times = purple_prefs_get_int("/plugins/prpl/qq/resend_times"); + if (qd->resend_times <= 1) qd->itv_config.resend = 4; + + qd->itv_config.resend = purple_prefs_get_int("/plugins/prpl/qq/resend_interval"); + if (qd->itv_config.resend <= 0) qd->itv_config.resend = 3; + purple_debug_info("QQ", "Resend interval %d, retries %d\n", + qd->itv_config.resend, qd->resend_times); - qq_connect(account); + qd->itv_config.keep_alive = purple_account_get_int(account, "keep_alive_interval", 60); + if (qd->itv_config.keep_alive < 30) qd->itv_config.keep_alive = 30; + qd->itv_config.keep_alive /= qd->itv_config.resend; + qd->itv_count.keep_alive = qd->itv_config.keep_alive; + + qd->itv_config.update = purple_account_get_int(account, "update_interval", 300); + if (qd->itv_config.update > 0) { + if (qd->itv_config.update < qd->itv_config.keep_alive) { + qd->itv_config.update = qd->itv_config.keep_alive; + } + qd->itv_config.update /= qd->itv_config.resend; + qd->itv_count.update = qd->itv_config.update; + } else { + qd->itv_config.update = 0; + } + + qd->connect_watcher = purple_timeout_add_seconds(0, qq_connect_later, gc); } /* clean up the given QQ connection and free all resources */ @@ -179,12 +192,20 @@ g_return_if_fail(gc != NULL && gc->proto_data); qd = gc->proto_data; + if (qd->check_watcher > 0) { + purple_timeout_remove(qd->check_watcher); + qd->check_watcher = 0; + } + + if (qd->connect_watcher > 0) { + purple_timeout_remove(qd->connect_watcher); + qd->connect_watcher = 0; + } + qq_disconnect(gc); - server_list_remove_all(qd); - + g_free(qd); - gc->proto_data = NULL; } @@ -212,10 +233,10 @@ g_string_append(status, _("Offline")); break; case QQ_BUDDY_ONLINE_NORMAL: - return NULL; + g_string_append(status, _("Online")); break; /* TODO What does this status mean? Labelling it as offline... */ - case QQ_BUDDY_ONLINE_OFFLINE: + case QQ_BUDDY_CHANGE_TO_OFFLINE: g_string_append(status, _("Offline")); break; case QQ_BUDDY_ONLINE_AWAY: @@ -303,8 +324,8 @@ g_string_append( str, _(" Video") ); } - if (q_bud->ext_flag & QQ_EXT_FLAG_SPACE) { - g_string_append( str, _(" Space") ); + if (q_bud->ext_flag & QQ_EXT_FLAG_ZONE) { + g_string_append( str, _(" Zone") ); } purple_notify_user_info_add_pair(user_info, _("Flag"), str->str); @@ -329,7 +350,7 @@ { /* each char** are refering to a filename in pixmaps/purple/status/default/ */ qq_buddy *q_bud; - + if (!b || !(q_bud = b->proto_data)) { return NULL; } @@ -374,11 +395,11 @@ } /* initiate QQ away with proper change_status packet */ -static void _qq_set_away(PurpleAccount *account, PurpleStatus *status) +static void _qq_change_status(PurpleAccount *account, PurpleStatus *status) { PurpleConnection *gc = purple_account_get_connection(account); - qq_send_packet_change_status(gc); + qq_request_change_status(gc, 0); } /* IMPORTANT: PurpleConvImFlags -> PurpleMessageFlags */ @@ -444,12 +465,12 @@ uid = purple_name_to_uid(who); if (uid <= 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not valid QQid: %s\n", who); + purple_debug_error("QQ", "Not valid QQid: %s\n", who); purple_notify_error(gc, NULL, _("Invalid name"), NULL); return; } - qq_send_packet_get_level(gc, uid); + qq_request_get_level(gc, uid); qq_send_packet_get_info(gc, uid, TRUE); } @@ -502,7 +523,7 @@ */ /* show a brief summary of what we get from login packet */ -static void _qq_menu_show_login_info(PurplePluginAction *action) +static void _qq_menu_account_info(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *) action->context; qq_data *qd; @@ -516,10 +537,17 @@ g_string_append(info, "<hr>\n"); - g_string_append_printf(info, _("<b>Server</b>: %s: %d<br>\n"), qd->server_name, qd->real_port); + g_string_append_printf(info, _("<b>Server</b>: %s<br>\n"), qd->curr_server); g_string_append_printf(info, _("<b>Connection Mode</b>: %s<br>\n"), qd->use_tcp ? "TCP" : "UDP"); - g_string_append_printf(info, _("<b>Real hostname</b>: %s: %d<br>\n"), qd->real_hostname, qd->real_port); - g_string_append_printf(info, _("<b>My Public IP</b>: %s<br>\n"), inet_ntoa(qd->my_ip)); + g_string_append_printf(info, _("<b>My Internet Address</b>: %s<br>\n"), inet_ntoa(qd->my_ip)); + + g_string_append(info, "<hr>\n"); + g_string_append(info, "<i>Network Status</i><br>\n"); + g_string_append_printf(info, _("<b>Sent</b>: %lu<br>\n"), qd->net_stat.sent); + g_string_append_printf(info, _("<b>Resend</b>: %lu<br>\n"), qd->net_stat.resend); + g_string_append_printf(info, _("<b>Lost</b>: %lu<br>\n"), qd->net_stat.lost); + g_string_append_printf(info, _("<b>Received</b>: %lu<br>\n"), qd->net_stat.rcved); + g_string_append_printf(info, _("<b>Received Duplicate</b>: %lu<br>\n"), qd->net_stat.rcved_dup); g_string_append(info, "<hr>\n"); g_string_append(info, "<i>Information below may not be accurate</i><br>\n"); @@ -612,7 +640,7 @@ act = purple_plugin_action_new(_("Change Password"), _qq_menu_change_password); m = g_list_append(m, act); - act = purple_plugin_action_new(_("Show Login Information"), _qq_menu_show_login_info); + act = purple_plugin_action_new(_("Account Information"), _qq_menu_account_info); m = g_list_append(m, act); /* @@ -633,7 +661,7 @@ PurpleMenuAction *act; m = NULL; - act = purple_menu_action_new(_("Leave this QQ Qun"), PURPLE_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL); + act = purple_menu_action_new(_("Leave the QQ Qun"), PURPLE_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL); m = g_list_append(m, act); /* TODO: enable this @@ -708,7 +736,7 @@ NULL, /* set_info */ NULL, /* send_typing */ _qq_get_info, /* get_info */ - _qq_set_away, /* set_away */ + _qq_change_status, /* change status */ NULL, /* set_idle */ NULL, /* change_passwd */ qq_add_buddy, /* add_buddy */ @@ -800,17 +828,43 @@ static void init_plugin(PurplePlugin *plugin) { PurpleAccountOption *option; + PurpleKeyValuePair *kvp; + GList *list = NULL; + GList *kvlist = NULL; + GList *entry; - option = purple_account_option_string_new(_("Server"), "server", NULL); + list = server_list_build('A'); + + purple_prefs_add_string_list("/plugins/prpl/qq/serverlist", list); + list = purple_prefs_get_string_list("/plugins/prpl/qq/serverlist"); + + kvlist = NULL; + kvp = g_new0(PurpleKeyValuePair, 1); + kvp->key = g_strdup(_("Auto")); + kvp->value = g_strdup("auto"); + kvlist = g_list_append(kvlist, kvp); + + entry = list; + while(entry) { + if (entry->data != NULL && strlen(entry->data) > 0) { + kvp = g_new0(PurpleKeyValuePair, 1); + kvp->key = g_strdup(entry->data); + kvp->value = g_strdup(entry->data); + kvlist = g_list_append(kvlist, kvp); + } + entry = entry->next; + } + + option = purple_account_option_list_new(_("Server"), "server", kvlist); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new(_("Port"), "port", 0); + option = purple_account_option_bool_new(_("Connect by TCP"), "use_tcp", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_bool_new(_("Connect using TCP"), "use_tcp", TRUE); + option = purple_account_option_bool_new(_("Show server notice"), "show_notice", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new(_("resend interval(s)"), "resend_interval", 10); + option = purple_account_option_bool_new(_("Show server news"), "show_news", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_int_new(_("Keep alive interval(s)"), "keep_alive_interval", 60); @@ -822,7 +876,9 @@ purple_prefs_add_none("/plugins/prpl/qq"); purple_prefs_add_bool("/plugins/prpl/qq/show_status_by_icon", TRUE); purple_prefs_add_bool("/plugins/prpl/qq/show_fake_video", FALSE); - purple_prefs_add_bool("/plugins/prpl/qq/prompt_group_msg_on_recv", TRUE); + purple_prefs_add_bool("/plugins/prpl/qq/show_room_when_newin", TRUE); + purple_prefs_add_int("/plugins/prpl/qq/resend_interval", 3); + purple_prefs_add_int("/plugins/prpl/qq/resend_times", 4); } PURPLE_INIT_PLUGIN(qq, init_plugin, info);
--- a/libpurple/protocols/qq/qq.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq.h Fri Sep 12 14:26:41 2008 +0000 @@ -36,14 +36,28 @@ #define QQ_KEY_LENGTH 16 +#ifdef _WIN32 +const char *qq_win32_buddy_icon_dir(void); +#define QQ_BUDDY_ICON_DIR qq_win32_buddy_icon_dir() +#endif + typedef struct _qq_data qq_data; typedef struct _qq_buddy qq_buddy; typedef struct _qq_interval qq_interval; +typedef struct _qq_net_stat qq_net_stat; struct _qq_interval { gint resend; gint keep_alive; - gint update; + gint update; +}; + +struct _qq_net_stat { + glong sent; + glong resend; + glong lost; + glong rcved; + glong rcved_dup; }; struct _qq_buddy { @@ -63,44 +77,51 @@ guint16 timeRemainder; time_t signon; time_t idle; - time_t last_refresh; + time_t last_update; gint8 role; /* role in group, used only in group->members list */ }; +typedef struct _qq_connection qq_connection; +struct _qq_connection { + int fd; /* socket file handler */ + int input_handler; + + /* tcp related */ + int can_write_handler; /* use in tcp_send_out */ + PurpleCircBuffer *tcp_txbuf; + guint8 *tcp_rxqueue; + int tcp_rxlen; +}; + struct _qq_data { PurpleConnection *gc; - /* common network resource */ - GList *servers; - gchar *user_server; - gint user_port; + GSList *openconns; gboolean use_tcp; /* network in tcp or udp */ - - gchar *server_name; - gboolean is_redirect; - gchar *real_hostname; /* from real connction */ - guint16 real_port; - guint reconnect_timeout; - gint reconnect_times; + PurpleProxyConnectData *conn_data; +#ifndef purple_proxy_connect_udp + PurpleDnsQueryData *udp_query_data; /* udp related */ + gint udp_can_write_handler; /* socket can_write handle, use in udp connecting and tcp send out */ +#endif + gint fd; /* socket file handler */ + qq_net_stat net_stat; - PurpleProxyConnectData *connect_data; - gint fd; /* socket file handler */ - gint tx_handler; /* socket can_write handle, use in udp connecting and tcp send out */ + GList *servers; + gchar *curr_server; /* point to servers->data, do not free*/ + + struct in_addr redirect_ip; + guint16 redirect_port; + guint check_watcher; + guint connect_watcher; + gint connect_retry; qq_interval itv_config; qq_interval itv_count; - guint network_timeout; - - GList *transactions; /* check ack packet and resend */ + guint network_watcher; + gint resend_times; - /* tcp related */ - PurpleCircBuffer *tcp_txbuf; - guint8 *tcp_rxqueue; - int tcp_rxlen; - - /* udp related */ - PurpleDnsQueryData *udp_query_data; + GList *transactions; /* check ack packet and resend */ guint32 uid; /* QQ number */ guint8 *token; /* get from server*/ @@ -112,7 +133,7 @@ guint16 send_seq; /* send sequence number */ guint8 login_mode; /* online of invisible */ - gboolean logged_in; /* used by qq-add_buddy */ + gboolean is_login; /* used by qq-add_buddy */ PurpleXfer *xfer; /* file transfer handler */ @@ -143,6 +164,9 @@ /* TODO pass qq_send_packet_get_info() a callback and use signals to get rid of these */ gboolean modifying_info; gboolean modifying_face; + + gboolean is_show_notice; + gboolean is_show_news; }; #endif
--- a/libpurple/protocols/qq/qq_base.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.c Fri Sep 12 14:26:41 2008 +0000 @@ -48,7 +48,7 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x14, 0x11, 0x20, 0x03, 0x9d, 0xb2, 0xe6, 0xb3, 0x11, 0xb7, 0x13, - 0x95, 0x67, 0xda, 0x2c, 0x01 + 0x95, 0x67, 0xda, 0x2c, 0x01 }; */ /* for QQ 2003iii 0304, fixed value */ @@ -139,7 +139,7 @@ { guint8 src[QQ_KEY_LENGTH + QQ_KEY_LENGTH]; gint bytes = 0; - + bytes += qq_put32(src + bytes, uid); bytes += qq_putdata(src + bytes, session_key, QQ_KEY_LENGTH); @@ -161,7 +161,7 @@ bytes += qq_get8(&lrop.result, data + bytes); /* 001-016: session key */ bytes += qq_getdata(lrop.session_key, sizeof(lrop.session_key), data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Got session_key\n"); + purple_debug_info("QQ", "Got session_key\n"); /* 017-020: login uid */ bytes += qq_get32(&lrop.uid, data + bytes); /* 021-024: server detected user public IP */ @@ -200,16 +200,16 @@ bytes += qq_getdata((guint8 *) &lrop.unknown6, 8, data + bytes); if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Fail parsing login info, expect %d bytes, read %d bytes\n", QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes); } /* but we still go on as login OK */ memcpy(qd->session_key, lrop.session_key, sizeof(qd->session_key)); get_session_md5(qd->session_md5, qd->uid, qd->session_key); - + qd->my_ip.s_addr = lrop.client_ip.s_addr; - + qd->my_port = lrop.client_port; qd->login_time = lrop.login_time; qd->last_login_time = lrop.last_login_time; @@ -237,39 +237,19 @@ bytes += qq_get16(&lrrp.new_server_port, data + bytes); if (bytes != QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Fail parsing login redirect packet, expect %d bytes, read %d bytes\n", QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN, bytes); return QQ_LOGIN_REPLY_ERR_MISC; } - + /* redirect to new server, do not disconnect or connect here * those connect should be called at packet_process */ - if (qd->real_hostname) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n"); - g_free(qd->real_hostname); - qd->real_hostname = NULL; - } - qd->real_hostname = g_strdup( inet_ntoa(lrrp.new_server_ip) ); - qd->real_port = lrrp.new_server_port; - + qd->redirect_ip.s_addr = lrrp.new_server_ip.s_addr; + qd->redirect_port = lrrp.new_server_port; return QQ_LOGIN_REPLY_REDIRECT; } -/* process login reply which says wrong password */ -static gint8 process_login_wrong_pwd(PurpleConnection *gc, guint8 *data, gint len) -{ - gchar *server_reply, *server_reply_utf8; - server_reply = g_new0(gchar, len); - g_memmove(server_reply, data + 1, len - 1); - server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Wrong password, server msg in UTF8: %s\n", server_reply_utf8); - g_free(server_reply); - g_free(server_reply_utf8); - - return QQ_LOGIN_REPLY_ERR_PWD; -} - /* request before login */ void qq_send_packet_token(PurpleConnection *gc) { @@ -281,9 +261,9 @@ qd = (qq_data *) gc->proto_data; bytes += qq_put8(buf + bytes, 0); - + qd->send_seq++; - qq_send_data(qd, QQ_CMD_TOKEN, qd->send_seq, TRUE, buf, bytes); + qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN, qd->send_seq, buf, bytes, TRUE); } /* send login packet to QQ server */ @@ -312,14 +292,14 @@ memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH); encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ - + bytes = 0; /* now generate the encrypted data * 000-015 use password_twice_md5 as key to encrypt empty string */ encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->password_twice_md5); g_return_if_fail(encrypted_len == 16); bytes += encrypted_len; - + /* 016-016 */ bytes += qq_put8(raw_data + bytes, 0x00); /* 017-020, used to be IP, now zero */ @@ -349,14 +329,15 @@ bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); qd->send_seq++; - qq_send_data(qd, QQ_CMD_LOGIN, qd->send_seq, TRUE, buf, bytes); + qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); } -guint8 qq_process_token_reply(PurpleConnection *gc, gchar *error_msg, guint8 *buf, gint buf_len) +guint8 qq_process_token_reply(PurpleConnection *gc, guint8 *buf, gint buf_len) { qq_data *qd; guint8 ret; int token_len; + gchar *error_msg; g_return_val_if_fail(buf != NULL && buf_len != 0, -1); @@ -364,30 +345,37 @@ qd = (qq_data *) gc->proto_data; ret = buf[0]; - + if (ret != QQ_TOKEN_REPLY_OK) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown request login token reply code : %d\n", buf[0]); + purple_debug_error("QQ", "Failed to request token: %d\n", buf[0]); qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", buf, buf_len, ">>> [default] decrypt and dump"); error_msg = try_dump_as_gbk(buf, buf_len); + if (error_msg == NULL) { + error_msg = g_strdup_printf( _("Invalid token reply code, 0x%02X"), ret); + } + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); return ret; } - + token_len = buf_len-2; if (token_len <= 0) { error_msg = g_strdup_printf( _("Invalid token len, %d"), token_len); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); return -1; } - + if (buf[1] != token_len) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Invalid token len. Packet specifies length of %d, actual length is %d\n", buf[1], buf_len-2); } qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", buf+2, token_len, "<<< got a token -> [default] decrypt and dump"); - + qd->token = g_new0(guint8, token_len); qd->token_len = token_len; g_memmove(qd->token, buf + 2, qd->token_len); @@ -402,48 +390,85 @@ qd = (qq_data *) gc->proto_data; for (i = 0; i < 4; i++) - qq_send_cmd_detail(qd, QQ_CMD_LOGOUT, 0xffff, FALSE, qd->password_twice_md5, QQ_KEY_LENGTH); + qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->password_twice_md5, QQ_KEY_LENGTH); - qd->logged_in = FALSE; /* update login status AFTER sending logout packets */ + qd->is_login = FALSE; /* update login status AFTER sending logout packets */ } /* process the login reply packet */ -guint8 qq_process_login_reply(guint8 *data, gint data_len, PurpleConnection *gc) +guint8 qq_process_login_reply( PurpleConnection *gc, guint8 *data, gint data_len) { qq_data *qd; - gchar* error_msg; + guint8 ret = data[0]; + gchar *server_reply, *server_reply_utf8; + gchar *error_msg; g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR_MISC); qd = (qq_data *) gc->proto_data; - switch (data[0]) { + switch (ret) { case QQ_LOGIN_REPLY_OK: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is OK\n"); + purple_debug_info("QQ", "Login OK\n"); return process_login_ok(gc, data, data_len); case QQ_LOGIN_REPLY_REDIRECT: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is redirect\n"); + purple_debug_info("QQ", "Redirect new server\n"); return process_login_redirect(gc, data, data_len); + + case QQ_LOGIN_REPLY_REDIRECT_EX: + purple_debug_error("QQ", "Extend redirect new server, not supported yet\n"); + error_msg = g_strdup( _("Unable login for not support Redirect_EX now") ); + return QQ_LOGIN_REPLY_REDIRECT_EX; + case QQ_LOGIN_REPLY_ERR_PWD: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is error password\n"); - return process_login_wrong_pwd(gc, data, data_len); + server_reply = g_strndup((gchar *)data + 1, data_len - 1); + server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); + + purple_debug_error("QQ", "Error password: %s\n", server_reply_utf8); + error_msg = g_strdup_printf( _("Error password: %s"), server_reply_utf8); + + g_free(server_reply); + g_free(server_reply_utf8); + + if (!purple_account_get_remember_password(gc->account)) { + purple_account_set_password(gc->account, NULL); + } + + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error_msg); + g_free(error_msg); + + return QQ_LOGIN_REPLY_ERR_PWD; + case QQ_LOGIN_REPLY_NEED_REACTIVE: - case QQ_LOGIN_REPLY_REDIRECT_EX: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is not actived or redirect extend\n"); + server_reply = g_strndup((gchar *)data + 1, data_len - 1); + server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); + + purple_debug_error("QQ", "Need active: %s\n", server_reply_utf8); + error_msg = g_strdup_printf( _("Need active: %s"), server_reply_utf8); + + g_free(server_reply); + g_free(server_reply_utf8); + break; + default: - break; + purple_debug_error("QQ", + "Unable login for unknow reply code 0x%02X\n", data[0]); + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", + data, data_len, + ">>> [default] decrypt and dump"); + error_msg = try_dump_as_gbk(data, data_len); + if (error_msg == NULL) { + error_msg = g_strdup_printf( + _("Unable login for unknow reply code 0x%02X"), data[0] ); + } + break; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown reply code: 0x%02X\n", data[0]); - qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", - data, data_len, - ">>> [default] decrypt and dump"); - error_msg = try_dump_as_gbk(data, data_len); - if (error_msg) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); - g_free(error_msg); - } - return QQ_LOGIN_REPLY_ERR_MISC; + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); + return ret; } /* send keep-alive packet to QQ server (it is a heart-beat) */ @@ -460,11 +485,11 @@ * the amount of online QQ users, my ip and port */ bytes += qq_put32(raw_data + bytes, qd->uid); - qq_send_cmd(qd, QQ_CMD_KEEP_ALIVE, raw_data, 4); + qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, 4); } /* parse the return of keep-alive packet, it includes some system information */ -gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc) +gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gchar **segments; @@ -478,7 +503,7 @@ /* the last one is 60, don't know what it is */ if (NULL == (segments = split_data(data, data_len, "\x1f", 6))) return TRUE; - + /* segments[0] and segment[1] are all 0x30 ("0") */ qd->total_online = strtol(segments[2], NULL, 10); if(0 == qd->total_online) { @@ -488,9 +513,9 @@ qd->my_ip.s_addr = inet_addr(segments[3]); qd->my_port = strtol(segments[4], NULL, 10); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "keep alive, %s:%d\n", + purple_debug_info("QQ", "keep alive, %s:%d\n", inet_ntoa(qd->my_ip), qd->my_port); - + g_strfreev(segments); return TRUE; }
--- a/libpurple/protocols/qq/qq_base.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.h Fri Sep 12 14:26:41 2008 +0000 @@ -44,10 +44,10 @@ #define QQ_UPDATE_ONLINE_INTERVAL 300 /* in sec */ void qq_send_packet_token(PurpleConnection *gc); -guint8 qq_process_token_reply(PurpleConnection *gc, gchar *error_msg, guint8 *buf, gint buf_len); +guint8 qq_process_token_reply(PurpleConnection *gc, guint8 *buf, gint buf_len); void qq_send_packet_login(PurpleConnection *gc); -guint8 qq_process_login_reply(guint8 *data, gint data_len, PurpleConnection *gc); +guint8 qq_process_login_reply( PurpleConnection *gc, guint8 *data, gint data_len); void qq_send_packet_logout(PurpleConnection *gc);
--- a/libpurple/protocols/qq/qq_network.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.c Fri Sep 12 14:26:41 2008 +0000 @@ -26,11 +26,6 @@ #include "debug.h" #include "internal.h" -#ifdef _WIN32 -#define random rand -#define srandom srand -#endif - #include "buddy_info.h" #include "group_info.h" #include "group_free.h" @@ -44,63 +39,100 @@ #include "utils.h" #include "qq_process.h" -/* set QQ_RECONNECT_MAX to 1, when test reconnecting */ -#define QQ_RECONNECT_MAX 4 -#define QQ_RECONNECT_INTERVAL 5000 -#define QQ_KEEP_ALIVE_INTERVAL 60000 -#define QQ_TRANS_INTERVAL 10000 +#define QQ_DEFAULT_PORT 8000 + +/* set QQ_CONNECT_MAX to 1, when test reconnecting */ +#define QQ_CONNECT_MAX 3 +#define QQ_CONNECT_INTERVAL 2 +#define QQ_CONNECT_CHECK 5 +#define QQ_KEEP_ALIVE_INTERVAL 60 +#define QQ_TRANS_INTERVAL 10 + +gboolean connect_to_server(PurpleConnection *gc, gchar *server, gint port); + +static qq_connection *connection_find(qq_data *qd, int fd) { + qq_connection *ret = NULL; + GSList *entry = qd->openconns; + while(entry) { + ret = entry->data; + if(ret->fd == fd) return ret; + entry = entry->next; + } + return NULL; +} +static qq_connection *connection_create(qq_data *qd, int fd) { + qq_connection *ret = g_new0(qq_connection, 1); + ret->fd = fd; + qd->openconns = g_slist_append(qd->openconns, ret); + return ret; +} + +static void connection_remove(qq_data *qd, int fd) { + qq_connection *conn = connection_find(qd, fd); + qd->openconns = g_slist_remove(qd->openconns, conn); + + g_return_if_fail( conn != NULL ); + + purple_debug_info("QQ", "Close socket %d\n", conn->fd); + if(conn->input_handler > 0) purple_input_remove(conn->input_handler); + if(conn->can_write_handler > 0) purple_input_remove(conn->can_write_handler); + + if (conn->fd >= 0) close(conn->fd); + if(conn->tcp_txbuf != NULL) purple_circ_buffer_destroy(conn->tcp_txbuf); + if (conn->tcp_rxqueue != NULL) g_free(conn->tcp_rxqueue); + + g_free(conn); +} + +static void connection_free_all(qq_data *qd) { + qq_connection *ret = NULL; + GSList *entry = qd->openconns; + while(entry) { + ret = entry->data; + connection_remove(qd, ret->fd); + entry = qd->openconns; + } +} static gboolean set_new_server(qq_data *qd) { gint count; gint index; GList *it = NULL; - + g_return_val_if_fail(qd != NULL, FALSE); if (qd->servers == NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list is NULL\n"); + purple_debug_info("QQ", "Server list is NULL\n"); return FALSE; } - if (qd->real_hostname) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n"); - g_free(qd->real_hostname); - qd->real_hostname = NULL; - } + /* remove server used before */ + if (qd->curr_server != NULL) { + purple_debug_info("QQ", + "Remove current [%s] from server list\n", qd->curr_server); + qd->servers = g_list_remove(qd->servers, qd->curr_server); + qd->curr_server = NULL; + } - /* remove server used before */ - if (qd->server_name != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Remove previous server [%s]\n", qd->server_name); - qd->servers = g_list_remove(qd->servers, qd->server_name); - qd->server_name = NULL; - } - count = g_list_length(qd->servers); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list has %d\n", count); + purple_debug_info("QQ", "Server list has %d\n", count); if (count <= 0) { /* no server left, disconnect when result is false */ qd->servers = NULL; return FALSE; } - + /* get new server */ - index = random() % count; + index = rand() % count; it = g_list_nth(qd->servers, index); - qd->server_name = it->data; /* do not free server_name */ - if (qd->server_name == NULL || strlen(qd->server_name) <= 0 ) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server name at %d is empty\n", index); + qd->curr_server = it->data; /* do not free server_name */ + if (qd->curr_server == NULL || strlen(qd->curr_server) <= 0 ) { + purple_debug_info("QQ", "Server name at %d is empty\n", index); return FALSE; } - qd->real_hostname = g_strdup(qd->server_name); - qd->real_port = qd->user_port; - - qd->reconnect_times = QQ_RECONNECT_MAX; - - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "set new server to %s:%d\n", qd->real_hostname, qd->real_port); + purple_debug_info("QQ", "set new server to %s\n", qd->curr_server); return TRUE; } @@ -115,152 +147,199 @@ return bytes; } -static gboolean reconnect_later_cb(gpointer data) +static gboolean connect_check(gpointer data) { - PurpleConnection *gc; + PurpleConnection *gc = (PurpleConnection *) data; qq_data *qd; - gc = (PurpleConnection *) data; + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); + qd = (qq_data *) gc->proto_data; + + if (qd->connect_watcher > 0) { + purple_timeout_remove(qd->connect_watcher); + qd->connect_watcher = 0; + } + + if (qd->fd >= 0 && qd->token != NULL && qd->token_len >= 0) { + purple_debug_info("QQ", "Connect ok\n"); + return FALSE; + } + + qd->connect_watcher = purple_timeout_add_seconds(0, qq_connect_later, gc); + return FALSE; +} + +/* Warning: qq_connect_later destory all connection + * Any function should be care of use qq_data after call this function + * Please conside tcp_pending and udp_pending */ +gboolean qq_connect_later(gpointer data) +{ + PurpleConnection *gc = (PurpleConnection *) data; + qq_data *qd; + char *server; + int port; + gchar **segments; + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); qd = (qq_data *) gc->proto_data; - qd->reconnect_timeout = 0; + if (qd->check_watcher > 0) { + purple_timeout_remove(qd->check_watcher); + qd->check_watcher = 0; + } + qq_disconnect(gc); + + if (qd->redirect_ip.s_addr != 0) { + /* redirect to new server */ + server = g_strdup_printf("%s:%d", inet_ntoa(qd->redirect_ip), qd->redirect_port); + qd->servers = g_list_append(qd->servers, server); + qd->curr_server = server; + + qd->redirect_ip.s_addr = 0; + qd->redirect_port = 0; + qd->connect_retry = QQ_CONNECT_MAX; + } - qq_connect(gc->account); + if (qd->curr_server == NULL || strlen (qd->curr_server) == 0 || qd->connect_retry <= 0) { + if ( set_new_server(qd) != TRUE) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Failed to connect all servers")); + return FALSE; + } + qd->connect_retry = QQ_CONNECT_MAX; + } + + segments = g_strsplit_set(qd->curr_server, ":", 0); + server = g_strdup(segments[0]); + port = atoi(segments[1]); + if (port <= 0) { + purple_debug_info("QQ", "Port not define in %s\n", qd->curr_server); + port = QQ_DEFAULT_PORT; + } + g_strfreev(segments); + + qd->connect_retry--; + if ( !connect_to_server(gc, server, port) ) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Unable to connect.")); + } + + qd->check_watcher = purple_timeout_add_seconds(QQ_CONNECT_CHECK, connect_check, gc); return FALSE; /* timeout callback stops */ } -static void reconnect_later(PurpleConnection *gc) -{ - qq_data *qd; - - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; - - qd->reconnect_times--; - if (qd->reconnect_times < 0) { - if ( set_new_server(qd) != TRUE) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Failed to connect server")); - return; - } - } - - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Reconnect to server %s:%d next retries %d in %d ms\n", - qd->real_hostname, qd->real_port, - qd->reconnect_times, QQ_RECONNECT_INTERVAL); - - qd->reconnect_timeout = purple_timeout_add(QQ_RECONNECT_INTERVAL, - reconnect_later_cb, gc); -} - /* process the incoming packet from qq_pending */ -static void packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len) +static gboolean packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len) { qq_data *qd; gint bytes, bytes_not_read; - gboolean prev_login_status; - guint8 header_tag; guint16 source_tag; guint16 cmd; guint16 seq; /* May be ack_seq or send_seq, depends on cmd */ - guint8 room_cmd; guint32 room_id; + gint update_class; + guint32 ship32; qq_transaction *trans; - g_return_if_fail(buf != NULL && buf_len > 0); + g_return_val_if_fail(buf != NULL && buf_len > 0, TRUE); qd = (qq_data *) gc->proto_data; - prev_login_status = qd->logged_in; + qd->net_stat.rcved++; + if (qd->net_stat.rcved <= 0) memset(&(qd->net_stat), 0, sizeof(qd->net_stat)); /* Len, header and tail tag have been checked before */ bytes = 0; bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes); #if 1 - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "==> [%05d] 0x%04X %s, from (0x%04X %s) len %d\n", - seq, cmd, qq_get_cmd_desc(cmd), source_tag, qq_get_ver_desc(source_tag), buf_len); -#endif + purple_debug_info("QQ", "==> [%05d] %s 0x%04X, source tag 0x%04X len %d\n", + seq, qq_get_cmd_desc(cmd), cmd, source_tag, buf_len); +#endif + /* this is the length of all the encrypted data (also remove tail tag) */ bytes_not_read = buf_len - bytes - 1; /* ack packet, we need to update send tranactions */ /* we do not check duplication for server ack */ - trans = qq_trans_find_rcved(qd, cmd, seq); + trans = qq_trans_find_rcved(gc, cmd, seq); if (trans == NULL) { /* new server command */ - qq_trans_add_server_cmd(qd, cmd, seq, buf + bytes, bytes_not_read); - if ( qd->logged_in ) { - qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); + if ( !qd->is_login ) { + qq_trans_add_remain(gc, cmd, seq, buf + bytes, bytes_not_read); + } else { + qq_trans_add_server_cmd(gc, cmd, seq, buf + bytes, bytes_not_read); + qq_proc_server_cmd(gc, cmd, seq, buf + bytes, bytes_not_read); } - return; + return TRUE; } if (qq_trans_is_dup(trans)) { - purple_debug(PURPLE_DEBUG_WARNING, - "QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd)); - return; - } - - if (qq_trans_is_server(trans)) { - if ( qd->logged_in ) { - qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); - } - return; + qd->net_stat.rcved_dup++; + purple_debug_info("QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd)); + return TRUE; } - /* this is the length of all the encrypted data (also remove tail tag */ - if (cmd == QQ_CMD_ROOM) { - room_cmd = qq_trans_get_room_cmd(trans); - room_id = qq_trans_get_room_id(trans); + update_class = qq_trans_get_class(trans); + ship32 = qq_trans_get_ship(trans); + + switch (cmd) { + case QQ_CMD_TOKEN: + if (qq_process_token_reply(gc, buf + bytes, bytes_not_read) == QQ_TOKEN_REPLY_OK) { + qq_send_packet_login(gc); + } + break; + case QQ_CMD_LOGIN: + qq_proc_login_cmd(gc, buf + bytes, bytes_not_read); + /* check is redirect or not, and do it now */ + if (qd->redirect_ip.s_addr != 0) { + if (qd->check_watcher > 0) { + purple_timeout_remove(qd->check_watcher); + qd->check_watcher = 0; + } + if (qd->connect_watcher > 0) purple_timeout_remove(qd->connect_watcher); + qd->connect_watcher = purple_timeout_add_seconds(QQ_CONNECT_INTERVAL, qq_connect_later, gc); + return FALSE; /* do nothing after this function and return now */ + } + break; + case QQ_CMD_ROOM: + room_cmd = qq_trans_get_room_cmd(trans); + room_id = qq_trans_get_room_id(trans); #if 1 - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "%s (0x%02X ) for room %d, len %d\n", - qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); -#endif - qq_proc_room_cmd_reply(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read); - } else { - qq_proc_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read); - } - - /* check is redirect or not, and do it now */ - if (qd->is_redirect) { - /* free resource except real_hostname and port */ - qq_disconnect(gc); - qd->reconnect_times = QQ_RECONNECT_MAX; - reconnect_later(gc); - return; + purple_debug_info("QQ", "%s (0x%02X) for room %d, len %d\n", + qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); +#endif + qq_proc_room_cmd(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read, update_class, ship32); + break; + default: + qq_proc_client_cmd(gc, cmd, seq, buf + bytes, bytes_not_read, update_class, ship32); + break; } - if (prev_login_status != qd->logged_in && qd->logged_in == TRUE) { - /* logged_in, but we have packets before login */ - qq_trans_process_before_login(qd); - } + return TRUE; } static void tcp_pending(gpointer data, gint source, PurpleInputCondition cond) { - PurpleConnection *gc; + PurpleConnection *gc = (PurpleConnection *) data; qq_data *qd; + qq_connection *conn; guint8 buf[1024]; /* set to 16 when test tcp_rxqueue */ gint buf_len; gint bytes; - + guint8 *pkt; guint16 pkt_len; - + gchar *error_msg; guint8 *jump; gint jump_len; - gc = (PurpleConnection *) data; g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; if(cond != PURPLE_INPUT_READ) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -268,8 +347,9 @@ return; } - qd = (qq_data *) gc->proto_data; - + conn = connection_find(qd, source); + g_return_if_fail(conn != NULL); + /* test code, not using tcp_rxqueue memset(pkt,0, sizeof(pkt)); buf_len = read(qd->fd, pkt, sizeof(pkt)); @@ -278,8 +358,8 @@ } return; */ - - buf_len = read(qd->fd, buf, sizeof(buf)); + + buf_len = read(source, buf, sizeof(buf)); if (buf_len < 0) { if (errno == EAGAIN) /* No worries */ @@ -299,93 +379,93 @@ * QQ need a keep alive packet in every 60 seconds gc->last_received = time(NULL); */ - /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", - "Read %d bytes from socket, rxlen is %d\n", buf_len, qd->tcp_rxlen); - */ - qd->tcp_rxqueue = g_realloc(qd->tcp_rxqueue, buf_len + qd->tcp_rxlen); - memcpy(qd->tcp_rxqueue + qd->tcp_rxlen, buf, buf_len); - qd->tcp_rxlen += buf_len; - + /* purple_debug_info("TCP_PENDING", "Read %d bytes, rxlen is %d\n", buf_len, conn->tcp_rxlen); */ + conn->tcp_rxqueue = g_realloc(conn->tcp_rxqueue, buf_len + conn->tcp_rxlen); + memcpy(conn->tcp_rxqueue + conn->tcp_rxlen, buf, buf_len); + conn->tcp_rxlen += buf_len; + pkt = g_newa(guint8, MAX_PACKET_SIZE); - while (1) { - if (qd->tcp_rxlen < QQ_TCP_HEADER_LENGTH) { + while (PURPLE_CONNECTION_IS_VALID(gc)) { + if (qd->openconns == NULL) { break; } - - bytes = 0; - bytes += qq_get16(&pkt_len, qd->tcp_rxqueue + bytes); - if (qd->tcp_rxlen < pkt_len) { + if (conn->tcp_rxqueue == NULL) { + conn->tcp_rxlen = 0; + break; + } + if (conn->tcp_rxlen < QQ_TCP_HEADER_LENGTH) { break; } - /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", - "Packet len is %d bytes, rxlen is %d\n", pkt_len, qd->tcp_rxlen); - */ - if ( pkt_len < QQ_TCP_HEADER_LENGTH - || *(qd->tcp_rxqueue + bytes) != QQ_PACKET_TAG - || *(qd->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) { - /* HEY! This isn't even a QQ. What are you trying to pull? */ + bytes = 0; + bytes += qq_get16(&pkt_len, conn->tcp_rxqueue + bytes); + if (conn->tcp_rxlen < pkt_len) { + break; + } - purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", - "Packet error, failed to check header and tail tag\n"); + /* purple_debug_info("TCP_PENDING", "Packet len=%d, rxlen=%d\n", pkt_len, conn->tcp_rxlen); */ + if ( pkt_len < QQ_TCP_HEADER_LENGTH + || *(conn->tcp_rxqueue + bytes) != QQ_PACKET_TAG + || *(conn->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) { + /* HEY! This isn't even a QQ. What are you trying to pull? */ + purple_debug_warning("TCP_PENDING", "Packet error, no header or tail tag\n"); - jump = memchr(qd->tcp_rxqueue + 1, QQ_PACKET_TAIL, qd->tcp_rxlen - 1); + jump = memchr(conn->tcp_rxqueue + 1, QQ_PACKET_TAIL, conn->tcp_rxlen - 1); if ( !jump ) { - purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", - "Failed to find next QQ_PACKET_TAIL, clear receive buffer\n"); - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = NULL; - qd->tcp_rxlen = 0; + purple_debug_warning("TCP_PENDING", "Failed to find next tail, clear receive buffer\n"); + g_free(conn->tcp_rxqueue); + conn->tcp_rxqueue = NULL; + conn->tcp_rxlen = 0; return; } /* jump and over QQ_PACKET_TAIL */ - jump_len = (jump - qd->tcp_rxqueue) + 1; - purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", - "Find next QQ_PACKET_TAIL at %d, jump %d bytes\n", jump_len, jump_len + 1); - g_memmove(qd->tcp_rxqueue, jump, qd->tcp_rxlen - jump_len); - qd->tcp_rxlen -= jump_len; + jump_len = (jump - conn->tcp_rxqueue) + 1; + purple_debug_warning("TCP_PENDING", "Find next tail at %d, jump %d\n", jump_len, jump_len + 1); + g_memmove(conn->tcp_rxqueue, jump, conn->tcp_rxlen - jump_len); + conn->tcp_rxlen -= jump_len; continue; } memset(pkt, 0, MAX_PACKET_SIZE); - g_memmove(pkt, qd->tcp_rxqueue + bytes, pkt_len - bytes); - + g_memmove(pkt, conn->tcp_rxqueue + bytes, pkt_len - bytes); + /* jump to next packet */ - qd->tcp_rxlen -= pkt_len; - if (qd->tcp_rxlen) { - /* - purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", "shrink tcp_rxqueue to %d\n", qd->tcp_rxlen); - */ - jump = g_memdup(qd->tcp_rxqueue + pkt_len, qd->tcp_rxlen); - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = jump; + conn->tcp_rxlen -= pkt_len; + if (conn->tcp_rxlen) { + /* purple_debug_info("TCP_PENDING", "shrink tcp_rxqueue to %d\n", conn->tcp_rxlen); */ + jump = g_memdup(conn->tcp_rxqueue + pkt_len, conn->tcp_rxlen); + g_free(conn->tcp_rxqueue); + conn->tcp_rxqueue = jump; } else { - /* purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", "free tcp_rxqueue\n"); */ - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = NULL; + /* purple_debug_info("TCP_PENDING", "free tcp_rxqueue\n"); */ + g_free(conn->tcp_rxqueue); + conn->tcp_rxqueue = NULL; } if (pkt == NULL) { continue; } - /* do not call packet_process before jump - * packet_process may call disconnect and destory tcp_rxqueue */ - packet_process(gc, pkt, pkt_len - bytes); + /* packet_process may call disconnect and destory data like conn + * do not call packet_process before jump, + * break if packet_process return FALSE */ + if (packet_process(gc, pkt, pkt_len - bytes) == FALSE) { + purple_debug_info("TCP_PENDING", "Connection has been destory\n"); + break; + } } } static void udp_pending(gpointer data, gint source, PurpleInputCondition cond) { - PurpleConnection *gc; + PurpleConnection *gc = (PurpleConnection *) data; qq_data *qd; guint8 *buf; gint buf_len; gc = (PurpleConnection *) data; g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; if(cond != PURPLE_INPUT_READ) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -393,13 +473,10 @@ return; } - qd = (qq_data *) gc->proto_data; - g_return_if_fail(qd->fd >= 0); - buf = g_newa(guint8, MAX_PACKET_SIZE); /* here we have UDP proxy suppport */ - buf_len = read(qd->fd, buf, MAX_PACKET_SIZE); + buf_len = read(source, buf, MAX_PACKET_SIZE); if (buf_len <= 0) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to read from socket")); @@ -419,73 +496,95 @@ return; } } - + + /* packet_process may call disconnect and destory data like conn + * do not call packet_process before jump, + * break if packet_process return FALSE */ packet_process(gc, buf, buf_len); } -static gint udp_send_out(qq_data *qd, guint8 *data, gint data_len) +static gint udp_send_out(PurpleConnection *gc, guint8 *data, gint data_len) { + qq_data *qd; gint ret; - g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; - /* - purple_debug(PURPLE_DEBUG_INFO, "UDP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); - */ - +#if 0 + purple_debug_info("UDP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); +#endif + errno = 0; ret = send(qd->fd, data, data_len, 0); if (ret < 0 && errno == EAGAIN) { return ret; } - + if (ret < 0) { /* TODO: what to do here - do we really have to disconnect? */ - purple_debug(PURPLE_DEBUG_ERROR, "UDP_SEND_OUT", "Send failed: %d, %s\n", errno, g_strerror(errno)); - purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); + purple_debug_error("UDP_SEND_OUT", "Send failed: %d, %s\n", errno, g_strerror(errno)); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); } return ret; } static void tcp_can_write(gpointer data, gint source, PurpleInputCondition cond) { - qq_data *qd = data; + PurpleConnection *gc = (PurpleConnection *) data; + qq_data *qd; + qq_connection *conn; int ret, writelen; - writelen = purple_circ_buffer_get_max_read(qd->tcp_txbuf); + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + conn = connection_find(qd, source); + g_return_if_fail(conn != NULL); + + writelen = purple_circ_buffer_get_max_read(conn->tcp_txbuf); if (writelen == 0) { - purple_input_remove(qd->tx_handler); - qd->tx_handler = 0; + purple_input_remove(conn->can_write_handler); + conn->can_write_handler = 0; return; } - ret = write(qd->fd, qd->tcp_txbuf->outptr, writelen); - purple_debug(PURPLE_DEBUG_ERROR, "TCP_CAN_WRITE", - "total %d bytes is sent %d\n", writelen, ret); + ret = write(source, conn->tcp_txbuf->outptr, writelen); + purple_debug_info("TCP_CAN_WRITE", "total %d bytes is sent %d\n", writelen, ret); if (ret < 0 && errno == EAGAIN) return; else if (ret < 0) { /* TODO: what to do here - do we really have to disconnect? */ - purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Write Error")); return; } - purple_circ_buffer_mark_read(qd->tcp_txbuf, ret); + purple_circ_buffer_mark_read(conn->tcp_txbuf, ret); } -static gint tcp_send_out(qq_data *qd, guint8 *data, gint data_len) +static gint tcp_send_out(PurpleConnection *gc, guint8 *data, gint data_len) { + qq_data *qd; + qq_connection *conn; gint ret; - g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; - /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); - */ + conn = connection_find(qd, qd->fd); + g_return_val_if_fail(conn, -1); - if (qd->tx_handler == 0) { +#if 0 + purple_debug_info("TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); +#endif + + if (conn->can_write_handler == 0) { ret = write(qd->fd, data, data_len); } else { ret = -1; @@ -493,28 +592,28 @@ } /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", + purple_debug_info("TCP_SEND_OUT", "Socket %d, total %d bytes is sent %d\n", qd->fd, data_len, ret); */ if (ret < 0 && errno == EAGAIN) { /* socket is busy, send later */ - purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Socket is busy and send later\n"); + purple_debug_info("TCP_SEND_OUT", "Socket is busy and send later\n"); ret = 0; } else if (ret <= 0) { /* TODO: what to do here - do we really have to disconnect? */ - purple_debug(PURPLE_DEBUG_ERROR, "TCP_SEND_OUT", + purple_debug_error("TCP_SEND_OUT", "Send to socket %d failed: %d, %s\n", qd->fd, errno, g_strerror(errno)); - purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); return ret; } if (ret < data_len) { - purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", + purple_debug_info("TCP_SEND_OUT", "Add %d bytes to buffer\n", data_len - ret); - if (qd->tx_handler == 0) { - qd->tx_handler = purple_input_add(qd->fd, PURPLE_INPUT_WRITE, tcp_can_write, qd); + if (conn->can_write_handler == 0) { + conn->can_write_handler = purple_input_add(qd->fd, PURPLE_INPUT_WRITE, tcp_can_write, gc); } - purple_circ_buffer_append(qd->tcp_txbuf, data + ret, data_len - ret); + purple_circ_buffer_append(conn->tcp_txbuf, data + ret, data_len - ret); } return ret; } @@ -528,17 +627,17 @@ g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, TRUE); qd = (qq_data *) gc->proto_data; - is_lost_conn = qq_trans_scan(qd); + is_lost_conn = qq_trans_scan(gc); if (is_lost_conn) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost")); return TRUE; } - if ( !qd->logged_in ) { + if ( !qd->is_login ) { return TRUE; } - + qd->itv_count.keep_alive--; if (qd->itv_count.keep_alive <= 0) { qd->itv_count.keep_alive = qd->itv_config.keep_alive; @@ -553,55 +652,29 @@ qd->itv_count.update--; if (qd->itv_count.update <= 0) { qd->itv_count.update = qd->itv_config.update; - qq_send_packet_get_buddies_online(gc, 0); - - qq_send_cmd_group_all_get_online_members(gc); + qq_update_online(gc, 0); return TRUE; } return TRUE; /* if return FALSE, timeout callback stops */ } -/* the callback function after socket is built - * we setup the qq protocol related configuration here */ -static void qq_connect_cb(gpointer data, gint source, const gchar *error_message) +static void do_request_token(PurpleConnection *gc) { qq_data *qd; - PurpleConnection *gc; gchar *conn_msg; const gchar *passwd; - PurpleAccount *account ; - - gc = (PurpleConnection *) data; - - if (!PURPLE_CONNECTION_IS_VALID(gc)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection\n"); - close(source); - return; - } - - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - - qd = (qq_data *) gc->proto_data; - account = purple_connection_get_account(gc); - - /* Connect is now complete; clear the PurpleProxyConnectData */ - qd->connect_data = NULL; - - if (source < 0) { /* socket returns -1 */ - purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection, source is < 0\n"); - qq_disconnect(gc); - reconnect_later(gc); - return; - } /* _qq_show_socket("Got login socket", source); */ + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + /* QQ use random seq, to minimize duplicated packets */ - srandom(time(NULL)); - qd->send_seq = random() & 0x0000ffff; - qd->fd = source; - qd->logged_in = FALSE; + srand(time(NULL)); + qd->send_seq = rand() & 0xffff; + + qd->is_login = FALSE; qd->channel = 1; qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10); @@ -614,41 +687,63 @@ qq_get_md5(qd->password_twice_md5, sizeof(qd->password_twice_md5), qd->password_twice_md5, sizeof(qd->password_twice_md5)); - g_return_if_fail(qd->network_timeout == 0); - qd->itv_config.resend = purple_account_get_int(account, "resend_interval", 10); - if (qd->itv_config.resend <= 0) qd->itv_config.resend = 10; - - qd->itv_config.keep_alive = purple_account_get_int(account, "keep_alive_interval", 60); - if (qd->itv_config.keep_alive < 30) qd->itv_config.keep_alive = 30; - qd->itv_config.keep_alive /= qd->itv_config.resend; - qd->itv_count.keep_alive = qd->itv_config.keep_alive; - - qd->itv_config.update = purple_account_get_int(account, "update_interval", 300); - if (qd->itv_config.update > 0) { - if (qd->itv_config.update < qd->itv_config.keep_alive) { - qd->itv_config.update = qd->itv_config.keep_alive; - } - qd->itv_config.update /= qd->itv_config.resend; - qd->itv_count.update = qd->itv_config.update; - } else { - qd->itv_config.update = 0; - } - - qd->network_timeout = purple_timeout_add(qd->itv_config.resend *1000, network_timeout, gc); - - if (qd->use_tcp) - gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, tcp_pending, gc); - else - gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, udp_pending, gc); + g_return_if_fail(qd->network_watcher == 0); + qd->network_watcher = purple_timeout_add_seconds(qd->itv_config.resend, network_timeout, gc); /* Update the login progress status display */ - conn_msg = g_strdup_printf("Login as %d", qd->uid); - purple_connection_update_progress(gc, conn_msg, QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS); + conn_msg = g_strdup_printf(_("Request token")); + purple_connection_update_progress(gc, conn_msg, 2, QQ_CONNECT_STEPS); g_free(conn_msg); qq_send_packet_token(gc); } +/* the callback function after socket is built + * we setup the qq protocol related configuration here */ +static void connect_cb(gpointer data, gint source, const gchar *error_message) +{ + PurpleConnection *gc; + qq_data *qd; + PurpleAccount *account ; + qq_connection *conn; + + gc = (PurpleConnection *) data; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + + qd = (qq_data *) gc->proto_data; + account = purple_connection_get_account(gc); + + /* conn_data will be destoryed */ + qd->conn_data = NULL; + + if (!PURPLE_CONNECTION_IS_VALID(gc)) { + purple_debug_info("QQ_CONN", "Invalid connection\n"); + close(source); + return; + } + + if (source < 0) { /* socket returns -1 */ + purple_debug_info("QQ_CONN", + "Could not establish a connection with the server:\n%s\n", + error_message); + if (qd->connect_watcher > 0) purple_timeout_remove(qd->connect_watcher); + qd->connect_watcher = purple_timeout_add_seconds(QQ_CONNECT_INTERVAL, qq_connect_later, gc); + return; + } + + /* _qq_show_socket("Got login socket", source); */ + qd->fd = source; + conn = connection_create(qd, source); + if (qd->use_tcp) { + conn->input_handler = purple_input_add(source, PURPLE_INPUT_READ, tcp_pending, gc); + } else { + conn->input_handler = purple_input_add(source, PURPLE_INPUT_READ, udp_pending, gc); + } + + do_request_token( gc ); +} + +#ifndef purple_proxy_connect_udp static void udp_can_write(gpointer data, gint source, PurpleInputCondition cond) { PurpleConnection *gc; @@ -679,22 +774,22 @@ ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); if (ret == 0 && error == EINPROGRESS) return; /* we'll be called again later */ - - purple_input_remove(qd->tx_handler); - qd->tx_handler = 0; + + purple_input_remove(qd->udp_can_write_handler); + qd->udp_can_write_handler = 0; if (ret < 0 || error != 0) { - if(ret != 0) + if(ret != 0) error = errno; close(source); purple_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", g_strerror(error)); - qq_connect_cb(gc, -1, _("Unable to connect")); + connect_cb(gc, -1, _("Unable to connect")); return; } - qq_connect_cb(gc, source, NULL); + connect_cb(gc, source, NULL); } static void udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) { @@ -725,7 +820,7 @@ hosts = g_slist_remove(hosts, hosts->data); memcpy(&server_addr, hosts->data, addr_size); g_free(hosts->data); - + hosts = g_slist_remove(hosts, hosts->data); while(hosts) { hosts = g_slist_remove(hosts, hosts->data); @@ -735,7 +830,7 @@ fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd < 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Unable to create socket: %s\n", g_strerror(errno)); return; } @@ -743,131 +838,103 @@ /* we use non-blocking mode to speed up connection */ flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | O_NONBLOCK); -#ifndef _WIN32 - fcntl(fd, F_SETFD, FD_CLOEXEC); -#endif /* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/ * * If a UDP socket is unconnected, which is the normal state after a * bind() call, then send() or write() are not allowed, since no * destination is available; only sendto() can be used to send data. - * + * * Calling connect() on the socket simply records the specified address * and port number as being the desired communications partner. That * means that send() or write() are now allowed; they use the destination * address and port given on the connect call as the destination of packets. */ if (connect(fd, &server_addr, addr_size) >= 0) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connected.\n"); + purple_debug_info("QQ", "Connected.\n"); flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); - qq_connect_cb(gc, fd, NULL); + connect_cb(gc, fd, NULL); return; } - + /* [EINPROGRESS] - * The socket is marked as non-blocking and the connection cannot be - * completed immediately. It is possible to select for completion by + * The socket is marked as non-blocking and the connection cannot be + * completed immediately. It is possible to select for completion by * selecting the socket for writing. * [EINTR] - * A signal interrupted the call. + * A signal interrupted the call. * The connection is established asynchronously. */ if ((errno == EINPROGRESS) || (errno == EINTR)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n"); - qd->tx_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc); + purple_debug_warning( "QQ", "Connect in asynchronous mode.\n"); + qd->udp_can_write_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc); return; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection failed: %s\n", g_strerror(errno)); + purple_debug_error("QQ", "Connection failed: %s\n", g_strerror(errno)); close(fd); } +#endif -/* establish a generic QQ connection - * TCP/UDP, and direct/redirected */ -void qq_connect(PurpleAccount *account) +gboolean connect_to_server(PurpleConnection *gc, gchar *server, gint port) { - PurpleConnection *gc; + PurpleAccount *account ; qq_data *qd; gchar *conn_msg; - gc = purple_account_get_connection(account); - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); + account = purple_connection_get_account(gc); qd = (qq_data *) gc->proto_data; - - /* test set_new_server - while (set_new_server(qd)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST", - "New server %s:%d Real server %s:%d\n", - qd->server_name, qd->user_port, qd->real_hostname, qd->real_port); - } - purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST", "qd->servers %lu\n", - qd->servers); - exit(1); - */ - if (qd->server_name == NULL) { - /* must be first call this function */ - if ( set_new_server(qd) != TRUE) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Failed to connect server")); - return; - } + if (server == NULL || strlen(server) == 0 || port == 0) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Invalid server or port")); + return FALSE; } - if (qd->real_hostname == NULL || qd->real_port == 0) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("hostname is NULL or port is 0")); - return; - } - - conn_msg = g_strdup_printf( _("Connecting server %s, retries %d"), - qd->real_hostname, qd->reconnect_times); + conn_msg = g_strdup_printf( _("Connecting server %s, retries %d"), server, port); purple_connection_update_progress(gc, conn_msg, 1, QQ_CONNECT_STEPS); g_free(conn_msg); - if (qd->is_redirect) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Redirect to %s:%d\n", - qd->real_hostname, qd->real_port); - } - qd->is_redirect = FALSE; + purple_debug_info("QQ", "Connect to %s:%d\n", server, port); + + if (qd->conn_data != NULL) { + purple_proxy_connect_cancel(qd->conn_data); + qd->conn_data = NULL; + } - qd->fd = -1; - qd->tx_handler = 0; - - /* QQ connection via UDP/TCP. +#ifdef purple_proxy_connect_udp + if (qd->use_tcp) { + qd->conn_data = purple_proxy_connect(gc, account, server, port, connect_cb, gc); + } else { + qd->conn_data = purple_proxy_connect_udp(gc, account, server, port, connect_cb, gc); + } + if ( qd->conn_data == NULL ) { + purple_debug_error("QQ", _("Couldn't create socket")); + return FALSE; + } +#else + /* QQ connection via UDP/TCP. * Now use Purple proxy function to provide TCP proxy support, * and qq_udp_proxy.c to add UDP proxy support (thanks henry) */ if(qd->use_tcp) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "TCP Connect to %s:%d\n", - qd->real_hostname, qd->real_port); - - /* TODO: is there a good default grow size? */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create tcp_txbuf\n"); - qd->tcp_txbuf = purple_circ_buffer_new(0); - - qd->connect_data = purple_proxy_connect(NULL, account, - qd->real_hostname, qd->real_port, qq_connect_cb, gc); - if (qd->connect_data == NULL) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to connect.")); + qd->conn_data = purple_proxy_connect(gc, account, server, port, connect_cb, gc); + if ( qd->conn_data == NULL ) { + purple_debug_error("QQ", "Unable to connect."); + return FALSE; } - return; + return TRUE; } - - purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Connect to %s:%d\n", - qd->real_hostname, qd->real_port); - g_return_if_fail(qd->udp_query_data == NULL); - qd->udp_query_data = purple_dnsquery_a(qd->real_hostname, qd->real_port, - udp_host_resolved, gc); - if (qd->udp_query_data == NULL) { - purple_connection_error_reason(qd->gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Could not resolve hostname")); + purple_debug_info("QQ", "UDP Connect to %s:%d\n", server, port); + qd->udp_query_data = purple_dnsquery_a(server, port, udp_host_resolved, gc); + if ( qd->udp_query_data == NULL ) { + purple_debug_error("QQ", "Could not resolve hostname"); + return FALSE; } +#endif + return TRUE; } /* clean up qq_data structure and all its components @@ -879,65 +946,43 @@ g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Disconnecting ...\n"); + purple_debug_info("QQ", "Disconnecting ...\n"); - if (qd->network_timeout > 0) { - purple_timeout_remove(qd->network_timeout); - qd->network_timeout = 0; + if (qd->network_watcher > 0) { + purple_debug_info("QQ", "Remove network watcher\n"); + purple_timeout_remove(qd->network_watcher); + qd->network_watcher = 0; } /* finish all I/O */ - if (qd->fd >= 0 && qd->logged_in) { + if (qd->fd >= 0 && qd->is_login) { qq_send_packet_logout(gc); } - if (gc->inpa > 0) { - purple_input_remove(gc->inpa); - gc->inpa = 0; - } - - if (qd->fd >= 0) { - close(qd->fd); - qd->fd = -1; - } - - if (qd->reconnect_timeout > 0) { - purple_timeout_remove(qd->reconnect_timeout); - qd->reconnect_timeout = 0; - } - - if (qd->connect_data != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Cancel connect_data\n"); - purple_proxy_connect_cancel(qd->connect_data); + /* not connected */ + if (qd->conn_data != NULL) { + purple_debug_info("QQ", "Connect cancel\n"); + purple_proxy_connect_cancel(qd->conn_data); + qd->conn_data = NULL; } - - if(qd->tcp_txbuf != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_txbuf\n"); - purple_circ_buffer_destroy(qd->tcp_txbuf); - qd->tcp_txbuf = NULL; +#ifndef purple_proxy_connect_udp + if (qd->udp_can_write_handler) { + purple_input_remove(qd->udp_can_write_handler); + qd->udp_can_write_handler = 0; } - - if (qd->tx_handler) { - purple_input_remove(qd->tx_handler); - qd->tx_handler = 0; - } - if (qd->tcp_rxqueue != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_rxqueue\n"); - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = NULL; - qd->tcp_rxlen = 0; - } - if (qd->udp_query_data != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy udp_query_data\n"); + purple_debug_info("QQ", "destroy udp_query_data\n"); purple_dnsquery_destroy(qd->udp_query_data); qd->udp_query_data = NULL; } +#endif + connection_free_all(qd); + qd->fd = -1; - qq_trans_remove_all(qd); - + qq_trans_remove_all(gc); + if (qd->token) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "free token\n"); + purple_debug_info("QQ", "free token\n"); g_free(qd->token); qd->token = NULL; qd->token_len = 0; @@ -955,13 +1000,13 @@ qq_buddies_list_free(gc->account, qd); } -static gint encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq, +static gint packet_encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { gint bytes = 0; g_return_val_if_fail(qd != NULL && buf != NULL && maxlen > 0, -1); g_return_val_if_fail(data != NULL && data_len > 0, -1); - + /* QQ TCP packet has two bytes in the begining defines packet length * so leave room here to store packet size */ if (qd->use_tcp) { @@ -971,7 +1016,7 @@ bytes += qq_put8(buf + bytes, QQ_PACKET_TAG); bytes += qq_put16(buf + bytes, QQ_CLIENT); bytes += qq_put16(buf + bytes, cmd); - + bytes += qq_put16(buf + bytes, seq); bytes += qq_put32(buf + bytes, qd->uid); @@ -987,109 +1032,168 @@ } /* data has been encrypted before */ -gint qq_send_data(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, - guint8 *data, gint data_len) +static gint packet_send_out(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { + qq_data *qd; guint8 *buf; gint buf_len; gint bytes_sent; - g_return_val_if_fail(qd != NULL, -1); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *)gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); - buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len); + buf_len = packet_encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len); if (buf_len <= 0) { return -1; } + qd->net_stat.sent++; if (qd->use_tcp) { - bytes_sent = tcp_send_out(qd, buf, buf_len); + bytes_sent = tcp_send_out(gc, buf, buf_len); } else { - bytes_sent = udp_send_out(qd, buf, buf_len); + bytes_sent = udp_send_out(gc, buf, buf_len); } - if (need_ack) { - qq_trans_add_client_cmd(qd, cmd, seq, data, data_len); - } - -#if 1 - /* qq_show_packet("QQ_SEND_DATA", buf, buf_len); */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "<== [%05d], 0x%04X %s, total %d bytes is sent %d\n", - seq, cmd, qq_get_cmd_desc(cmd), buf_len, bytes_sent); -#endif return bytes_sent; } -/* Encrypt data with session_key, then call qq_send_data */ -gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, - guint8 *data, gint data_len) +gint qq_send_cmd_encrypted(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *encrypted_data, gint encrypted_len, gboolean is_save2trans) { + gint sent_len; + +#if 1 + /* qq_show_packet("qq_send_cmd_encrypted", data, data_len); */ + purple_debug_info("QQ", "<== [%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, encrypted_len); +#endif + + sent_len = packet_send_out(gc, cmd, seq, encrypted_data, encrypted_len); + if (is_save2trans) { + qq_trans_add_client_cmd(gc, cmd, seq, encrypted_data, encrypted_len, 0, 0); + } + return sent_len; +} + +/* Encrypt data with session_key, and send packet out */ +static gint send_cmd_detail(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len, gboolean is_save2trans, gint update_class, guint32 ship32) +{ + qq_data *qd; guint8 *encrypted_data; gint encrypted_len; + gint bytes_sent; - g_return_val_if_fail(qd != NULL, -1); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *)gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); /* at most 16 bytes more */ encrypted_data = g_newa(guint8, data_len + 16); -#if 0 - purple_debug(PURPLE_DEBUG_INFO, "QQ_ENCRYPT", - "Before %d: [%05d] 0x%04X %s\n", - data_len, seq, cmd, qq_get_cmd_desc(cmd)); -#endif encrypted_len = qq_encrypt(encrypted_data, data, data_len, qd->session_key); if (encrypted_len < 16) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ_ENCRYPT", - "Error len %d: [%05d] 0x%04X %s\n", + purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] 0x%04X %s\n", encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); return -1; } -#if 0 - purple_debug(PURPLE_DEBUG_INFO, "QQ_ENCRYPT", - "After %d: [%05d] 0x%04X %s\n", - encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); -#endif - return qq_send_data(qd, cmd, seq, need_ack, encrypted_data, encrypted_len); + bytes_sent = packet_send_out(gc, cmd, seq, encrypted_data, encrypted_len); + + if (is_save2trans) { + qq_trans_add_client_cmd(gc, cmd, seq, encrypted_data, encrypted_len, + update_class, ship32); + } + return bytes_sent; } -/* set seq and need_ack, then call qq_send_cmd_detail */ -gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint data_len) +gint qq_send_cmd_mess(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len, + gint update_class, guint32 ship32) { - g_return_val_if_fail(qd != NULL, -1); + qq_data *qd; + guint16 seq; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); - qd->send_seq++; - return qq_send_cmd_detail(qd, cmd, qd->send_seq, TRUE, data, data_len); + seq = ++qd->send_seq; +#if 1 + purple_debug_info("QQ", "<== [%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, data_len); +#endif + return send_cmd_detail(gc, cmd, seq, data, data_len, TRUE, update_class, ship32); } -gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, - guint8 *data, gint data_len) +/* set seq and is_save2trans, then call send_cmd_detail */ +gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len) { - return qq_send_room_cmd(gc, room_cmd, 0, data, data_len); + qq_data *qd; + guint16 seq; + gboolean is_save2trans; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + if (cmd != QQ_CMD_LOGOUT) { + seq = ++qd->send_seq; + is_save2trans = TRUE; + } else { + seq = 0xFFFF; + is_save2trans = FALSE; + } +#if 1 + purple_debug_info("QQ", "<== [%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, data_len); +#endif + return send_cmd_detail(gc, cmd, seq, data, data_len, is_save2trans, 0, 0); } -gint qq_send_room_cmd_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +/* set seq and is_save2trans, then call send_cmd_detail */ +gint qq_send_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { - g_return_val_if_fail(room_cmd > 0 && room_id > 0, -1); - return qq_send_room_cmd(gc, room_cmd, room_id, NULL, 0); + qq_data *qd; + guint8 *encrypted_data; + gint encrypted_len; + gint bytes_sent; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *)gc->proto_data; + g_return_val_if_fail(data != NULL && data_len > 0, -1); + +#if 1 + purple_debug_info("QQ", "<== [SRV-%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, data_len); +#endif + /* at most 16 bytes more */ + encrypted_data = g_newa(guint8, data_len + 16); + encrypted_len = qq_encrypt(encrypted_data, data, data_len, qd->session_key); + if (encrypted_len < 16) { + purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] 0x%04X %s\n", + encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); + return -1; + } + + bytes_sent = packet_send_out(gc, cmd, seq, encrypted_data, encrypted_len); + qq_trans_add_server_reply(gc, cmd, seq, encrypted_data, encrypted_len); + + return bytes_sent; } -gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len) +static gint send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32) { qq_data *qd; - guint8 *buf; gint buf_len; guint8 *encrypted_data; gint encrypted_len; gint bytes_sent; guint16 seq; - + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); qd = (qq_data *) gc->proto_data; @@ -1106,6 +1210,7 @@ if (data != NULL && data_len > 0) { buf_len += qq_putdata(buf + buf_len, data, data_len); } + qd->send_seq++; seq = qd->send_seq; @@ -1114,32 +1219,44 @@ encrypted_data = g_newa(guint8, buf_len + 16); encrypted_len = qq_encrypt(encrypted_data, buf, buf_len, qd->session_key); if (encrypted_len < 16) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ_ENCRYPT", - "Error len %d: [%05d] QQ_CMD_ROOM.(0x%02X %s)\n", - encrypted_len, seq, room_cmd, qq_get_room_cmd_desc(room_cmd)); - return -1; - } - - /* Encap header to buf */ - buf_len = encap(qd, buf, MAX_PACKET_SIZE, QQ_CMD_ROOM, seq, encrypted_data, encrypted_len); - if (buf_len <= 0) { + purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] %s (0x%02X)\n", + encrypted_len, seq, qq_get_room_cmd_desc(room_cmd), room_cmd); return -1; } - if (qd->use_tcp) { - bytes_sent = tcp_send_out(qd, buf, buf_len); - } else { - bytes_sent = udp_send_out(qd, buf, buf_len); - } + bytes_sent = packet_send_out(gc, QQ_CMD_ROOM, seq, encrypted_data, encrypted_len); +#if 1 + /* qq_show_packet("send_room_cmd", buf, buf_len); */ + purple_debug_info("QQ", + "<== [%05d], %s (0x%02X) to room %d, datalen %d\n", + seq, qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); +#endif - qq_trans_add_room_cmd(qd, seq, room_cmd, room_id, buf, buf_len); - -#if 1 - /* qq_show_packet("QQ_SEND_DATA", buf, buf_len); */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "<== [%05d], QQ_CMD_ROOM.(0x%02X %s) to room %d, total %d bytes is sent %d\n", - seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, - buf_len, bytes_sent); -#endif + qq_trans_add_room_cmd(gc, seq, room_cmd, room_id, encrypted_data, encrypted_len, + update_class, ship32); return bytes_sent; } + +gint qq_send_room_cmd_mess(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32) +{ + return send_room_cmd(gc, room_cmd, room_id, data, data_len, update_class, ship32); +} + +gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len) +{ + return send_room_cmd(gc, room_cmd, room_id, data, data_len, 0, 0); +} + +gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, + guint8 *data, gint data_len) +{ + return send_room_cmd(gc, room_cmd, 0, data, data_len, 0, 0); +} + +gint qq_send_room_cmd_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + g_return_val_if_fail(room_cmd > 0 && room_id > 0, -1); + return send_room_cmd(gc, room_cmd, room_id, NULL, 0, 0, 0); +}
--- a/libpurple/protocols/qq/qq_network.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.h Fri Sep 12 14:26:41 2008 +0000 @@ -32,19 +32,23 @@ #define QQ_CONNECT_STEPS 3 /* steps in connection */ -void qq_connect(PurpleAccount *account); +gboolean qq_connect_later(gpointer data); void qq_disconnect(PurpleConnection *gc); -void qq_connect_later(PurpleConnection *gc); -gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint datalen); -gint qq_send_data(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, - guint8 *data, gint data_len); -gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, - guint8 *data, gint data_len); +gint qq_send_cmd_encrypted(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *encrypted_data, gint encrypted_len, gboolean is_save2trans); +gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, guint8 *data, gint datalen); +gint qq_send_cmd_mess(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len, + gint update_class, guint32 ship32); + +gint qq_send_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len); gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len); +gint qq_send_room_cmd_mess(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32); gint qq_send_room_cmd_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); -gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, +gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, guint8 *data, gint data_len); #endif
--- a/libpurple/protocols/qq/qq_process.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Fri Sep 12 14:26:41 2008 +0000 @@ -26,11 +26,6 @@ #include "debug.h" #include "internal.h" -#ifdef _WIN32 -#define random rand -#define srandom srand -#endif - #include "buddy_info.h" #include "buddy_list.h" #include "buddy_opt.h" @@ -65,7 +60,7 @@ }; /* default process, decrypt and dump */ -static void process_cmd_unknow(PurpleConnection *gc,gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq) +static void process_cmd_unknow(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq) { qq_data *qd; gchar *msg_utf8 = NULL; @@ -82,14 +77,13 @@ seq, qq_get_cmd_desc(cmd)); msg_utf8 = try_dump_as_gbk(data, data_len); - if (msg_utf8) { - purple_notify_info(gc, NULL, msg_utf8, NULL); + if (msg_utf8 != NULL) { + purple_notify_info(gc, _("QQ Error"), title, msg_utf8); g_free(msg_utf8); } } -void qq_proc_cmd_server(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) +void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) { qq_data *qd; @@ -102,20 +96,20 @@ data = g_newa(guint8, rcved_len); data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); if (data_len < 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Can not decrypt server cmd by session key, [%05d], 0x%04X %s, len %d\n", + purple_debug_warning("QQ", + "Can not decrypt server cmd by session key, [%05d], 0x%04X %s, len %d\n", seq, cmd, qq_get_cmd_desc(cmd), rcved_len); qq_show_packet("Can not decrypted", rcved, rcved_len); return; } if (data_len <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Server cmd decrypted is empty, [%05d], 0x%04X %s, len %d\n", + purple_debug_warning("QQ", + "Server cmd decrypted is empty, [%05d], 0x%04X %s, len %d\n", seq, cmd, qq_get_cmd_desc(cmd), rcved_len); return; } - + /* now process the packet */ switch (cmd) { case QQ_CMD_RECV_IM: @@ -124,107 +118,208 @@ case QQ_CMD_RECV_MSG_SYS: qq_process_msg_sys(data, data_len, seq, gc); break; - case QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS: + case QQ_CMD_BUDDY_CHANGE_STATUS: qq_process_buddy_change_status(data, data_len, gc); break; default: - process_cmd_unknow(gc, "Unknow SERVER CMD", data, data_len, cmd, seq); + process_cmd_unknow(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq); break; } } -static void process_cmd_login(PurpleConnection *gc, guint8 *data, gint data_len) +static void process_room_cmd_notify(PurpleConnection *gc, + guint8 room_cmd, guint8 room_id, guint8 reply, guint8 *data, gint data_len) { - qq_data *qd; - guint ret_8; - - g_return_if_fail (gc != NULL && gc->proto_data != NULL); - - qd = (qq_data *) gc->proto_data; - - ret_8 = qq_process_login_reply(data, data_len, gc); - if (ret_8 == QQ_LOGIN_REPLY_OK) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login repliess OK; everything is fine\n"); - - purple_connection_set_state(gc, PURPLE_CONNECTED); - qd->logged_in = TRUE; /* must be defined after sev_finish_login */ - - /* now initiate QQ Qun, do it first as it may take longer to finish */ - qq_group_init(gc); - - /* Now goes on updating my icon/nickname, not showing info_window */ - qd->modifying_face = FALSE; - - qq_send_packet_get_info(gc, qd->uid, FALSE); - /* grab my level */ - qq_send_packet_get_level(gc, qd->uid); - - qq_send_packet_change_status(gc); - - /* refresh buddies */ - qq_send_packet_get_buddies_list(gc, 0); - - /* refresh groups */ - qq_send_packet_get_buddies_and_rooms(gc, 0); - - return; - } - - if (ret_8 == QQ_LOGIN_REPLY_REDIRECT) { - qd->is_redirect = TRUE; - /* - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Redirected to new server: %s:%d\n", qd->real_hostname, qd->real_port); - */ - return; - } - - if (ret_8 == QQ_LOGIN_REPLY_ERR_PWD) { - if (!purple_account_get_remember_password(gc->account)) { - purple_account_set_password(gc->account, NULL); - } - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect password.")); - return; - } - - if (ret_8 == QQ_LOGIN_REPLY_ERR_MISC) { - if (purple_debug_is_enabled()) - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to login. Check debug log.")); - else - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to login")); - return; - } -} - -static void process_room_cmd_notify(PurpleConnection *gc, - guint8 room_cmd, guint8 room_id, guint8 reply_cmd, guint8 reply, guint8 *data, gint data_len) -{ + gchar *prim; gchar *msg, *msg_utf8; g_return_if_fail(data != NULL && data_len > 0); msg = g_strndup((gchar *) data, data_len); /* it will append 0x00 */ msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); g_free(msg); - - msg = g_strdup_printf(_( - "Reply %s(0x%02X )\n" - "Sent %s(0x%02X )\n" - "Room id %d, reply [0x%02X]: \n" - "%s"), - qq_get_room_cmd_desc(reply_cmd), reply_cmd, - qq_get_room_cmd_desc(room_cmd), room_cmd, - room_id, reply, msg_utf8); - - purple_notify_error(gc, NULL, _("Failed room reply"), msg); - g_free(msg); + + prim = g_strdup_printf(_("Error reply of %s(0x%02X)\nRoom %d, reply 0x%02X"), + qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, reply); + + purple_notify_error(gc, _("QQ Qun Command"), prim, msg_utf8); + + g_free(prim); g_free(msg_utf8); } -void qq_proc_room_cmd_reply(PurpleConnection *gc, - guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len) +void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + qq_data *qd; + qq_group *group; + gint ret; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + group = qq_room_search_id(gc, room_id); + if (group == NULL && room_id <= 0) { + purple_debug_info("QQ", "No room, nothing update\n"); + return; + } + if (group == NULL ) { + purple_debug_warning("QQ", "Failed search room id [%d]\n", room_id); + return; + } + + switch (room_cmd) { + case 0: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ROOM, 0); + break; + case QQ_ROOM_CMD_GET_INFO: + ret = qq_request_room_get_buddies(gc, group, QQ_CMD_CLASS_UPDATE_ROOM); + if (ret <= 0) { + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ROOM, 0); + } + break; + case QQ_ROOM_CMD_GET_BUDDIES: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ROOM, 0); + break; + case QQ_ROOM_CMD_GET_ONLINES: + /* last command */ + default: + break; + } +} + +static void update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + qq_data *qd; + gboolean is_new_turn = FALSE; + qq_group *next_group; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + next_group = qq_room_get_next(gc, room_id); + if (next_group == NULL && room_id <= 0) { + purple_debug_info("QQ", "No room. Finished update\n"); + return; + } + if (next_group == NULL ) { + is_new_turn = TRUE; + next_group = qq_room_get_next(gc, 0); + g_return_if_fail(next_group != NULL); + } + + switch (room_cmd) { + case 0: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + break; + case QQ_ROOM_CMD_GET_INFO: + if (!is_new_turn) { + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + } else { + qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL); + } + break; + case QQ_ROOM_CMD_GET_BUDDIES: + /* last command */ + if (!is_new_turn) { + qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL); + } else { + purple_debug_info("QQ", "Finished update\n"); + } + break; + default: + break; + } +} + +void qq_update_all(PurpleConnection *gc, guint16 cmd) +{ + qq_data *qd; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + switch (cmd) { + case 0: + qq_request_buddy_info(gc, qd->uid, QQ_CMD_CLASS_UPDATE_ALL, QQ_BUDDY_INFO_UPDATE_ONLY); + break; + case QQ_CMD_GET_BUDDY_INFO: + qq_request_change_status(gc, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_CHANGE_STATUS: + qq_request_get_buddies_list(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_BUDDIES_LIST: + qq_request_get_buddies_and_rooms(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_BUDDIES_AND_ROOMS: + qq_request_get_buddies_level(gc, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_LEVEL: + qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_BUDDIES_ONLINE: + /* last command */ + update_all_rooms(gc, 0, 0); + break; + default: + break; + } +} + +static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + qq_data *qd; + qq_group *next_group; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + next_group = qq_room_get_next_conv(gc, room_id); + if (next_group == NULL && room_id <= 0) { + purple_debug_info("QQ", "No room in conversation, no update online buddies\n"); + return; + } + if (next_group == NULL ) { + purple_debug_info("QQ", "finished update rooms' online buddies\n"); + return; + } + + switch (room_cmd) { + case 0: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + break; + case QQ_ROOM_CMD_GET_ONLINES: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + break; + default: + break; + } +} + +void qq_update_online(PurpleConnection *gc, guint16 cmd) +{ + switch (cmd) { + case 0: + qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ONLINE); + break; + case QQ_CMD_GET_BUDDIES_ONLINE: + /* last command */ + update_all_rooms_online(gc, 0, 0); + break; + default: + break; + } +} + +void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq, + guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, + gint update_class, guint32 ship32) { qq_data *qd; guint8 *data; @@ -239,58 +334,57 @@ data = g_newa(guint8, rcved_len); data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); if (data_len < 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Can not decrypt room cmd by session key, [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Can not decrypt room cmd by session key, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); qq_show_packet("Can not decrypted", rcved, rcved_len); return; } if (room_id <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invaild room id, [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Invaild room id, [%05d], 0x%02X %s for %d, len %d\n", + seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); + /* Some room cmd has no room id, like QQ_ROOM_CMD_SEARCH */ + } + + if (data_len <= 2) { + purple_debug_warning("QQ", + "Invaild len of room cmd decrypted, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); return; } - if (data_len <= 2) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invaild len of room cmd decrypted, [%05d], 0x%02X %s for %d, len %d\n", - seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); - return; - } - group = qq_room_search_id(gc, room_id); if (group == NULL) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Missing room id in [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Missing room id in [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); } - + bytes = 0; bytes += qq_get8(&reply_cmd, data + bytes); bytes += qq_get8(&reply, data + bytes); if (reply_cmd != room_cmd) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Missing room cmd in reply 0x%02X %s, [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Missing room cmd in reply 0x%02X %s, [%05d], 0x%02X %s for %d, len %d\n", reply_cmd, qq_get_room_cmd_desc(reply_cmd), seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); } - + /* now process the packet */ if (reply != QQ_ROOM_CMD_REPLY_OK) { if (group != NULL) { qq_set_pending_id(&qd->joining_groups, group->ext_id, FALSE); } - + switch (reply) { /* this should be all errors */ case QQ_ROOM_CMD_REPLY_NOT_MEMBER: if (group != NULL) { - purple_debug(PURPLE_DEBUG_WARNING, - "QQ", - _("You are not a member of group \"%s\"\n"), group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + purple_debug_warning("QQ", + _("You are not a member of QQ Qun \"%s\"\n"), group->title_utf8); + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); } break; @@ -300,7 +394,7 @@ purple_roomlist_set_in_progress(qd->roomlist, FALSE); } default: - process_room_cmd_notify(gc, room_cmd, room_id, reply_cmd, reply, data + bytes, data_len - bytes); + process_room_cmd_notify(gc, reply_cmd, room_id, reply, data + bytes, data_len - bytes); } return; } @@ -309,10 +403,6 @@ switch (reply_cmd) { case QQ_ROOM_CMD_GET_INFO: qq_process_room_cmd_get_info(data + bytes, data_len - bytes, gc); - if (group != NULL) { - qq_send_cmd_group_get_members_info(gc, group); - qq_send_cmd_group_get_online_members(gc, group); - } break; case QQ_ROOM_CMD_CREATE: qq_group_process_create_group_reply(data + bytes, data_len - bytes, gc); @@ -346,20 +436,88 @@ if (group != NULL) qq_group_conv_refresh_online_member(gc, group); break; - case QQ_ROOM_CMD_GET_MEMBER_INFO: - qq_process_room_cmd_get_members(data + bytes, data_len - bytes, gc); - if (group != NULL) + case QQ_ROOM_CMD_GET_BUDDIES: + qq_process_room_cmd_get_buddies(data + bytes, data_len - bytes, gc); + if (group != NULL) { + group->is_got_info = TRUE; qq_group_conv_refresh_online_member(gc, group); + } break; default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Unknow room cmd 0x%02X %s\n", + purple_debug_warning("QQ", "Unknow room cmd 0x%02X %s\n", reply_cmd, qq_get_room_cmd_desc(reply_cmd)); } + + if (update_class == QQ_CMD_CLASS_NONE) + return; + + purple_debug_info("QQ", "Update class %d\n", update_class); + if (update_class == QQ_CMD_CLASS_UPDATE_ALL) { + update_all_rooms(gc, room_cmd, room_id); + return; + } + if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) { + update_all_rooms_online(gc, room_cmd, room_id); + return; + } + if (update_class == QQ_CMD_CLASS_UPDATE_ROOM) { + qq_update_room(gc, room_cmd, room_id); + } } -void qq_proc_cmd_reply(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) +void qq_proc_login_cmd(PurpleConnection *gc, guint8 *rcved, gint rcved_len) +{ + qq_data *qd; + guint8 *data; + gint data_len; + guint ret_8; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + data = g_newa(guint8, rcved_len); + /* May use password_twice_md5 in the past version like QQ2005*/ + data_len = qq_decrypt(data, rcved, rcved_len, qd->inikey); + if (data_len >= 0) { + purple_debug_warning("QQ", + "Decrypt login reply packet with inikey, %d bytes\n", data_len); + } else { + data_len = qq_decrypt(data, rcved, rcved_len, qd->password_twice_md5); + if (data_len >= 0) { + purple_debug_warning("QQ", + "Decrypt login reply packet with password_twice_md5, %d bytes\n", data_len); + } else { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Can not decrypt login reply")); + return; + } + } + + ret_8 = qq_process_login_reply(gc, data, data_len); + if (ret_8 != QQ_LOGIN_REPLY_OK) { + return; + } + + purple_debug_info("QQ", "Login repliess OK; everything is fine\n"); + + purple_connection_set_state(gc, PURPLE_CONNECTED); + qd->is_login = TRUE; /* must be defined after sev_finish_login */ + + /* now initiate QQ Qun, do it first as it may take longer to finish */ + qq_group_init(gc); + + /* Now goes on updating my icon/nickname, not showing info_window */ + qd->modifying_face = FALSE; + + /* is_login, but we have packets before login */ + qq_trans_process_remained(gc); + + qq_update_all(gc, 0); + return; +} + +void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32) { qq_data *qd; @@ -369,7 +527,7 @@ guint8 ret_8 = 0; guint16 ret_16 = 0; guint32 ret_32 = 0; - gchar *error_msg = NULL; + gboolean is_unknow = FALSE; g_return_if_fail(rcved_len > 0); @@ -377,61 +535,23 @@ qd = (qq_data *) gc->proto_data; data = g_newa(guint8, rcved_len); - if (cmd == QQ_CMD_TOKEN) { - g_memmove(data, rcved, rcved_len); - data_len = rcved_len; - } else if (cmd == QQ_CMD_LOGIN) { - /* May use password_twice_md5 in the past version like QQ2005*/ - data_len = qq_decrypt(data, rcved, rcved_len, qd->inikey); - if (data_len >= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Decrypt login reply packet with inikey, %d bytes\n", data_len); - } else { - data_len = qq_decrypt(data, rcved, rcved_len, qd->password_twice_md5); - if (data_len >= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Decrypt login reply packet with password_twice_md5, %d bytes\n", data_len); - } else { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Can not decrypt login reply")); - return; - } - } - } else { - data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); - if (data_len < 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Can not reply by session key, [%05d], 0x%04X %s, len %d\n", - seq, cmd, qq_get_cmd_desc(cmd), rcved_len); - qq_show_packet("Can not decrypted", rcved, rcved_len); - return; - } + data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); + if (data_len < 0) { + purple_debug_warning("QQ", + "Reply can not be decrypted by session key, [%05d], 0x%04X %s, len %d\n", + seq, cmd, qq_get_cmd_desc(cmd), rcved_len); + qq_show_packet("Can not decrypted", rcved, rcved_len); + return; } - + if (data_len <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Reply decrypted is empty, [%05d], 0x%04X %s, len %d\n", + purple_debug_warning("QQ", + "Reply decrypted is empty, [%05d], 0x%04X %s, len %d\n", seq, cmd, qq_get_cmd_desc(cmd), rcved_len); return; } switch (cmd) { - case QQ_CMD_TOKEN: - ret_8 = qq_process_token_reply(gc, error_msg, data, data_len); - if (ret_8 != QQ_TOKEN_REPLY_OK) { - if (error_msg == NULL) { - error_msg = g_strdup_printf( _("Invalid token reply code, 0x%02X"), ret_8); - } - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); - g_free(error_msg); - return; - } - - qq_send_packet_login(gc); - break; - case QQ_CMD_LOGIN: - process_cmd_login(gc, data, data_len); - break; case QQ_CMD_UPDATE_INFO: qq_process_modify_info_reply(data, data_len, gc); break; @@ -447,10 +567,10 @@ case QQ_CMD_BUDDY_AUTH: qq_process_add_buddy_auth_reply(data, data_len, gc); break; - case QQ_CMD_GET_USER_INFO: - qq_process_get_info_reply(data, data_len, gc); + case QQ_CMD_GET_BUDDY_INFO: + qq_process_get_buddy_info(data, data_len, gc); break; - case QQ_CMD_CHANGE_ONLINE_STATUS: + case QQ_CMD_CHANGE_STATUS: qq_process_change_status_reply(data, data_len, gc); break; case QQ_CMD_SEND_IM: @@ -462,41 +582,53 @@ case QQ_CMD_GET_BUDDIES_ONLINE: ret_8 = qq_process_get_buddies_online_reply(data, data_len, gc); if (ret_8 > 0 && ret_8 < 0xff) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more online buddies\n"); - qq_send_packet_get_buddies_online(gc, ret_8); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "All online buddies received\n"); - /* Fixme: this should not be called once*/ - qq_send_packet_get_buddies_levels(gc); - - qq_refresh_all_buddy_status(gc); + purple_debug_info("QQ", "Requesting for more online buddies\n"); + qq_request_get_buddies_online(gc, ret_8, update_class); + return; } + purple_debug_info("QQ", "All online buddies received\n"); + qq_refresh_all_buddy_status(gc); break; case QQ_CMD_GET_LEVEL: qq_process_get_level_reply(data, data_len, gc); break; case QQ_CMD_GET_BUDDIES_LIST: ret_16 = qq_process_get_buddies_list_reply(data, data_len, gc); - if (ret_16 > 0 && ret_16 < 0xffff) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more buddies\n"); - qq_send_packet_get_buddies_list(gc, ret_16); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "All buddies received. Requesting buddies' levels\n"); - qq_send_packet_get_buddies_online(gc, 0); + if (ret_16 > 0 && ret_16 < 0xffff) { + purple_debug_info("QQ", "Requesting for more buddies\n"); + qq_request_get_buddies_list(gc, ret_16, update_class); + return; } + purple_debug_info("QQ", "All buddies received. Requesting buddies' levels\n"); break; case QQ_CMD_GET_BUDDIES_AND_ROOMS: ret_32 = qq_process_get_buddies_and_rooms(data, data_len, gc); if (ret_32 > 0 && ret_32 < 0xffffffff) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more buddies and groups\n"); - qq_send_packet_get_buddies_and_rooms(gc, ret_32); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "All buddies and groups received\n"); + purple_debug_info("QQ", "Requesting for more buddies and groups\n"); + qq_request_get_buddies_and_rooms(gc, ret_32, update_class); + return; } + purple_debug_info("QQ", "All buddies and groups received\n"); break; default: - process_cmd_unknow(gc, "Unknow reply CMD", data, data_len, cmd, seq); + process_cmd_unknow(gc, _("Unknow reply CMD"), data, data_len, cmd, seq); + is_unknow = TRUE; break; } + if (is_unknow) + return; + + if (update_class == QQ_CMD_CLASS_NONE) + return; + + purple_debug_info("QQ", "Update class %d\n", update_class); + if (update_class == QQ_CMD_CLASS_UPDATE_ALL) { + qq_update_all(gc, cmd); + return; + } + if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) { + qq_update_online(gc, cmd); + return; + } }
--- a/libpurple/protocols/qq/qq_process.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.h Fri Sep 12 14:26:41 2008 +0000 @@ -30,12 +30,24 @@ #include "qq.h" -void qq_proc_cmd_reply(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); -void qq_proc_room_cmd_reply(PurpleConnection *gc, - guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len); - -void qq_proc_cmd_server(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); +enum { + QQ_CMD_CLASS_NONE = 0, + QQ_CMD_CLASS_UPDATE_ALL, + QQ_CMD_CLASS_UPDATE_ONLINE, + QQ_CMD_CLASS_UPDATE_ROOM, +}; + +void qq_proc_login_cmd(PurpleConnection *gc, guint8 *rcved, gint rcved_len); +void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32); +void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq, + guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, + gint update_class, guint32 ship32); + +void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); + +void qq_update_all(PurpleConnection *gc, guint16 cmd); +void qq_update_online(PurpleConnection *gc, guint16 cmd); +void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); #endif
--- a/libpurple/protocols/qq/qq_trans.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Fri Sep 12 14:26:41 2008 +0000 @@ -35,55 +35,47 @@ #include "qq_process.h" #include "qq_trans.h" -#define QQ_RESEND_MAX 3 /* max resend per packet */ +enum { + QQ_TRANS_IS_SERVER = 0x01, /* Is server command or client command */ + QQ_TRANS_IS_IMPORT = 0x02, /* Only notice if not get reply; or resend, disconn if reties get 0*/ + QQ_TRANS_REMAINED = 0x04, /* server command before login*/ + QQ_TRANS_IS_REPLY = 0x08, /* server command before login*/ +}; -qq_transaction *qq_trans_find_rcved(qq_data *qd, guint16 cmd, guint16 seq) -{ - GList *curr; - GList *next; - qq_transaction *trans; - - if (qd->transactions == NULL) { - return NULL; - } +struct _qq_transaction { + guint8 flag; + guint16 seq; + guint16 cmd; - next = qd->transactions; - while( (curr = next) ) { - next = curr->next; - - trans = (qq_transaction *) (curr->data); - if(trans->cmd == cmd && trans->seq == seq) { - if (trans->rcved_times == 0) { - trans->scan_times = 0; - } - trans->rcved_times++; - if (qq_trans_is_server(trans) && qq_trans_is_dup(trans)) { - /* server may not get our confirm reply before, send reply again*/ - if (trans->data != NULL && trans->data_len > 0) { - qq_send_data(qd, trans->cmd, trans->seq, FALSE, trans->data, trans->data_len); - } - } - return trans; - } - } + guint8 room_cmd; + guint32 room_id; + + guint8 *data; + gint data_len; - return NULL; -} + gint fd; + gint send_retries; + gint rcved_times; + gint scan_times; -gboolean qq_trans_is_server(qq_transaction *trans) + gint update_class; + guint32 ship32; +}; + +gboolean qq_trans_is_server(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, FALSE); - + if (trans->flag & QQ_TRANS_IS_SERVER) return TRUE; else return FALSE; } -gboolean qq_trans_is_dup(qq_transaction *trans) +gboolean qq_trans_is_dup(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, TRUE); - + if (trans->rcved_times > 1) return TRUE; else @@ -102,115 +94,203 @@ return trans->room_id; } -/* Remove a packet with seq from send trans */ -static void trans_remove(qq_data *qd, qq_transaction *trans) +gint qq_trans_get_class(qq_transaction *trans) +{ + g_return_val_if_fail(trans != NULL, QQ_CMD_CLASS_NONE); + return trans->update_class; +} + +gint qq_trans_get_ship(qq_transaction *trans) +{ + g_return_val_if_fail(trans != NULL, 0); + return trans->ship32; +} + +static qq_transaction *trans_create(PurpleConnection *gc, gint fd, + guint16 cmd, guint16 seq, guint8 *data, gint data_len, gint update_class, guint32 ship32) { - g_return_if_fail(qd != NULL && trans != NULL); - - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", + qq_data *qd; + qq_transaction *trans; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); + qd = (qq_data *) gc->proto_data; + + trans = g_new0(qq_transaction, 1); + + memset(trans, 0, sizeof(qq_transaction)); + trans->fd = fd; + trans->cmd = cmd; + trans->seq = seq; + + trans->data = NULL; + trans->data_len = 0; + if (data != NULL && data_len > 0) { + /* don't use g_strdup, may have 0x00 */ + trans->data = g_memdup(data, data_len); + trans->data_len = data_len; + } + + trans->update_class = update_class; + return trans; +} + +/* Remove a packet with seq from send trans */ +static void trans_remove(PurpleConnection *gc, qq_transaction *trans) +{ + qq_data *qd = (qq_data *)gc->proto_data; + + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + g_return_if_fail(trans != NULL); +#if 0 + purple_debug_info("QQ_TRANS", "Remove [%s%05d] retry %d rcved %d scan %d %s\n", (trans->flag & QQ_TRANS_IS_SERVER) ? "SRV-" : "", trans->seq, trans->send_retries, trans->rcved_times, trans->scan_times, qq_get_cmd_desc(trans->cmd)); - +#endif if (trans->data) g_free(trans->data); qd->transactions = g_list_remove(qd->transactions, trans); g_free(trans); } -void qq_trans_add_client_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len) +static qq_transaction *trans_find(PurpleConnection *gc, guint16 cmd, guint16 seq) { - qq_transaction *trans = g_new0(qq_transaction, 1); + qq_data *qd; + GList *list; + qq_transaction *trans; - g_return_if_fail(trans != NULL); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); + qd = (qq_data *) gc->proto_data; - trans->flag = 0; - if (cmd == QQ_CMD_TOKEN || cmd == QQ_CMD_LOGIN || cmd == QQ_CMD_KEEP_ALIVE) { - trans->flag |= QQ_TRANS_CLI_IMPORT; + list = qd->transactions; + while (list != NULL) { + trans = (qq_transaction *) list->data; + if(trans->cmd == cmd && trans->seq == seq) { + return trans; + } + list = list->next; } - trans->fd = qd->fd; - trans->cmd = cmd; - trans->seq = seq; - trans->room_cmd = 0; - trans->room_id = 0; - trans->send_retries = QQ_RESEND_MAX; - trans->rcved_times = 0; - trans->scan_times = 0; + + return NULL; +} - trans->data = NULL; - trans->data_len = 0; - if (data != NULL && data_len > 0) { - trans->data = g_memdup(data, data_len); /* don't use g_strdup, may have 0x00 */ - trans->data_len = data_len; +void qq_trans_add_client_cmd(PurpleConnection *gc, + guint16 cmd, guint16 seq, guint8 *data, gint data_len, gint update_class, guint32 ship32) +{ + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, update_class, ship32); + + if (cmd == QQ_CMD_TOKEN || cmd == QQ_CMD_LOGIN || cmd == QQ_CMD_KEEP_ALIVE) { + trans->flag |= QQ_TRANS_IS_IMPORT; } - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", - "Add client cmd, seq = %d, data = %p, len = %d\n", + trans->send_retries = qd->resend_times; +#if 0 + purple_debug_info("QQ_TRANS", "Add client cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); +#endif qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_add_room_cmd(qq_data *qd, guint16 seq, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len) +qq_transaction *qq_trans_find_rcved(PurpleConnection *gc, guint16 cmd, guint16 seq) { - qq_transaction *trans = g_new0(qq_transaction, 1); + qq_transaction *trans; + + trans = trans_find(gc, cmd, seq); + if (trans == NULL) { + return NULL; + } - g_return_if_fail(trans != NULL); + if (trans->rcved_times == 0) { + trans->scan_times = 0; + } + trans->rcved_times++; + /* server may not get our confirm reply before, send reply again*/ + if (qq_trans_is_server(trans) && (trans->flag & QQ_TRANS_IS_REPLY)) { + if (trans->data != NULL && trans->data_len > 0) { + qq_send_cmd_encrypted(gc, trans->cmd, trans->seq, trans->data, trans->data_len, FALSE); + } + } + return trans; +} - trans->flag = 0; - trans->fd = qd->fd; - trans->seq = seq; - trans->cmd = QQ_CMD_ROOM; +void qq_trans_add_room_cmd(PurpleConnection *gc, + guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len, + gint update_class, guint32 ship32) +{ + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, QQ_CMD_ROOM, seq, data, data_len, + update_class, ship32); + trans->room_cmd = room_cmd; trans->room_id = room_id; - trans->send_retries = QQ_RESEND_MAX; - trans->rcved_times = 0; - trans->scan_times = 0; - - trans->data = NULL; - trans->data_len = 0; - if (data != NULL && data_len > 0) { - trans->data = g_memdup(data, data_len); /* don't use g_strdup, may have 0x00 */ - trans->data_len = data_len; - } - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", - "Add room cmd, seq = %d, data = %p, len = %d\n", + trans->send_retries = qd->resend_times; +#if 0 + purple_debug_info("QQ_TRANS", "Add room cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); +#endif qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_add_server_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len) +void qq_trans_add_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *rcved, gint rcved_len) { - qq_transaction *trans = g_new0(qq_transaction, 1); - - g_return_if_fail(trans != NULL); + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, rcved, rcved_len, QQ_CMD_CLASS_NONE, 0); trans->flag = QQ_TRANS_IS_SERVER; - if ( !qd->logged_in ) { - trans->flag |= QQ_TRANS_BEFORE_LOGIN; - } - trans->fd = qd->fd; - trans->cmd = cmd; - trans->seq = seq; - trans->room_cmd = 0; - trans->room_id = 0; trans->send_retries = 0; trans->rcved_times = 1; - trans->scan_times = 0; - trans->data = NULL; - trans->data_len = 0; - if (data != NULL && data_len > 0) { - trans->data = g_memdup(data, data_len); /* don't use g_strdup, may have 0x00 */ - trans->data_len = data_len; - } - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", - "Add server cmd, seq = %d, data = %p, len = %d\n", +#if 0 + purple_debug_info("QQ_TRANS", "Add server cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); +#endif qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_process_before_login(qq_data *qd) +void qq_trans_add_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *reply, gint reply_len) { + qq_transaction *trans; + + g_return_if_fail(reply != NULL && reply_len > 0); + + trans = trans_find(gc, cmd, seq); + if (trans == NULL) { + return; + } + + g_return_if_fail(trans->flag & QQ_TRANS_IS_SERVER); + trans->flag |= QQ_TRANS_IS_REPLY; + + if (trans->data) g_free(trans->data); + + trans->data = g_memdup(reply, reply_len); + trans->data_len = reply_len; +} + +void qq_trans_add_remain(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len) +{ + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, QQ_CMD_CLASS_NONE, 0); + + trans->flag = QQ_TRANS_IS_SERVER; + trans->flag |= QQ_TRANS_REMAINED; + trans->send_retries = 0; + trans->rcved_times = 1; +#if 1 + purple_debug_info("QQ_TRANS", "Add server cmd and remained, seq %d, data %p, len %d\n", + trans->seq, trans->data, trans->data_len); +#endif + qd->transactions = g_list_append(qd->transactions, trans); +} + +void qq_trans_process_remained(PurpleConnection *gc) +{ + qq_data *qd = (qq_data *)gc->proto_data; GList *curr; GList *next; qq_transaction *trans; @@ -221,43 +301,46 @@ while( (curr = next) ) { next = curr->next; trans = (qq_transaction *) (curr->data); - /* purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", "Scan [%d]\n", trans->seq); */ - +#if 0 + purple_debug_info("QQ_TRANS", "Scan [%d]\n", trans->seq); +#endif if ( !(trans->flag & QQ_TRANS_IS_SERVER) ) { continue; } - if ( !(trans->flag & QQ_TRANS_BEFORE_LOGIN) ) { + if ( !(trans->flag & QQ_TRANS_REMAINED) ) { continue; } - // set QQ_TRANS_BEFORE_LOGIN off - trans->flag &= ~QQ_TRANS_BEFORE_LOGIN; + /* set QQ_TRANS_REMAINED off */ + trans->flag &= ~QQ_TRANS_REMAINED; - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", - "Process server cmd before login, seq %d, data %p, len %d, send_retries %d\n", +#if 1 + purple_debug_info("QQ_TRANS", + "Process server cmd remained, seq %d, data %p, len %d, send_retries %d\n", trans->seq, trans->data, trans->data_len, trans->send_retries); - - qq_proc_cmd_reply(qd->gc, trans->seq, trans->cmd, trans->data, trans->data_len); +#endif + qq_proc_server_cmd(gc, trans->cmd, trans->seq, trans->data, trans->data_len); } - /* purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Scan finished\n"); */ + /* purple_debug_info("QQ_TRANS", "Scan finished\n"); */ return; } -gboolean qq_trans_scan(qq_data *qd) +gboolean qq_trans_scan(PurpleConnection *gc) { + qq_data *qd = (qq_data *)gc->proto_data; GList *curr; GList *next; qq_transaction *trans; g_return_val_if_fail(qd != NULL, FALSE); - + next = qd->transactions; while( (curr = next) ) { next = curr->next; trans = (qq_transaction *) (curr->data); - /* purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Scan [%d]\n", trans->seq); */ - - if (trans->flag & QQ_TRANS_BEFORE_LOGIN) { + /* purple_debug_info("QQ_TRANS", "Scan [%d]\n", trans->seq); */ + + if (trans->flag & QQ_TRANS_REMAINED) { /* keep server cmd before login*/ continue; } @@ -270,67 +353,62 @@ if (trans->rcved_times > 0) { /* Has been received */ - trans_remove(qd, trans); + trans_remove(gc, trans); continue; } if (trans->flag & QQ_TRANS_IS_SERVER) { continue; } - + /* Never get reply */ trans->send_retries--; if (trans->send_retries <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ_TRANS", + purple_debug_warning("QQ_TRANS", "[%d] %s is lost.\n", trans->seq, qq_get_cmd_desc(trans->cmd)); - if (trans->flag & QQ_TRANS_CLI_IMPORT) { + if (trans->flag & QQ_TRANS_IS_IMPORT) { return TRUE; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", + qd->net_stat.lost++; + purple_debug_error("QQ_TRANS", "Lost [%d] %s, data %p, len %d, retries %d\n", trans->seq, qq_get_cmd_desc(trans->cmd), trans->data, trans->data_len, trans->send_retries); - trans_remove(qd, trans); + trans_remove(gc, trans); continue; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", + qd->net_stat.resend++; + purple_debug_warning("QQ_TRANS", "Resend [%d] %s data %p, len %d, send_retries %d\n", trans->seq, qq_get_cmd_desc(trans->cmd), trans->data, trans->data_len, trans->send_retries); - qq_send_data(qd, trans->cmd, trans->seq, FALSE, trans->data, trans->data_len); + qq_send_cmd_encrypted(gc, trans->cmd, trans->seq, trans->data, trans->data_len, FALSE); } - /* purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Scan finished\n"); */ + /* purple_debug_info("QQ_TRANS", "Scan finished\n"); */ return FALSE; } /* clean up send trans and free all contents */ -void qq_trans_remove_all(qq_data *qd) +void qq_trans_remove_all(PurpleConnection *gc) { - GList *curr; - GList *next; + qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans; gint count = 0; - curr = qd->transactions; - while(curr) { - next = curr->next; - - trans = (qq_transaction *) (curr->data); - /* - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", - "Remove to transaction, seq = %d, buf = %p, len = %d\n", - trans->seq, trans->buf, trans->len); - */ - trans_remove(qd, trans); + while(qd->transactions != NULL) { + trans = (qq_transaction *) (qd->transactions->data); + qd->transactions = g_list_remove(qd->transactions, trans); + + if (trans->data) g_free(trans->data); + g_free(trans); count++; - curr = next; } - g_list_free(qd->transactions); - - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Free all %d packets\n", count); + if (count > 0) { + purple_debug_info("QQ_TRANS", "Free all %d packets\n", count); + } }
--- a/libpurple/protocols/qq/qq_trans.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.h Fri Sep 12 14:26:41 2008 +0000 @@ -28,44 +28,30 @@ #include <glib.h> #include "qq.h" -enum { - QQ_TRANS_IS_SERVER = 0x01, /* Is server command or client command */ - /* prefix QQ_TRANS_CLI is for client command*/ - QQ_TRANS_CLI_EMERGE = 0x02, /* send at once; or may wait for next reply*/ - QQ_TRANS_CLI_IMPORT = 0x04, /* Only notice if not get reply; or resend, disconn if reties get 0*/ - QQ_TRANS_BEFORE_LOGIN = 0x08, /* server command before login*/ -}; - -typedef struct _qq_transaction { - guint8 flag; - guint16 seq; - guint16 cmd; +typedef struct _qq_transaction qq_transaction; - guint8 room_cmd; - guint32 room_id; - - guint8 *data; - gint data_len; - - gint fd; - gint send_retries; - gint rcved_times; - gint scan_times; -} qq_transaction; - -qq_transaction *qq_trans_find_rcved(qq_data *qd, guint16 cmd, guint16 seq); +qq_transaction *qq_trans_find_rcved(PurpleConnection *gc, guint16 cmd, guint16 seq); gboolean qq_trans_is_server(qq_transaction *trans) ; gboolean qq_trans_is_dup(qq_transaction *trans); guint8 qq_trans_get_room_cmd(qq_transaction *trans); guint32 qq_trans_get_room_id(qq_transaction *trans); +gint qq_trans_get_class(qq_transaction *trans); +gint qq_trans_get_ship(qq_transaction *trans); -void qq_trans_add_client_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len); -void qq_trans_add_server_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len); -void qq_trans_add_room_cmd(qq_data *qd, guint16 seq, guint8 room_cmd, guint32 room_id, +void qq_trans_add_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len, gint update_class, guint32 ship32); +void qq_trans_add_room_cmd(PurpleConnection *gc, + guint16 seq, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32); +void qq_trans_add_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *rcved, gint rcved_len); +void qq_trans_add_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *reply, gint reply_len); +void qq_trans_add_remain(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len); -void qq_trans_process_before_login(qq_data *qd); -gboolean qq_trans_scan(qq_data *qd); -void qq_trans_remove_all(qq_data *qd); +void qq_trans_process_remained(PurpleConnection *gc); +gboolean qq_trans_scan(PurpleConnection *gc); +void qq_trans_remove_all(PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/send_file.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/send_file.c Fri Sep 12 14:26:41 2008 +0000 @@ -54,7 +54,7 @@ static int _qq_in_same_lan(ft_info *info) { if (info->remote_internet_ip == info->local_internet_ip) return 1; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Not in the same LAN, remote internet ip[%x], local internet ip[%x]\n", info->remote_internet_ip , info->local_internet_ip); @@ -87,7 +87,7 @@ info = (ft_info *) xfer->data; sinlen = sizeof(sin); r = recvfrom(info->recv_fd, buf, len, 0, (struct sockaddr *) &sin, &sinlen); - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "==> recv %d bytes from File UDP Channel, remote ip[%s], remote port[%d]\n", r, inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); return r; @@ -121,12 +121,12 @@ sin.sin_port = g_htons(info->remote_minor_port); sin.sin_addr.s_addr = g_htonl(info->remote_real_ip); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "sending to channel: %d.%d.%d.%d:%d\n", - (int)sin.sin_addr.s_addr & 0xff, - (int)(sin.sin_addr.s_addr >> 8) & 0xff, - (int)(sin.sin_addr.s_addr >> 16) & 0xff, - (int)sin.sin_addr.s_addr >> 24, - (int)g_ntohs(sin.sin_port) + purple_debug_info("QQ", "sending to channel: %d.%d.%d.%d:%d\n", + sin.sin_addr.s_addr & 0xff, + (sin.sin_addr.s_addr >> 8) & 0xff, + (sin.sin_addr.s_addr >> 16) & 0xff, + sin.sin_addr.s_addr >> 24, + g_ntohs(sin.sin_port) ); return sendto(info->sender_fd, buf, len, 0, (struct sockaddr *) &sin, sizeof(sin)); } @@ -207,20 +207,20 @@ qq_xfer_close_file(xfer); if (info->dest_fp != NULL) { fclose(info->dest_fp); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "file closed\n"); + purple_debug_info("QQ", "file closed\n"); } if (info->major_fd != 0) { close(info->major_fd); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "major port closed\n"); + purple_debug_info("QQ", "major port closed\n"); } if (info->minor_fd != 0) { close(info->minor_fd); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "minor port closed\n"); + purple_debug_info("QQ", "minor port closed\n"); } /* if (info->buffer != NULL) { munmap(info->buffer, purple_xfer_get_size(xfer)); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "file mapping buffer is freed.\n"); + purple_debug_info("QQ", "file mapping buffer is freed.\n"); } */ g_free(info); @@ -235,7 +235,7 @@ real_ip_str = gen_ip_str((guint8 *) &ip); ip = g_htonl(info->remote_internet_ip); internet_ip_str = gen_ip_str((guint8 *) &ip); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "remote internet ip[%s:%d], major port[%d], real ip[%s], minor port[%d]\n", + purple_debug_info("QQ", "remote internet ip[%s:%d], major port[%d], real ip[%s], minor port[%d]\n", internet_ip_str, info->remote_internet_port, info->remote_major_port, real_ip_str, info->remote_minor_port ); @@ -393,7 +393,7 @@ info->local_real_ip = 0x7f000001; */ info->local_real_ip = g_ntohl(inet_addr(purple_network_get_my_ip(-1))); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "local real ip is %x", info->local_real_ip); + purple_debug_info("QQ", "local real ip is %x", info->local_real_ip); for (i = 0; i < 2; i++) { sockfd = socket(PF_INET, SOCK_DGRAM, 0); @@ -412,13 +412,13 @@ case 0: info->local_major_port = listen_port; info->major_fd = sockfd; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Major Channel created on port[%d]\n", + purple_debug_info("QQ", "UDP Major Channel created on port[%d]\n", info->local_major_port); break; case 1: info->local_minor_port = listen_port; info->minor_fd = sockfd; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Minor Channel created on port[%d]\n", + purple_debug_info("QQ", "UDP Minor Channel created on port[%d]\n", info->local_minor_port); break; } @@ -475,9 +475,9 @@ bytes += qq_putdata (raw_data + bytes, (guint8 *) filelen_str, filelen_strlen); if (packet_len == bytes) - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_request", + purple_debug_info("qq_send_packet_file_request", "%d bytes expected but got %d bytes\n", packet_len, bytes); @@ -497,7 +497,7 @@ qd = (qq_data *) gc->proto_data; info = (ft_info *) qd->xfer->data; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "I've accepted the file transfer request from %d\n", to_uid); + purple_debug_info("QQ", "I've accepted the file transfer request from %d\n", to_uid); _qq_xfer_init_socket(qd->xfer); packet_len = 79; @@ -516,9 +516,9 @@ info->local_real_ip = real_ip; if (packet_len == bytes) - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_accept", + purple_debug_info("qq_send_packet_file_accept", "%d bytes expected but got %d bytes\n", packet_len, bytes); } @@ -539,13 +539,13 @@ raw_data = g_newa (guint8, packet_len); bytes = 0; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== sending qq file notify ip packet\n"); + purple_debug_info("QQ", "<== sending qq file notify ip packet\n"); bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_NOTIFY, qd, TRUE); bytes += qq_fill_conn_info(raw_data + bytes, info); if (packet_len == bytes) - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_notify", + purple_debug_info("qq_send_packet_file_notify", "%d bytes expected but got %d bytes\n", packet_len, bytes); @@ -561,7 +561,7 @@ guint8 *raw_data; gint packet_len, bytes; - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_reject", "start"); + purple_debug_info("_qq_send_packet_file_reject", "start"); qd = (qq_data *) gc->proto_data; packet_len = 64; @@ -571,9 +571,9 @@ bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_DENY_UDP, qd, TRUE); if (packet_len == bytes) - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file", + purple_debug_info("qq_send_packet_file", "%d bytes expected but got %d bytes\n", packet_len, bytes); } @@ -585,27 +585,27 @@ guint8 *raw_data; gint packet_len, bytes; - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "start\n"); + purple_debug_info("_qq_send_packet_file_cancel", "start\n"); qd = (qq_data *) gc->proto_data; packet_len = 64; raw_data = g_newa (guint8, packet_len); bytes = 0; - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "before create header\n"); + purple_debug_info("_qq_send_packet_file_cancel", "before create header\n"); bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_CANCEL, qd, TRUE); - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "end create header\n"); + purple_debug_info("_qq_send_packet_file_cancel", "end create header\n"); if (packet_len == bytes) { - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "before send cmd\n"); - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + purple_debug_info("_qq_send_packet_file_cancel", "before send cmd\n"); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); } else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file", + purple_debug_info("qq_send_packet_file", "%d bytes expected but got %d bytes\n", packet_len, bytes); - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_cancel", "end\n"); + purple_debug_info("qq_send_packet_file_cancel", "end\n"); } /* request to send a file */ @@ -694,7 +694,7 @@ /* border has been checked before if (*cursor >= (data + data_len - 1)) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Received file reject message is empty\n"); return; } @@ -724,8 +724,7 @@ /* border has been checked before if (*cursor >= (data + data_len - 1)) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file reject message is empty\n"); + purple_debug_warning("QQ", "Received file reject message is empty\n"); return; } */ @@ -755,8 +754,7 @@ info = (ft_info *) qd->xfer->data; if (data_len <= 30 + QQ_CONN_INFO_LEN) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file reject message is empty\n"); + purple_debug_warning("QQ", "Received file reject message is empty\n"); return; } @@ -789,8 +787,7 @@ info->to_uid = sender_uid; if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file request message is empty\n"); + purple_debug_warning("QQ", "Received file request message is empty\n"); return; } bytes = 0; @@ -806,7 +803,7 @@ /* FACE from IP detector, ignored by gfhuang */ if(g_ascii_strcasecmp(fileinfo[0], "FACE") == 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Received a FACE ip detect from qq-%d, so he/she must be online :)\n", sender_uid); b = purple_find_buddy(gc->account, sender_name); @@ -826,11 +823,11 @@ qq_update_buddy_contact(gc, q_bud); } else - purple_debug(PURPLE_DEBUG_INFO, "QQ", "buddy %d is already online\n", sender_uid); + purple_debug_info("QQ", "buddy %d is already online\n", sender_uid); } else - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "buddy %d is not in list\n", sender_uid); + purple_debug_warning("QQ", "buddy %d is not in list\n", sender_uid); g_free(sender_name); g_strfreev(fileinfo); @@ -892,8 +889,7 @@ xfer = qd->xfer; info = (ft_info *) qd->xfer->data; if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file notify message is empty\n"); + purple_debug_warning("QQ", "Received file notify message is empty\n"); return; }
--- a/libpurple/protocols/qq/sys_msg.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/sys_msg.c Fri Sep 12 14:26:41 2008 +0000 @@ -84,7 +84,7 @@ nombre = uid_to_purple_name(uid); purple_request_action - (gc, NULL, _("Do you want to approve the request?"), "", + (gc, NULL, _("Do you approve the requestion?"), "", PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), nombre, NULL, g, 2, @@ -108,7 +108,7 @@ qq_send_packet_get_info(gc, uid, TRUE); /* we want to see window */ nombre = uid_to_purple_name(uid); purple_request_action - (gc, NULL, _("Do you want to add this buddy?"), "", + (gc, NULL, _("Do you add the buddy?"), "", PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), nombre, NULL, g, 2, @@ -126,7 +126,7 @@ gint ack_len, bytes; qd = (qq_data *) gc->proto_data; - + str = g_strdup_printf("%d", from); bar = 0x1e; ack_len = 1 + 1 + strlen(str) + 1 + 2; @@ -142,9 +142,9 @@ g_free(str); if (bytes == ack_len) /* creation OK */ - qq_send_cmd_detail(qd, QQ_CMD_ACK_SYS_MSG, 0, FALSE, ack, ack_len); + qq_send_server_reply(gc, QQ_CMD_ACK_SYS_MSG, 0, ack, ack_len); else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); } @@ -178,9 +178,9 @@ _("Add"), G_CALLBACK(qq_add_buddy_with_gc_and_uid), _("Search"), G_CALLBACK(_qq_search_before_add_with_gc_and_uid)); } else { - message = g_strdup_printf(_("%s has added you [%s] to his or her buddy list"), from, to); + message = g_strdup_printf(_("%s added you [%s] to buddy list"), from, to); _qq_sys_msg_log_write(gc, message, from); - purple_notify_info(gc, NULL, message, NULL); + purple_notify_info(gc, _("QQ Budy"), _("Successed:"), message); } g_free(name); @@ -194,11 +194,11 @@ g_return_if_fail(from != NULL && to != NULL); - message = g_strdup_printf(_("User %s rejected your request"), from); - reason = g_strdup_printf(_("Reason: %s"), msg_utf8); + message = g_strdup_printf(_("Requestion rejected by %s"), from); + reason = g_strdup_printf(_("Message: %s"), msg_utf8); _qq_sys_msg_log_write(gc, message, from); - purple_notify_info(gc, NULL, message, reason); + purple_notify_info(gc, _("QQ Buddy"), message, reason); g_free(message); g_free(reason); } @@ -214,9 +214,9 @@ qd = (qq_data *) gc->proto_data; qq_add_buddy_by_recv_packet(gc, strtol(from, NULL, 10), TRUE, TRUE); - message = g_strdup_printf(_("User %s approved your request"), from); + message = g_strdup_printf(_("Requestion approved by %s"), from); _qq_sys_msg_log_write(gc, message, from); - purple_notify_info(gc, NULL, message, NULL); + purple_notify_info(gc, _("QQ Buddy"), _("Notice:"), message); g_free(message); } @@ -263,9 +263,9 @@ g2 = g_new0(gc_and_uid, 1); g2->gc = gc; g2->uid = strtol(from, NULL, 10); - message = g_strdup_printf(_("%s is not in your buddy list"), from); + message = g_strdup_printf(_("%s is not in buddy list"), from); purple_request_action(gc, NULL, message, - _("Would you like to add him?"), PURPLE_DEFAULT_ACTION_NONE, + _("Would you add?"), PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), name, NULL, g2, 3, _("Cancel"), NULL, @@ -279,14 +279,19 @@ static void _qq_process_msg_sys_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) { + qq_data *qd = (qq_data *) gc->proto_data; gchar *title, *content; g_return_if_fail(from != NULL && to != NULL); - title = g_strdup_printf(_("Notice from: %s"), from); + title = g_strdup_printf(_("From %s:"), from); content = g_strdup_printf(_("%s"), msg_utf8); - purple_notify_info(gc, NULL, title, content); + if (qd->is_show_notice) { + purple_notify_info(gc, _("QQ Server Notice"), title, content); + } else { + purple_debug_info("QQ", "QQ Server notice from %s:\n%s", from, msg_utf8); +} g_free(title); g_free(content); } @@ -310,12 +315,19 @@ _qq_send_packet_ack_msg_sys(gc, code[0], strtol(from, NULL, 10), seq); if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Recv sys msg to [%s], not me!, discard\n", to); + purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to); g_strfreev(segments); return; } msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + if (from == NULL && msg_utf8) { + purple_debug_error("QQ", "Recv NULL sys msg to [%s], discard\n", to); + g_strfreev(segments); + g_free(msg_utf8); + return; + } + switch (strtol(code, NULL, 10)) { case QQ_MSG_SYS_BEING_ADDED: _qq_process_msg_sys_being_added(gc, from, to, msg_utf8); @@ -333,12 +345,12 @@ _qq_process_msg_sys_notice(gc, from, to, msg_utf8); break; case QQ_MSG_SYS_NEW_VERSION: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "QQ server says there is newer version than %s\n", qq_get_ver_desc(QQ_CLIENT)); break; default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Recv unknown sys msg code: %s\n", code); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "the msg is : %s\n", msg_utf8); + purple_debug_warning("QQ", "Recv unknown sys msg code: %s\n", code); + purple_debug_warning("QQ", "the msg is : %s\n", msg_utf8); } g_free(msg_utf8); g_strfreev(segments);
--- a/libpurple/protocols/qq/utils.c Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/utils.c Fri Sep 12 14:26:41 2008 +0000 @@ -47,8 +47,8 @@ struct sockaddr_in sin; socklen_t len = sizeof(sin); getsockname(fd, (struct sockaddr *)&sin, &len); - purple_debug(PURPLE_DEBUG_INFO, desc, "%s:%d\n", - inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); + purple_debug_info(desc, "%s:%d\n", + inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); } */ @@ -121,16 +121,16 @@ for (i = 0; segments[i] != NULL; i++) {; } if (i < expected_fields) { /* not enough fields */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid data, expect %d fields, found only %d, discard\n", expected_fields, i); + purple_debug_error("QQ", "Invalid data, expect %d fields, found only %d, discard\n", + expected_fields, i); g_strfreev(segments); return NULL; } else if (i > expected_fields) { /* more fields, OK */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Dangerous data, expect %d fields, found %d, return all\n", expected_fields, i); + purple_debug_warning("QQ", "Dangerous data, expect %d fields, found %d, return all\n", + expected_fields, i); /* free up those not used */ for (j = expected_fields; j < i; j++) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "field[%d] is %s\n", j, segments[j]); + purple_debug_warning("QQ", "field[%d] is %s\n", j, segments[j]); g_free(segments[j]); } @@ -218,7 +218,7 @@ msg_utf8 = i < len ? qq_to_utf8((gchar *) &incoming[i], QQ_CHARSET_DEFAULT) : NULL; if (msg_utf8 != NULL) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Try extract GB msg: %s\n", msg_utf8); + purple_debug_warning("QQ", "Try extract GB msg: %s\n", msg_utf8); } return msg_utf8; } @@ -257,7 +257,7 @@ hex_buffer = strstrip(buffer); if (strlen(hex_buffer) % 2 != 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Unable to convert an odd number of nibbles to a string of bytes!\n"); g_free(hex_buffer); return NULL; @@ -272,8 +272,8 @@ } else if (g_ascii_isalpha(*cursor) && (gint) *cursor - 87 < 16) { nibble1 = (gint) *cursor - 87; } else { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invalid char \'%c\' found in hex string!\n", *cursor); + purple_debug_warning("QQ", "Invalid char \'%c\' found in hex string!\n", + *cursor); g_free(hex_str); return NULL; } @@ -284,8 +284,7 @@ } else if (g_ascii_isalpha(*cursor) && (gint) (*cursor - 87) < 16) { nibble2 = (gint) *cursor - 87; } else { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invalid char found in hex string!\n"); + purple_debug_warning("QQ", "Invalid char found in hex string!\n"); g_free(hex_str); return NULL; } @@ -362,22 +361,7 @@ void qq_show_packet(const gchar *desc, const guint8 *buf, gint len) { - /* - char buf1[8*len+2], buf2[10]; - int i; - buf1[0] = 0; - for (i = 0; i < len; i++) { - sprintf(buf2, " %02x(%d)", buf[i] & 0xff, buf[i] & 0xff); - strcat(buf1, buf2); - } - strcat(buf1, "\n"); - purple_debug(PURPLE_DEBUG_INFO, desc, "%s", buf1); - */ - - /* modified by s3e, 20080424 */ - qq_hex_dump(PURPLE_DEBUG_INFO, desc, - buf, len, - ""); + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", buf, len, desc); } /* convert face num from packet (0-299) to local face (1-100) */ @@ -397,5 +381,16 @@ if (purple_prefs_exists("/prpl/qq/buddy_icon_dir")) return purple_prefs_get_string("/prpl/qq/buddy_icon_dir"); else - return NULL; + return QQ_BUDDY_ICON_DIR; } + +#ifdef _WIN32 +const char *qq_win32_buddy_icon_dir(void) +{ + static char *dir = NULL; + if (dir == NULL) + dir = g_build_filename(wpurple_install_dir(), "pixmaps", + "purple", "buddy_icons", "qq", NULL); + return dir; +} +#endif
--- a/libpurple/protocols/qq/utils.h Thu Sep 11 22:30:04 2008 +0000 +++ b/libpurple/protocols/qq/utils.h Fri Sep 12 14:26:41 2008 +0000 @@ -56,5 +56,6 @@ guint8 *hex_str_to_bytes(const gchar *buf, gint *out_len); const gchar *qq_buddy_icon_dir(void); +const gchar *qq_win32_buddy_icon_dir(void); #endif