icq.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package handler
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/binary"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "log/slog"
  10. "github.com/mk6i/retro-aim-server/server/oscar"
  11. "github.com/mk6i/retro-aim-server/server/oscar/middleware"
  12. "github.com/mk6i/retro-aim-server/state"
  13. "github.com/mk6i/retro-aim-server/wire"
  14. )
  15. type ICQService interface {
  16. DeleteMsgReq(ctx context.Context, sess *state.Session, seq uint16) error
  17. FindByICQName(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0515_DBQueryMetaReqSearchByDetails, seq uint16) error
  18. FindByICQEmail(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0529_DBQueryMetaReqSearchByEmail, seq uint16) error
  19. FindByEmail3(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0573_DBQueryMetaReqSearchByEmail3, seq uint16) error
  20. FindByICQInterests(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0533_DBQueryMetaReqSearchWhitePages, seq uint16) error
  21. FindByUIN(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x051F_DBQueryMetaReqSearchByUIN, seq uint16) error
  22. FindByUIN2(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0569_DBQueryMetaReqSearchByUIN2, seq uint16) error
  23. FindByWhitePages2(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x055F_DBQueryMetaReqSearchWhitePages2, seq uint16) error
  24. FullUserInfo(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x051F_DBQueryMetaReqSearchByUIN, seq uint16) error
  25. OfflineMsgReq(ctx context.Context, sess *state.Session, seq uint16) error
  26. SetAffiliations(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x041A_DBQueryMetaReqSetAffiliations, seq uint16) error
  27. SetBasicInfo(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x03EA_DBQueryMetaReqSetBasicInfo, seq uint16) error
  28. SetEmails(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x040B_DBQueryMetaReqSetEmails, seq uint16) error
  29. SetInterests(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0410_DBQueryMetaReqSetInterests, seq uint16) error
  30. SetMoreInfo(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x03FD_DBQueryMetaReqSetMoreInfo, seq uint16) error
  31. SetPermissions(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0424_DBQueryMetaReqSetPermissions, seq uint16) error
  32. SetUserNotes(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0406_DBQueryMetaReqSetNotes, seq uint16) error
  33. SetWorkInfo(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x03F3_DBQueryMetaReqSetWorkInfo, seq uint16) error
  34. ShortUserInfo(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x04BA_DBQueryMetaReqShortInfo, seq uint16) error
  35. XMLReqData(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x0898_DBQueryMetaReqXMLReq, seq uint16) error
  36. }
  37. var (
  38. errUnknownICQMetaReqType = errors.New("unknown ICQ request type")
  39. errUnknownICQMetaReqSubType = errors.New("unknown ICQ metadata request subtype")
  40. )
  41. func NewICQHandler(logger *slog.Logger, ICQService ICQService) ICQHandler {
  42. return ICQHandler{
  43. RouteLogger: middleware.RouteLogger{
  44. Logger: logger,
  45. },
  46. ICQService: ICQService,
  47. }
  48. }
  49. type ICQHandler struct {
  50. ICQService
  51. middleware.RouteLogger
  52. }
  53. func (rt ICQHandler) DBQuery(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, r io.Reader, rw oscar.ResponseWriter) error {
  54. inBody := wire.SNAC_0x15_0x02_BQuery{}
  55. if err := wire.UnmarshalBE(&inBody, r); err != nil {
  56. return err
  57. }
  58. md, ok := inBody.Bytes(wire.ICQTLVTagsMetadata)
  59. if !ok {
  60. return errors.New("invalid ICQ frame")
  61. }
  62. icqChunk := wire.ICQMessageRequestEnvelope{}
  63. if err := wire.UnmarshalLE(&icqChunk, bytes.NewBuffer(md)); err != nil {
  64. return err
  65. }
  66. buf := bytes.NewBuffer(icqChunk.Body)
  67. icqMD := wire.ICQMetadataWithSubType{}
  68. if err := wire.UnmarshalLE(&icqMD, buf); err != nil {
  69. return err
  70. }
  71. switch icqMD.ReqType {
  72. case wire.ICQDBQueryOfflineMsgReq:
  73. return rt.ICQService.OfflineMsgReq(ctx, sess, icqMD.Seq)
  74. case wire.ICQDBQueryDeleteMsgReq:
  75. return rt.ICQService.DeleteMsgReq(ctx, sess, icqMD.Seq)
  76. case wire.ICQDBQueryMetaReq:
  77. if icqMD.Optional == nil {
  78. return errors.New("got req without subtype")
  79. }
  80. rt.Logger.Debug("ICQ client request",
  81. "query_name", wire.ICQDBQueryName(icqMD.ReqType),
  82. "query_type", wire.ICQDBQueryMetaName(icqMD.Optional.ReqSubType),
  83. "uin", sess.UIN())
  84. switch icqMD.Optional.ReqSubType {
  85. case wire.ICQDBQueryMetaReqShortInfo:
  86. userInfo := wire.ICQ_0x07D0_0x04BA_DBQueryMetaReqShortInfo{}
  87. if err := binary.Read(buf, binary.LittleEndian, &userInfo); err != nil {
  88. return nil
  89. }
  90. return rt.ICQService.ShortUserInfo(ctx, sess, userInfo, icqMD.Seq)
  91. case wire.ICQDBQueryMetaReqFullInfo, wire.ICQDBQueryMetaReqFullInfo2:
  92. userInfo := wire.ICQ_0x07D0_0x051F_DBQueryMetaReqSearchByUIN{}
  93. if err := binary.Read(buf, binary.LittleEndian, &userInfo); err != nil {
  94. return nil
  95. }
  96. return rt.ICQService.FullUserInfo(ctx, sess, userInfo, icqMD.Seq)
  97. case wire.ICQDBQueryMetaReqXMLReq:
  98. req := wire.ICQ_0x07D0_0x0898_DBQueryMetaReqXMLReq{}
  99. if err := wire.UnmarshalLE(&req, buf); err != nil {
  100. return err
  101. }
  102. if err := rt.ICQService.XMLReqData(ctx, sess, req, icqMD.Seq); err != nil {
  103. return err
  104. }
  105. case wire.ICQDBQueryMetaReqSetPermissions:
  106. req := wire.ICQ_0x07D0_0x0424_DBQueryMetaReqSetPermissions{}
  107. if err := wire.UnmarshalLE(&req, buf); err != nil {
  108. return err
  109. }
  110. if err := rt.ICQService.SetPermissions(ctx, sess, req, icqMD.Seq); err != nil {
  111. return err
  112. }
  113. case wire.ICQDBQueryMetaReqSearchByUIN:
  114. req := wire.ICQ_0x07D0_0x051F_DBQueryMetaReqSearchByUIN{}
  115. if err := wire.UnmarshalLE(&req, buf); err != nil {
  116. return err
  117. }
  118. if err := rt.ICQService.FindByUIN(ctx, sess, req, icqMD.Seq); err != nil {
  119. return err
  120. }
  121. case wire.ICQDBQueryMetaReqSearchByUIN2:
  122. req := wire.ICQ_0x07D0_0x0569_DBQueryMetaReqSearchByUIN2{}
  123. if err := wire.UnmarshalLE(&req, buf); err != nil {
  124. return err
  125. }
  126. if err := rt.ICQService.FindByUIN2(ctx, sess, req, icqMD.Seq); err != nil {
  127. return err
  128. }
  129. case wire.ICQDBQueryMetaReqSearchByEmail:
  130. req := wire.ICQ_0x07D0_0x0529_DBQueryMetaReqSearchByEmail{}
  131. if err := wire.UnmarshalLE(&req, buf); err != nil {
  132. return err
  133. }
  134. if err := rt.ICQService.FindByICQEmail(ctx, sess, req, icqMD.Seq); err != nil {
  135. return err
  136. }
  137. case wire.ICQDBQueryMetaReqSearchByEmail3:
  138. req := wire.ICQ_0x07D0_0x0573_DBQueryMetaReqSearchByEmail3{}
  139. if err := wire.UnmarshalLE(&req, buf); err != nil {
  140. return err
  141. }
  142. if err := rt.ICQService.FindByEmail3(ctx, sess, req, icqMD.Seq); err != nil {
  143. return err
  144. }
  145. case wire.ICQDBQueryMetaReqSearchByDetails:
  146. req := wire.ICQ_0x07D0_0x0515_DBQueryMetaReqSearchByDetails{}
  147. if err := wire.UnmarshalLE(&req, buf); err != nil {
  148. return err
  149. }
  150. if err := rt.ICQService.FindByICQName(ctx, sess, req, icqMD.Seq); err != nil {
  151. return err
  152. }
  153. case wire.ICQDBQueryMetaReqSearchWhitePages:
  154. req := wire.ICQ_0x07D0_0x0533_DBQueryMetaReqSearchWhitePages{}
  155. if err := wire.UnmarshalLE(&req, buf); err != nil {
  156. return err
  157. }
  158. if err := rt.ICQService.FindByICQInterests(ctx, sess, req, icqMD.Seq); err != nil {
  159. return err
  160. }
  161. case wire.ICQDBQueryMetaReqSearchWhitePages2:
  162. req := wire.ICQ_0x07D0_0x055F_DBQueryMetaReqSearchWhitePages2{}
  163. if err := wire.UnmarshalLE(&req, buf); err != nil {
  164. return err
  165. }
  166. if err := rt.ICQService.FindByWhitePages2(ctx, sess, req, icqMD.Seq); err != nil {
  167. return err
  168. }
  169. case wire.ICQDBQueryMetaReqSetBasicInfo:
  170. req := wire.ICQ_0x07D0_0x03EA_DBQueryMetaReqSetBasicInfo{}
  171. if err := wire.UnmarshalLE(&req, buf); err != nil {
  172. return err
  173. }
  174. if err := rt.ICQService.SetBasicInfo(ctx, sess, req, icqMD.Seq); err != nil {
  175. return err
  176. }
  177. case wire.ICQDBQueryMetaReqSetWorkInfo:
  178. req := wire.ICQ_0x07D0_0x03F3_DBQueryMetaReqSetWorkInfo{}
  179. if err := wire.UnmarshalLE(&req, buf); err != nil {
  180. return err
  181. }
  182. if err := rt.ICQService.SetWorkInfo(ctx, sess, req, icqMD.Seq); err != nil {
  183. return err
  184. }
  185. case wire.ICQDBQueryMetaReqSetMoreInfo:
  186. req := wire.ICQ_0x07D0_0x03FD_DBQueryMetaReqSetMoreInfo{}
  187. if err := wire.UnmarshalLE(&req, buf); err != nil {
  188. return err
  189. }
  190. if err := rt.ICQService.SetMoreInfo(ctx, sess, req, icqMD.Seq); err != nil {
  191. return err
  192. }
  193. case wire.ICQDBQueryMetaReqSetNotes:
  194. req := wire.ICQ_0x07D0_0x0406_DBQueryMetaReqSetNotes{}
  195. if err := wire.UnmarshalLE(&req, buf); err != nil {
  196. return err
  197. }
  198. if err := rt.ICQService.SetUserNotes(ctx, sess, req, icqMD.Seq); err != nil {
  199. return err
  200. }
  201. case wire.ICQDBQueryMetaReqSetEmails:
  202. req := wire.ICQ_0x07D0_0x040B_DBQueryMetaReqSetEmails{}
  203. if err := wire.UnmarshalLE(&req, buf); err != nil {
  204. return err
  205. }
  206. if err := rt.ICQService.SetEmails(ctx, sess, req, icqMD.Seq); err != nil {
  207. return err
  208. }
  209. case wire.ICQDBQueryMetaReqSetInterests:
  210. req := wire.ICQ_0x07D0_0x0410_DBQueryMetaReqSetInterests{}
  211. if err := wire.UnmarshalLE(&req, buf); err != nil {
  212. return err
  213. }
  214. if err := rt.ICQService.SetInterests(ctx, sess, req, icqMD.Seq); err != nil {
  215. return err
  216. }
  217. case wire.ICQDBQueryMetaReqSetAffiliations:
  218. req := wire.ICQ_0x07D0_0x041A_DBQueryMetaReqSetAffiliations{}
  219. if err := wire.UnmarshalLE(&req, buf); err != nil {
  220. return err
  221. }
  222. if err := rt.ICQService.SetAffiliations(ctx, sess, req, icqMD.Seq); err != nil {
  223. return err
  224. }
  225. case wire.ICQDBQueryMetaReqStat0a8c,
  226. wire.ICQDBQueryMetaReqStat0a96,
  227. wire.ICQDBQueryMetaReqStat0aaa,
  228. wire.ICQDBQueryMetaReqStat0ab4,
  229. wire.ICQDBQueryMetaReqStat0ab9,
  230. wire.ICQDBQueryMetaReqStat0abe,
  231. wire.ICQDBQueryMetaReqStat0ac8,
  232. wire.ICQDBQueryMetaReqStat0acd,
  233. wire.ICQDBQueryMetaReqStat0ad2,
  234. wire.ICQDBQueryMetaReqStat0ad7,
  235. wire.ICQDBQueryMetaReqStat0758:
  236. rt.Logger.Debug("got a request for stats, not doing anything right now")
  237. default:
  238. return fmt.Errorf("%w: %X", errUnknownICQMetaReqSubType, icqMD.Optional.ReqSubType)
  239. }
  240. default:
  241. return fmt.Errorf("%w: %X", errUnknownICQMetaReqType, icqMD.ReqType)
  242. }
  243. return nil
  244. }