<commit_before>#!/usr/bin/env ruby
# vim: et ts=2 sw=2

require "cgi"
require "uri"
require "net/https"
require "json/pure"

module ICloud
  class Session
    include Proxy

    def initialize apple_id, pass, client_id=nil
      @apple_id = apple_id
      @pass = <PASSWORD>

      @user = nil
      @services = nil
      @pool = Pool.new

      @http = {}
      @cookies = []

      @request_id = 1
      @client_id = client_id || default_client_id
    end

    #
    # Public: Logs in to icloud.com or raises some subclass of Net::HTTPError.
    #
    def login!
      uri = URI.parse("https://setup.icloud.com/setup/ws/1/login")
      payload = { "apple_id"=>@apple_id, "password"=><PASSWORD>, "extended_login"=>false }

      response = http(uri.host, uri.port).post(uri.path, payload.to_json, default_headers)
      @cookies = response.get_fields("set-cookie")
      body = JSON.parse(response.body)

      @user = Records::DsInfo.from_icloud(body["dsInfo"])
      @services = parse_services(body["webservices"])

      update(get_startup)

      true
    end

    def user
      ensure_logged_in
      @user
    end

    def services
      ensure_logged_in
      @services
    end

    def collections
      ensure_logged_in
      @pool.find_by_type(Records::Collection)
    end

    def reminders
      ensure_logged_in
      update(get_completed)
      @pool.find_by_type(Records::Reminder)
    end

    def post_reminder(reminder)
      ensure_logged_in

      # TODO: Should ClientState always be included in posts?
      post(service_url(:reminders, "/rd/reminders/tasks"), { }, {
        "Reminders" => reminder.to_icloud,
        "ClientState" => client_state
      })
    end

    def put_reminder(reminder)
      ensure_logged_in

      # TODO: Should ClientState always be included in posts?
      post(service_url(:reminders, "/rd/reminders/tasks"), { "methodOverride" => "PUT" }, {
        "Reminders" => reminder.to_icloud,
        "ClientState" => client_state
      })
    end

    def put_collection_reminder(reminder)
      ensure_logged_in

      post(service_url(:reminders, "/rd/reminders/#{reminder.p_guid}"), { "methodOverride" => "PUT" }, {
        "Reminders" => reminder.to_icloud,
        "ClientState" => client_state
      })
    end

    def delete_reminder(reminder)
      ensure_logged_in

      post(service_url(:reminders, "/rd/reminders/tasks"), { "methodOverride" => "DELETE", "id" => deletion_id }, {
        "Reminders" => [reminder.to_icloud],
        "ClientState" => client_state
      })
    end

    def apply_changeset(cs)
      if cs.include?("updates")<commit_msg>Support creating/deleting reminders in collections<commit_after>#!/usr/bin/env ruby
# vim: et ts=2 sw=2

require "cgi"
require "uri"
require "net/https"
require "json/pure"

module ICloud
  class Session
    include Proxy

    def initialize apple_id, pass, client_id=nil
      @apple_id = apple_id
      @pass = <PASSWORD>

      @user = nil
      @services = nil
      @pool = Pool.new

      @http = {}
      @cookies = []

      @request_id = 1
      @client_id = client_id || default_client_id
    end

    #
    # Public: Logs in to icloud.com or raises some subclass of Net::HTTPError.
    #
    def login!
      uri = URI.parse("https://setup.icloud.com/setup/ws/1/login")
      payload = { "apple_id"=>@apple_id, "password"=><PASSWORD>, "extended_login"=>false }

      response = http(uri.host, uri.port).post(uri.path, payload.to_json, default_headers)
      @cookies = response.get_fields("set-cookie")
      body = JSON.parse(response.body)

      @user = Records::DsInfo.from_icloud(body["dsInfo"])
      @services = parse_services(body["webservices"])

      update(get_startup)

      true
    end

    def user
      ensure_logged_in
      @user
    end

    def services
      ensure_logged_in
      @services
    end

    def collections
      ensure_logged_in
      @pool.find_by_type(Records::Collection)
    end

    def reminders
      ensure_logged_in
      update(get_completed)
      @pool.find_by_type(Records::Reminder)
    end

    def post_reminder(reminder)
      ensure_logged_in

      path = "/rd/reminders/#{reminder.p_guid || 'tasks'}"
      # TODO: Should ClientState always be included in posts?
      post(service_url(:reminders, path), { }, {
        "Reminders" => reminder.to_icloud,
        "ClientState" => client_state
      })
    end

    def put_reminder(reminder)
      ensure_logged_in

      path = "/rd/reminders/#{reminder.p_guid || 'tasks'}"
      # TODO: Should ClientState always be included in posts?
      post(service_url(:reminders, path), { "methodOverride" => "PUT" }, {
        "Reminders" => reminder.to_icloud,
        "ClientState" => client_state
      })
    end

    def put_collection_reminder(reminder)
      ensure_logged_in

      post(service_url(:reminders, "/rd/reminders/#{reminder.p_guid}"), { "methodOverride" => "PUT" }, {
        "Reminders" => reminder.to_icloud,
        "ClientState" => client_state
      })
    end

    def delete_reminder(reminder)
      ensure_logged_in

      path = "/rd/reminders/#{reminder.p_guid || 'tasks'}"
      post(service_url(:reminders, path), { "methodOverride" => "DELETE", "id" => deletion_id }, {
        "Reminders" => [reminder.to_icloud],
        "ClientState" => client_state
      })
    end

    def apply_changeset(cs)
      if cs.include?("updates")
{'fraction_non_alphanumeric': 0.12312256628963471, 'fraction_numerical': 0.0014834044131281292, 'mean_word_length': 2.689466484268126, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 37, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4081043', 'n_tokens_mistral': 1832, 'n_tokens_neox': 1806, 'n_words': 346}