diff --git a/discord.go b/discord.go
index db59670b90836599e969c511164b3bf048b7ce63..bd6048ee2ce84c2e6b6b55ede8080bdd1c3d3d8c 100644
--- a/discord.go
+++ b/discord.go
@@ -49,5 +49,7 @@ func openDiscord() {
 }
 
 func handleDiscord() {
-	// TODO
+	session.AddHandler(func(session *discordgo.Session, create *discordgo.MessageCreate) {
+		// TODO
+	})
 }
diff --git a/main.go b/main.go
index 415593f1620800baf1b818605b25170cdfa07cdf..91f208fddd28e07747de63c7d392bff2201db7d3 100644
--- a/main.go
+++ b/main.go
@@ -6,12 +6,14 @@ import (
 	"os"
 	"os/signal"
 	"syscall"
+	"time"
 )
 
 var (
-	exec  string
-	rest  bool
-	ready = make(chan struct{})
+	exec      string
+	rest      bool
+	ready     = make(chan struct{})
+	readyTime time.Time
 )
 
 func main() {
@@ -24,6 +26,7 @@ func main() {
 	go func() {
 		<-ready
 		<-ready
+		readyTime = time.Now()
 		log.Print("sessions ready, starting handlers")
 		go handleDiscord()
 		go handleTelegram()
diff --git a/telegram.go b/telegram.go
index 3e8ac1b64eea8d47e906088194831915ba0f7f5c..433b4ef3ccb40e5b324fc0760a216ebdfd7ff44a 100644
--- a/telegram.go
+++ b/telegram.go
@@ -3,12 +3,10 @@ package main
 import (
 	"github.com/bwmarrin/discordgo"
 	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
-	"io"
 	"log"
 	"net/http"
 	"strconv"
 	"strings"
-	"time"
 )
 
 var botAPI *tgbotapi.BotAPI
@@ -48,8 +46,23 @@ func handleTelegram() {
 		log.Fatalf("error getting updates: %s", err)
 	} else {
 		if config.Telegram.BypassBacklog {
-			time.Sleep(time.Millisecond * 500)
-			updates.Clear()
+			for update := range updates {
+				if update.Message == nil {
+					continue
+				}
+
+				if update.Message.Time().After(readyTime) {
+					if config.System.Verbose {
+						log.Printf("update %v after current, breaking bypass loop", update.UpdateID)
+					}
+					respondTelegram(update)
+					break
+				}
+
+				if config.System.Verbose {
+					log.Printf("skipped update %v", update.UpdateID)
+				}
+			}
 		}
 
 		for update := range updates {
@@ -68,15 +81,44 @@ func setPreviousCaller(cid int64, uid int) bool {
 	return false
 }
 
+var (
+	messageReference = make(map[int]*discordgo.MessageReference)
+	hasHeader        = make(map[int]bool)
+)
+
 func respondTelegram(update tgbotapi.Update) {
-	// TODO: cross reply
 	// TODO: sticker object storage
 
-	if update.Message == nil || update.Message.Chat == nil {
-		if update.EditedMessage != nil {
-			// TODO: handle edit
-			return
+	if update.EditedMessage != nil {
+		if reference, ok := messageReference[update.EditedMessage.MessageID]; ok {
+			content := update.EditedMessage.Text
+			if hasHeader[update.EditedMessage.MessageID] {
+				if update.EditedMessage.Chat == nil || update.EditedMessage.From == nil {
+					if config.System.Verbose {
+						log.Printf("got irrelevant update %v in edit", update.UpdateID)
+					}
+					return
+				}
+				header, _ := makeHeader(update.EditedMessage, true)
+				content = header + content
+			}
+			if _, err := session.ChannelMessageEdit(reference.ChannelID, reference.MessageID, content); err != nil {
+				msg := tgbotapi.NewMessage(update.EditedMessage.Chat.ID, "error relaying edit")
+				msg.ReplyToMessageID = update.EditedMessage.MessageID
+				log.Printf("error relaying edit of %v: %s", update.EditedMessage.MessageID, err)
+				_, _ = botAPI.Send(msg)
+				return
+			}
+			log.Printf("T%vM%v -> D%sM%s @%s (%v) [edit]: %s",
+				update.EditedMessage.Chat.ID, update.EditedMessage.MessageID,
+				reference.ChannelID, reference.MessageID,
+				update.EditedMessage.From.UserName, update.EditedMessage.From.ID,
+				update.EditedMessage.Text)
 		}
+		return
+	}
+
+	if update.Message == nil || update.Message.Chat == nil {
 		if config.System.Verbose {
 			log.Printf("got irrelevant update %v", update.UpdateID)
 		}
@@ -104,6 +146,9 @@ func respondTelegram(update tgbotapi.Update) {
 		tc bridgePlatformConf
 	)
 	if c, ok := telegramBridge[update.Message.Chat.ID]; !ok {
+		if config.System.Verbose {
+			log.Printf("got update %v from unconfigured chat %v", update.UpdateID, update.Message.Chat.ID)
+		}
 		return
 	} else {
 		dc = c.Discord
@@ -111,28 +156,93 @@ func respondTelegram(update tgbotapi.Update) {
 	}
 
 	var (
-		username = "unknown"
-		id       = -1
-		dMsgID   = "-1"
+		username   = "unknown"
+		id         = -1
+		dMessageID = "-1"
+		dGuildID   = "-1"
+		dChannelID = "-1"
 	)
 	if update.Message.From != nil {
 		username = update.Message.From.UserName
 		id = update.Message.From.ID
 	}
-
-	space := ""
-	if update.Message.From.LastName != "" {
-		space = " "
+	var reference *discordgo.MessageReference
+	if update.Message.ReplyToMessage != nil {
+		if r, ok := messageReference[update.Message.ReplyToMessage.MessageID]; ok {
+			reference = r
+			setPreviousCaller(update.Message.Chat.ID, -1)
+		}
 	}
-	name := ""
-	if !config.System.DisplaceHeader || !setPreviousCaller(update.Message.Chat.ID, update.Message.From.ID) {
-		// TODO: check the discord side for header displace
-		name = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(config.Telegram.NameFormat,
-			"$FIRST", update.Message.From.FirstName),
-			"$LAST", update.Message.From.LastName),
-			"$USER", update.Message.From.UserName),
-			"$SPACE", space)
-		name += "\n"
+
+	header, has := makeHeader(update.Message, false)
+
+	if update.Message.Photo != nil && len(*update.Message.Photo) > 0 {
+		fids := ""
+		files := make([]*discordgo.File, len(*update.Message.Photo))
+		for i, info := range *update.Message.Photo {
+			var url string
+			if u, err := botAPI.GetFileDirectURL(info.FileID); err != nil {
+				msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error getting URL")
+				msg.ReplyToMessageID = update.Message.MessageID
+				log.Printf("error getting URL of %s: %s", info.FileID, err)
+				_, _ = botAPI.Send(msg)
+				return
+			} else {
+				url = u
+			}
+
+			if resp, err := http.Get(url); err != nil {
+				msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error getting file")
+				msg.ReplyToMessageID = update.Message.MessageID
+				log.Printf("error getting file %s: %s", info.FileID, err)
+				_, _ = botAPI.Send(msg)
+				return
+			} else {
+				files[i] = &discordgo.File{
+					Name:        "sticker.webp",
+					ContentType: "image/webp",
+					Reader:      resp.Body,
+				}
+				//goland:noinspection GoDeferInLoop
+				defer func() {
+					if err = resp.Body.Close(); err != nil {
+						log.Printf("error closing request body: %s", err)
+					}
+				}()
+			}
+
+			if i != 0 {
+				fids += ", "
+			}
+			fids += info.FileID
+		}
+
+		if message, err := session.ChannelMessageSendComplex(strconv.Itoa(dc.ID), &discordgo.MessageSend{
+			Content:   header + update.Message.Caption,
+			Files:     files,
+			Reference: reference,
+		}); err != nil {
+			msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error relaying message")
+			msg.ReplyToMessageID = update.Message.MessageID
+			log.Printf("error relaying message %v: %s", update.Message.MessageID, err)
+			_, _ = botAPI.Send(msg)
+			return
+		} else {
+			dMessageID = message.ID
+			dChannelID = message.ChannelID
+			dGuildID = message.GuildID
+		}
+
+		messageReference[update.Message.MessageID] = &discordgo.MessageReference{
+			MessageID: dMessageID,
+			ChannelID: dChannelID,
+			GuildID:   dGuildID,
+		}
+		hasHeader[update.Message.MessageID] = has
+
+		log.Printf("T%vM%v -> D%vM%s @%s (%v) [photo]: %s; caption: %s",
+			tc.ID, update.Message.MessageID, dc.ID, dMessageID, username, id, fids, update.Message.Caption)
+		return
 	}
 
 	if update.Message.Sticker != nil {
@@ -147,10 +257,7 @@ func respondTelegram(update tgbotapi.Update) {
 			url = u
 		}
 
-		var (
-			file *discordgo.File
-			body io.ReadCloser
-		)
+		var file *discordgo.File
 		if resp, err := http.Get(url); err != nil {
 			msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error getting file")
 			msg.ReplyToMessageID = update.Message.MessageID
@@ -163,16 +270,22 @@ func respondTelegram(update tgbotapi.Update) {
 				ContentType: "image/webp",
 				Reader:      resp.Body,
 			}
-			body = resp.Body
+			defer func() {
+				if err = resp.Body.Close(); err != nil {
+					log.Printf("error closing request body: %s", err)
+				}
+			}()
 		}
 
-		content := name
+		content := header
 		if config.Telegram.StickerEmoji {
 			content += update.Message.Sticker.Emoji
 		}
+
 		if message, err := session.ChannelMessageSendComplex(strconv.Itoa(dc.ID), &discordgo.MessageSend{
-			Content: content,
-			File:    file,
+			Content:   content,
+			File:      file,
+			Reference: reference,
 		}); err != nil {
 			msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error relaying message")
 			msg.ReplyToMessageID = update.Message.MessageID
@@ -180,34 +293,64 @@ func respondTelegram(update tgbotapi.Update) {
 			_, _ = botAPI.Send(msg)
 			return
 		} else {
-			dMsgID = message.ID
+			dMessageID = message.ID
+			dChannelID = message.ChannelID
+			dGuildID = message.GuildID
 		}
-		if err := body.Close(); err != nil {
-			log.Printf("error closing request body: %s", err)
+
+		messageReference[update.Message.MessageID] = &discordgo.MessageReference{
+			MessageID: dMessageID,
+			ChannelID: dChannelID,
+			GuildID:   dGuildID,
 		}
-		log.Printf("T%vM%v -> D%vM%s @%s (%v): %s",
-			tc.ID, update.Message.MessageID, dc.ID, dMsgID, username, id, "Sticker: "+update.Message.Sticker.FileID)
-		return
-	}
+		hasHeader[update.Message.MessageID] = has
 
-	if update.Message.Contact != nil {
-		// TODO: handle contact
+		log.Printf("T%vM%v -> D%vM%s @%s (%v) [sticker]: %s",
+			tc.ID, update.Message.MessageID, dc.ID, dMessageID, username, id, update.Message.Sticker.FileID)
 		return
 	}
 
 	if update.Message.Text == "" {
+		if config.System.Verbose {
+			log.Printf("got update %v with empty message", update.UpdateID)
+		}
 		return
 	}
 
-	if message, err := session.ChannelMessageSend(strconv.Itoa(dc.ID), name+update.Message.Text); err != nil {
+	if message, err := session.ChannelMessageSendReply(strconv.Itoa(dc.ID), header+update.Message.Text, reference); err != nil {
 		msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error relaying message")
 		msg.ReplyToMessageID = update.Message.MessageID
 		log.Printf("error relaying message %v: %s", update.Message.MessageID, err.Error())
 		_, _ = botAPI.Send(msg)
 	} else {
-		dMsgID = message.ID
+		dMessageID = message.ID
+		dChannelID = message.ChannelID
+		dGuildID = message.GuildID
 	}
 
+	messageReference[update.Message.MessageID] = &discordgo.MessageReference{
+		MessageID: dMessageID,
+		ChannelID: dChannelID,
+		GuildID:   dGuildID,
+	}
+	hasHeader[update.Message.MessageID] = has
+
 	log.Printf("T%vM%v -> D%vM%s @%s (%v): %s",
-		tc.ID, update.Message.MessageID, dc.ID, dMsgID, username, id, update.Message.Text)
+		tc.ID, update.Message.MessageID, dc.ID, dMessageID, username, id, update.Message.Text)
+}
+
+func makeHeader(message *tgbotapi.Message, force bool) (string, bool) {
+	if !config.System.DisplaceHeader || force || !setPreviousCaller(message.Chat.ID, message.From.ID) {
+		// TODO: check the discord side for header displace
+		space := ""
+		if message.From.LastName != "" {
+			space = " "
+		}
+		return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(config.Telegram.NameFormat,
+			"$FIRST", message.From.FirstName),
+			"$LAST", message.From.LastName),
+			"$USER", message.From.UserName),
+			"$SPACE", space) + "\n", true
+	}
+	return "", false
 }